webアプリのサーバーサイドをAWS×Serverless Frameworkで構築しています。
今回、webアプリの開発を進めていくうえで、リソースが多くなり、cloudFormationのリソース上限を超えてしまい、デプロイできなくなるエラーに遭遇しましたので、エラーの内容と対策を紹介していきます。
※エラーに遭遇してから、上限があることを知り、ググったりして原因と対策を取りました。
serverless FrameworkやAWS CloudFormationに精通しているエンジニアではないことご理解お願いします。
今回のエラー
AWSのリソースをServeless Frameworkを用いて、sls deploy
した際に以下のようなエラーが出ました。
The CloudFormation template is invalid: Template form error: Number of resources, 507, is greater then maximum allowed, 500
エラーの内容はCloudFormationテンプレートのエラーで、リソースが507個あり、上限の500個を超えているというものでした。
AWSのソースについてはこちらをご確認ください。
エラー要因を探る
私自身、AWSもServeless Frameworkもまだまだ勉強中のみでありますので、詳細解説を行うことはできません。
ただ、エラーの内容は理解できてますし、ServelessFrameworkにより作成されるClouFormationのコンソールから今回のエラー要因である上限500を探っていきます。
AWS CloudFormationを検証
AWS CloudFormationのページにアクセスすると現在作成されているスタックが表示されます。
すでにいくつかありますが、このうち説明にServeless Applicationと記載があるものが、ServerlessFrameworkから作成されたものです。
Serveless Frameworkで作成されたスタックをクリックして、上部タブからリソースに切り替えるとその中のスタックが表示されます。
すでに対策を取ったものなので、500を超えていませんが、それでもリソースが473あることが分かります。
これが、さらにAPIパスやLambdaなどを増やし、500を超えるとエラーが発生します。
1APIパス × 1Lambdaで圧迫
リソースという単位が難しいですが、Lambda ファンクション1つにつき4~5のリソースが作られることになります。
APIパスのGETメソッドやオプション、Lambdaファンクション、Lambdaのロググループやバージョン、EventBridgeなどごとにリソースが作られます。
今回私は、主にAPI Gatewayのメッソドに対応するLambdaを作成していましたが、細かく分けて作成したこともありますが、webアプリを機能追加・改修していくたびにどんどんと肥大化していきました。
1つのlambdaで複数のAPIパスをハンドリングしたり、lambdaの書き方を工夫することでリソース数を少なくすることもできますが、今回のwebアプリの開発ではAPI Gatewayの1パスで1Lambdaという構成でした。
これにより、100を超えるAPIパス、Lambdaが作成され、リソース上限500を超える結果となっていることが主要な原因です。
Lambdaの構成により、リソースが増えていることが分かったので、この点を対策取っていきます。
現状は、数を減らして500以下にしましたが、そのうち500を超えてしまうことがあるので、根本対策を解ていきます。
エラー対策
ここからは、リソース上限500を超えたあとに取りうる対策になります。
リソース上限を緩和するような仕組みではなく、リソースを減らしたり、スタックを分割したりするという対策を取る必要があります。
対策は以下が考えられます。
- Serveless側で不要なresource(Lambda)を削除する
- Serveless Pluginでスタックをネスト化する
- 一つのLambdaで複数APIをハンドリングする
今回は上二つの対策を取りましたので、事例紹介していきます。
1. Serveless側で不要なresource(Lambda)を削除する
まずは、不要なリソースを作らないことが重要です。
作ったけど、使ってないAPIパス、Lambdaがないか確認することから始めました。
1Lambdaにつき4~5のリソースが作られますので、5~10個消すだけでもリソース上限を解消することが可能です。
私の場合、10個のテスト環境のみで必要としていたLambdaがありましたので、これらを削除しました。
この状態が、先ほどスクショで表示したリソースが470程度まで減らせた状態です。
2. Serveless Pluginでスタックをネスト化する
ひとまず、不要Lambdaを削除することで、リソースが500個未満になり、無事デプロイすることはできました。
ただ、まだまだ開発途中のwebアプリですので、いずれ再度上限にかかる可能性はまだありました。
そこで、二つ目の対策です。
AWSの公式ドキュメント(こちら)では、スタックをネスト化(入れ子構造)にする方法が紹介されています。
これで全体のスタックを分割して、一つあたりが500以下になるように設定することが可能です。
このネスト化ですが、CloudFormationのテンプレートに記載することでネスト化の設定することは可能とのことですが、CloudFormationのテンプレートの理解もあまりできてないですし、他の方法で実現しました。
Serveless Frameworkのプラグインに「serverless-plugin-split-stacks」という便利なものがありますので、今回はこちらを利用しました。
使い方は非常に簡単で、まずはプラグインのインストール
npm install --save serverless-plugin-split-stacks
そして、serveless.ymlのpluginsにライブラリを記載するだけです。
plugins:
- serverless-plugin-split-stacks
これだけで、デプロイした際にリソースが500を超えていた場合は、自動で分割してくれます。
プラグイン自体のカスタマイズもできるとのことですが、基本的にはプラグイン呼び込むだけで使えるので非常に簡単です。
3. 一つのLambdaで複数APIをハンドリングする
私は実施してませんが、1APIパス×1Lambdaという構成を見直して、1Lambdaで複数のAPIをハンドリグルことでリソース数を減らすことも有効な対策です。
私の場合は、すでにいくつものAPIパス、Lambda作成していましたし、チーム開発でしたので、今から鋼製を見直すということは対応が困難でした。
調べてみると、Serveless-Expressなどのパッケージを用いることで、一つのLambdaで複数のAPI パスをハンドリングできるようになるようです。
ただ、この方法は実際には利用していないので、参考にした記事(こちら)を添付しておきます。
おわりに
webアプリ開発をしていくと、開発していくにつれて出現するエラーが数多くあります。
事前にAWSやServeless Frameworkの特徴を理解して、開発を進めていければベストなのかもしれませんが、私のように勉強しながら開発を進めていくと、問題に直面してからの後手解決ということも多々あります。
少しずつ、スキルを高めて、より良いwebアプリ開発できるように頑張っていきます。
コメント