emahiro/b.log

Drastically Repeat Yourself !!!!

Serverless Framework@v3 で monorepo 構成にする

Overview

Serverless Framework@v3 で monorepo 構成にするワークアラウンドについて記載します。
なお、あくまでワークアラウンドなのでいつか使えなくなるかもしれません。

Motivation

Serverless Framework を運用する上でのモノレポ構成、最新の Serverless Framework@v3 では monorepo 構成をとること(= 一つのリポジトリに対して複数のディレクトリを切ってそれぞれ serverless.yml を持つ、という構成)が非推奨になってしまいました。

ema-hiro.hatenablog.com

上記のエントリにも記載してますが、あるリポジトリに複数のサービスとして serverless.yml を持っている状態だと serverless/github-action を使って CI/CD を構築すると、Deprecation code: NESTED_CUSTOM_CONFIGURATION_PATH のエラーが発生し、デプロイができなくなります。

とはいえ、サービスとして機能させるために FaaS をスタックとして採用するケースを除き、基本的には bot の管理やちょっとしたイベントをフックして Lambda で処理を回したいときなどある FaaS ごとにリポジトリを作成したら、リポジトリ爆発を起こして、収集がつかなくなり、管理が煩雑になります。

そのため、FaaS 運用を考えるとちょっとした処理をする FaaS に関しては一つの箱の中にしまっておきたくなります。
現職ではそうした背景から、ちょっとした FaaS の運用については1つのリポジトリにまとまっていました。しかし、これが Serverless Framework の最新版になったことでこの構成をとることが非推奨構成として、基本的にはこの状態ではデプロイができなくなってしまいました。

これを受けて、FaaS を分けるのか、それともクソデカ serverless.yml を爆誕させるかで悩んでましたが、どちらも取りたくないなーと考えてたところ、調べてみると似たようなことに悩んでる人がいたらしく issue が上がっていたので改めて v3 でも monorepo 構成を取れるか調査してみようと思って調査してみたところワークアラウンドを見つけた話になります。

以下は同じようなことに悩んでる人が立てた issue。

github.com

ワークアラウンドについて

v3 でも monorepo 構成を取るためには以下の設定を CI (今回は actions をベースにしてます)に追加していきます。

actions も v3 にあげる

- uses: serverless/github-action@v2
+ uses: serverless/github-action@v3

entrypoint option を設定する

serverless/actions を使う場合は以下の issue のコメントを参考にして -c のインラインコマンドオプションと entrypoint オプションを使用します。

with:
- args: deploy --config ./${{ env.WORKING_DIR }}/serverless.yml --verbose --stage=stage
+ args: -c "cd ./$yourServiceDir && sls deploy"
+ entrypoint: /bin/sh

ref: https://github.com/serverless/github-action/issues/53#issuecomment-1059839383

SSM を使ってる場合 ~true suffix を削除する

以下のブログエントリにあるように SSM を使って Cred を読み込む場合の ~true という suffix が必要なくなります。

- ${ssm:${self:custom.environment.${self:provider.stage}.KeyName}~true}
+ ${ssm:${self:custom.environment.${self:provider.stage}.KeyName}}

With the latest version, not that this is a requirement anymore, but you have to remove it, or otherwise it will be treated as a parameter name which can lead to an error.

www.serverlessguru.com

environment で JSON を読み込む場合には raw 指定する

これは最後の最後でつまづきましたが、GCP の credential 等 json 形式で保存されてる場合に environment で指定すると string を期待してるところに JSON object が指定されてる、というエラーが出てデプロイができませんでした。

UPDATE_FAILED: $FuncName (AWS::Lambda::Function)
Properties validation failed for resource $FuncName with message:
#/Environment/Variables/$GCPCredName: expected type: String, found: JSONObject

これを解決するには raw option を指定すると JSON object の状態でも environment への指定が可能になります。

Note: you can turn off parsing by passing raw instruction into variable as: ${ssm(raw):/path/to/secureparam}, if you need to also pass custom region, put it first as: ${ssm(eu-west-1, raw):/path/to/secureparam})

ref: https://www.serverless.com/framework/docs/providers/aws/guide/variables/#resolution-of-non-plain-string-types

なので以下のように指定します。

- ${ssm:${self:custom.environment.${self:provider.stage}.KeyName}}
+ ${ssm(raw):${self:custom.environment.${self:provider.stage}.KeyName}}

まとめ

Lambda かつ SSM を使った Credentials のロード、そして actions を使ったデプロイ、など条件がありましたが、この条件において複数サービスの monorepo 構成であっても Serverless Framework@v3 でデプロイまで持っていくことができました。普通に困っていたので対処療法とはいえ、対応できてよかったです。