Overview
Serverless Framework@v3 で monorepo 構成にするワークアラウンドについて記載します。
なお、あくまでワークアラウンドなのでいつか使えなくなるかもしれません。
Motivation
Serverless Framework を運用する上でのモノレポ構成、最新の Serverless Framework@v3 では monorepo 構成をとること(= 一つのリポジトリに対して複数のディレクトリを切ってそれぞれ serverless.yml を持つ、という構成)が非推奨になってしまいました。
上記のエントリにも記載してますが、あるリポジトリに複数のサービスとして 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。
ワークアラウンドについて
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.
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})
なので以下のように指定します。
- ${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 でデプロイまで持っていくことができました。普通に困っていたので対処療法とはいえ、対応できてよかったです。