概要
私は掲題の両CDKともいくつかのプログラミング言語でそれなりに使い込んでいますが、一つのStackでどの程度の数のサービスを構築するか、他のスタックと分けるポイントはどこかを解説します。
最初に例を示すパターン
たとえば一般的なSPA, API, DBの構成を考えてみましょうか。
Route53でドメイン定義、TLSの証明書もとる。
CloudFrontでS3オリジンを使いCDNやりつつ、VPCや各種subnet ルーティング、NATgw を作成してECSでAPIを構築してS3とかSQSやLambdaも作ります。RDRも作る。キャッシュとしてRedisもほしいですね。
メールもやりたい。
これをStackに落とすときは下記のような感じになります、前ダサいですけどあえてわかりやすくしている例なのでお許しを。
- DomainStack
- FrontStack
- VPCStack
- BackendStack
- DBStack
- MailStack
- IAMStack
- MoniterStack
- Utility (Stackではない共通処理)
依存関係を図にするとこんなかんじ。
依存されているものについて解説します。
- DomainStackの中でRoute53のHosted Zone, RecordSetの作成、証明書の取得などを行っているため、インターネット面に接するサービスはすべてこれに依存します。
- VPCStackはVPCのページにある基本的なものをだいたい面倒みるのでVPC上にあるものはすべてこのスタックに依存します
- ただし、VPNやフローログ、各種エンドポイントなど、機能を実現するために必要そうなものはここでは準備しません。ネットワークまわりなど地面と基礎だけ準備している感じです。
さて、FrontStackとBackendStackの中でS3を作っているのですが、作成する実働処理は最初の方はUtilの方に切り出しておきます。
同じことを何度も書くとduplicated codeとか指摘されてVSCodeやIntelliJさんに怒られるのもあるんですが、共通化できるものは Utilの中にぽいぽいと放り込んでおいて ゆるく 共通化しておくかんじです。(このゆるさが後々の保守にとって大切なことになっていくケースがありました)
説明
さて、上記のような分け方をした理由について下記のような方針があります。
- Stackの中で構築するものを集合させるときはAWSサービス単位ではなく、機能単位で考える
- 細かくStackを切りすぎてもあまりいいことはなかったです
- 逆に大きすぎると一つの変更が変なところに作用するのと、Stackの実行時間がかかるようになるためあまりよくない。
- 後から手を加える際のいい塩梅を考えたときデプロイの影響範囲は理論機能の中に収まる傾向がある
- Stack間を疎結合にする
- 後続のStackから見てすでに存在するインスタンス等は名前やARNで参照して使うことになりますが、これを極力前のStackに依存しないように突き詰めて実装します
- 連続性のあるタスクはREADMEとかでわかるようにする
- 依存関係とか書いておくと後から手をいれるときにわかりやすいし、そこに構築順序を降っておくとよいんじゃないでしょうか
- なるべくconfigは配列で持って複数作成できるようにする
- 本番、ステージ、開発環境とかスペックだけ変えて同じもの作りたいよね?
- 複数の環境を設定で切り替えられるようにconfigを意識する
- たとえばCloudFrontを1個だけ作れるようにしたconfigよりも、複数あることを前提としたほうがリソースを増やすときに融通が効くため、1個でも基本的に配列にしてconfigを作っておきます。
- このときに絶対やってはいけないのが for などで配列を回しているときに インフラ作成の new時の2番目の引数・・・ nameを雑に名付けてはいけない 間違ってもループの連番とかで名付けすると後々地獄が待っているのでお気をつけあれ・・ちゃんと固有の名前をsuffixとして付与してあげましょう
そろそろ二桁くらい更地からCDK(TF)でインフラ作ってますが、いまのところこんなかんじでいい塩梅です。