はじめに
みなさん、CroudFormation(以下「Cfnと記載」)使ってますか?
アプリ環境をクラウドで構築する際、構成やリソースをテンプレートファイルで定義することも増えました。(いわゆる「IaC(Infrastructure as Code)」)
しかし初めのうちはともかく、規模が大きくなってくると、下記のような問題が発生します。
- リソース数が膨大な数になる。
- リソース数の増加により、管理が大変になる。
そこで、今回はCfnの構成・リソースを管理する際の考え方(=管理の仕方)について、自分なりの考えを書きました。
前提
個人的には、Cfnでの構成・リソース管理としては、こんな感じに分かれるのかな、と思ってます。
- 同一プロジェクトで管理
- 1ファイルにすべて記載
- スタックのネスト(親子関係をつける)
- 個別プロジェクトで管理
- リソース種別で管理
- サービス単位で管理
なので上記について、特徴やメリット・デメリットを説明したいと思います。
ただ、結構長くなりそうなので、パートを2パートに分けました。
今回はパート1として「同一プロジェクトで管理」について書きたいと思います。
なおAWS公式ドキュメントに「AWS CloudFormation ベストプラクティス」というのがあるので、こちらを一読するのをお勧めします。
docs.aws.amazon.com
同一プロジェクトで管理
名前の通り、1つのプロジェクトでCfnの構成・リソースを管理するパターンです。
「スタックのネスト」のように、スタック(≒テンプレートファイル)を分けるケースもありますが、1回のデプロイコマンドで全リソースをデプロイできます。
1ファイルにすべて記載
特に難しいことは意識せず、1テンプレートファイルにすべての構成・リソースを記載する方法です。
管理方法としては、いたってシンプルです。
メリット:管理がしやすい(リソース数が少ない場合)
他のパターンと違い、テンプレートファイルは1つだけなので(環境ごとの差分ファイルは除く)、管理がしやすい(=手っ取り早い)と思います。
特に構成・リソースが少ないうちは、なおさら管理コストは少ないと思います。
なので、とりあえずアプリを作れれば良い(規模が大きくなる・運用管理などは想定しない)場合は、この方法を採用するのが手っ取り早いと思います。
デメリット1:管理が大変(リソース数が多い場合)
ただ、先程「特に構成・リソースが少ないうちは、なおさら管理コストは少ない」と書きましたが、裏を返せば「構成・リソースが多くなると、管理コストが高くなる」ということです。
特に、1ファイルに大量の定義がなされている場合、どこに何があるかを探すだけでも大変になるかと思います。(依存関係があるとなおさら)
また、「デプロイ時に全リソースをデプロイしなければならない(≒デプロイに時間がかかる)」デメリットもあります。
例えば「S3バケットを1つ追加したいだけ」というケースでも、それ以外の全リソースをデプロイしなければならず、時間がかかります。(無関係な他の全リソースもデプロイしなければならない)
デメリット2:リソース数の上限に引っかかりやすい
Cfnでは「1スタックに格納できるリソースは500個まで」という制限があります。
なので1ファイルにあまりにたくさん構成・リソースを定義しすぎると、この上限に引っかかってデプロイができない...という事態が発生しやすくなります。
※ちなみに、500個という上限も昨年10月に引き上げられたもので、それまでは200個が上限でした。
なので、ちょっと規模が大きいアプリの構成を1ファイルに定義していると、すぐ上限に引っかかる...というケースが結構あったと思います。(僕もありました)
スタックのネスト(親子関係をつける)
上記の「1ファイルにすべて記載」で述べたような定義ファイルの肥大化、およびそれに伴う問題を解消する方法として「Cfnスタックを分ける」というのがあります。
この「スタックのネスト(親子関係をつける) 」は「Cfnスタックを分ける」方法のうち、同一プロジェクトで全スタックを管理する方法になります。
メリット1:リソースの上限を気にしなくてよい
先程の「リソースの上限」は、個々のスタック単位の制限なので、個々のスタックで管理しているリソースが500を超えなければ、Cfnのリソースの上限には引っかかりません。(たとえプロジェクト全体で管理しているリソース数が500を超えたとしても)
なので、ネストしている個々のスタックの管理さえ気を付ければ、リソース数を気にする必要はなくなります。
メリット2:リソースの管理について、柔軟性がある
スタックのネストでは、スタックをいくつかに分けます。 そしてその分け方は自由です。
なので(パート2の「個別プロジェクトで管理」にも言えますが)、リソースの管理単位を柔軟に決めることができます。
ですので、プロジェクトで管理しやすい単位でスタックを分割することにより、リソースの管理がしやすくなります。
例えば「個別プロジェクトで管理」に書いたような「リソース単位」「サービス単位」でのスタック分割などを行うことで、リソース管理がしやすくなります。
デメリット1:慣れるまで操作がややこしい
スタックのネストは、「1ファイルにすべて記載」みたいに1デプロイで終了するわけではないですし、
- 事前に下位テンプレートのアップロードが必要(S3に格納する必要がある)
- 親子スタック間での値の受け渡しにクセがある
- クロススタック参照みたいに、定義一つで終わり...というわけではない
というのがあり、慣れるまでちょっとややこしいかもしれません。(実際、スタックのネストはちょっと癖があるなあ...というのが個人的な感想です)
とはいえ、ここは慣れの部分もあるかもしれませんし、慣れればそこまで問題にはならないかもです。
デメリット2:全リソースをデプロイしなければならない&そのせいでデプロイに時間がかかる
これは先程の「1ファイルにすべて記載」と同じですが、スタックを分割しても、1デプロイで全リソースをデプロイする事には変わりません。
そのため「全リソースをデプロイしなければならない&そのせいでデプロイに時間がかかる」デメリットは変わりません。(事前に下位テンプレートのアップロードをしても、デプロイまでは実施しません)
Serverless Frameworkでのスタックのネスト
ちなみにServerless Frameworkを使用する場合、「serverless-plugin-split-stacks」というプラグインを使用するだけで、スタックのネストを自動で行ってくれます。
基本は「serverless-plugin-split-stacks」プラグインに振り分け方式を設定するだけで自動で振り分けを行ってくれますが、「stacks-map.js」ファイルを作成することで、振り分け方式をカスタマイズすることもできます。
僕のブログでも、過去にこの「serverless-plugin-split-stacks」について触れていますので、よろしければ参照ください。
ただし、公式ページにも下記の記載がされている通り、いわゆる「銀の弾丸」的なプラグインではありませんので、まずはアプリのスタックの管理(=リソース数削減)の見直しを検討してください。
This plugin is not a substitute for fine-grained services - try to limit the size of your service.
(訳:このプラグインは(スタックのネストについて)万能なサービスの代わりではありません。あなたのサービス(=アプリ)のスタックサイズを制限することを試してください)
まとめ
以上、同一プロジェクトで管理する方法について書きました。
「個別プロジェクトで管理」については、少し長くなるかもしれないので、パート2として近いうちにアップしたいと思います。
告知
3/20(土)に開催される「JAWS DAYS 2021」にて、「AWS Lambdaのいろいろなテスト方法」という内容で登壇させていただくことになりました。
jawsdays2021.jaws-ug.jp
内容としては、1/6(水)の「Serverless Meetup Japan Virtual #14」での登壇内容である「Severless Frameworkで行うLambdaテスト」をベースに、時間の関係でお話しできなかった内容を追加する予定です。
それでは、パート1はこの辺で。