CDKの便利機能 (L2,L3)コンストラクト

k.goto氏:次に、CDKの便利機能を1個ずつ紹介していきます。まずはL2、L3コンストラクト。まずコンストラクトが何かというと、CDKの独自機能や独自概念という感じです。ソースコード上でいうと、CDKの独自クラスによるAWSリソース定義の抽象化をしてくれるものです。

L1、L2、L3というようにレイヤーが分かれていて、数字が大きくなる、上にいくほど抽象度の高いものとなっています。L3だと複数のリソースを含む構成パターン。例えば「ALBとFargateと、なんとかとなんとか」みたいなものを一気にバッと作ってくれるみたいな、ちょっと抽象度の高いものがL3。

真ん中のL2コンストラクト。これはCDKをやる上で一番使うんじゃないかなと思うんですが、便利なデフォルト値とか、便利メソッドとかを単一のAWSリソースに持たせてくれているものになります。

CloudFormationを使ったことがある方もいると思うんですが、一番下のL1コンストラクトというのは、CloudFormationのプロパティ設定と同じ感じで、CloudFormationで指定が必須なものは全部明示的に指定する必要がある。なので抽象度が一番低いものとなっています。

ここでいうL2、L3コンストラクトの良いところとしては、ベストプラクティスに基づいたパラメーターをあらかじめ指定してくれていること。必要最低限のパラメーターのみの指定でリソース定義が可能だったり、いい感じにIAM権限を付与してくれるgrantメソッドとかがあるので、頭を使う時間や手間が削減されるというメリットがあります。

AWS Black Beltとかにももっと細かい、良い説明があるので、良かったらご覧ください。

どんなものがあるかという例を挙げていきます。(スライドを示して)例えばVPCの設定。これは例えばVPCとサブネット、ルートテーブルとNATゲートウェイ、インターネットゲートみたいな感じで、CloudFormationで作ると100行ぐらいいったりするんですが、CDKだとこんな感じにサラッと定義できます。

いい感じにIAM権限を付与してくれるgrantメソッド。これもまさにコード中にL2コンストラクトを使っているんですが、上にnew Bucket、S3バケットを作る。2個目にNodejsFunctionというものを呼んでいるんですが、これはLambdaですね。Node.jsで書かれたLambda。

一番下の枠で囲ったところがBucket.grantReadで、Lambdaを入れる。S3バケットに対するいい感じの読み取り権限をLambdaに与える。例えばListBucketとかGetObjectとか、そういったいい感じのものをLambdaに付与してくれるということを1行で行うことができます。

次の例が、CDKレイヤーでLambdaのTypeScriptのビルド、トランスパイルをしてくれるNodejsFunction。ふだんTypeScriptはJavaScriptに変換、トランスパイルというんですが、変換をして、そのJavaScriptファイルでデプロイしたり、動かしたりします。しかし、この場合はTypeScriptのファイルを指定するだけで、内部でいい感じにビルド、デプロイしてくれるというような、使い勝手の良いコンストラクトとなっています。

次がCDKレイヤーでDockerビルドとECRプッシュも行ってくれるものです。DockerのビルドとかECRプッシュはIaCの管理外で、例えばジョブでLinuxコマンドを直打ちとか、Shellを叩いたりすることが多いと思います。こういったDockerビルドやECRプッシュも全部含めてCDKレイヤーで行うことができる便利なコンストラクトが、DockerImageAssetとECRDeployment。

(スライドを示して)上のソースコードでいうと、DockerImageAssetというのは、ディレクトリのDockerファイルを読み込んでいる。それをビルドして、次のECRデプロイメントで特定のECRにタグ付きでプッシュするということがCDK上でできます。

CDKの便利機能 自作コンストラクト

ここまでがコンストラクトのL1、L2、L3のAWSが提供してくれているコンストラクトの話だったんですが、コンストラクトというのはAWS提供のものだけでなくて、自作定義、自作のクラスを作ることが可能です。

スタックというのはCloudFormationとかCDKの1個のデプロイの粒度みたいな、グルーピングみたいな単位ですが、リソース以上スタック未満の自由な粒度で、AWSリソースとか、L1、L2、L3コンストラクトを自分でモジュール化するということで、コンストラクトごとにリソースをまとめて、いい感じに可読性・再利用性がアップします。

(スライドを示して)ここで挙げているソースコードは、スタッククラスの中でSSMConstructとAppRunnerConstructという自分の作ったコンストラクトを2つ呼ぶというもので、スタックはすごく可読性が良い。読みやすいんですよね。

それらがどんなものなのかというと、別ファイルの別クラスで定義します。

左側がSSMConstruct。これはextends Constructと定義します。SSMに関するもの、SSMパラメーターとか、そのIAMロールとかをクラスに突っ込む。一方で、AppRunnerに関するものは右側のAppRunnerクラスに突っ込むため、関係があるもの同士でまとめられるので、いい感じに使うことができます。これが自作コンストラクトでした。

CDKの便利機能 組み込みバリデーション

次が組み込みバリデーション。CDKは内部でCloudFormationが走っていてCloudFormationでデプロイされます。CloudFormationではデプロイ中にエラーになるようなパラーメーター指定があって、「このパラメーターとこのパラメーターを組み合わせるともう絶対にエラーになっちゃうよ」というものが、デプロイして初めてエラーになるようなことがあるんです。

ですが、CDKではそれをデプロイ前にエラーにしてくれるというような実装があったりします。つまり、CloudFormationデプロイの前段階なので、CloudFormationデプロイが走りません。ということは、デプロイフェーズまで行ってからエラーになるようなケースも減ります。これによって開発サイクルが短縮される。

CloudFormationの便利な機能の1つとして、デプロイに失敗したら1個前の状態のリソースにロールバックするという機能があったりするんですが、これがたまに失敗するんですね。そういったロールバック失敗のリスクも減ったりします。

また、もともとCDKの内部に組み込まれているバリデーション以外に、自作のバリデーションもスタックとかコンストラクトに組み込むことができます。

このような柔軟なバリデーションを組み合わせることで、より早い段階でのエラー発火により、開発サイクルをより短く・低リスクにすることができるという特徴があります。

CDKの便利機能 hotswapデプロイ

次はhotswapデプロイ。これが何かというと、先ほどお話ししたとおり、CDKデプロイというのは、CloudFormationによって内部でデプロイがされます。「Terraform」とかをやっている方は知っているかもしれませんが、CloudFormationのデプロイはあまり速くないんですね。

リソースがちょっと限定されるんですが、LambdaとかECSとかStepFunctionsとかのアプリケーションリソースをhotswapデプロイでデプロイをすると、5倍、10倍の速い時間で可能です。Lambdaとかだと5秒とか10秒かからないぐらいでデプロイできたりするという機能がhotswapデプロイです。

なんでこんなに速いのかというと、CloudFormationを通さずに、アプリケーションのコードだけを反映してくれているから。だから非常に速くデプロイが可能になるという機能です。ただ、CloudFormationを通していないということは、IaCの管理外になってしまう。

いわゆるドリフト差分というか、手動で変更した時と同じような状況が生まれて、予想しない挙動も起きてしまうかもしれないということで、「本番環境では使用しないこと」という注意書きもあります。

ですが、開発環境で使う分には非常に強力なので、素早いデプロイで開発者体験がアップできるという機能がhotswapデプロイでした。

CDKの便利機能 watchモード

次がwatchモード。ふだんアプリケーション開発をされている方とかは馴染みがあるかもしれませんが、実装の最中、コードを打っている最中にコード・アセットに変更がないかを監視して、変更が検出されたら自動で内部でデプロイしてくれるみたいなモードになります。デフォルトでhotswapデプロイが走るため、組み合わせるとすごく早いデプロイになります。実装を追った自動デプロイで、開発者の体験アップになります。

CDKの便利機能 Aspects

次がAspectsという機能になります。これはどんなものかというと、特定のスコープ内のすべての構成に操作を適用する方法。この「特定のスコープ」は何かというと、CDKスタック全体であったり、特定のコンストラクト内の全リソースという、自由に選べるようなスコープとなっています。

このAspectsの具体的な使用例の1個目としては、スタック内の全リソースに同じタグを付与する。CDKを使ったことがある人は知っているかもしれませんが、Tags.of().addみたいな、「すべてのリソースに同じタグ付与ができるよ」という便利なメソッドが用意されています。ただ、実はこのメソッドの内部でAspectsが使用されているので、ここで挙げました。

2個目が、コンストラクト内の全リソースに対してDeletionPolicy:RETAIN(を付与する)。これは削除保護の設定ですね。これを付与したり、あとは特定の種類のリソースにコンプライアンス違反する設定がないかもチェックする。「これはよく使われたりする方法かな?」ということで、一貫した複数リソースへの設定の一括適用・検査が可能なものがAspectsという機能になります。

(スライドを示して)「こんな感じで定義するよ」というものを載せています。「スタック内のすべてのS3バケットのバージョニングがオンになっているかを検査する」というのが、この具体例になります。こんな感じでクラスを定義して、ルールを書いてエラーにするみたいな、シンプルなソースコードで全リソースをチェックできます。

CDKの便利機能 カスタムリソース簡単作成

この章の最後になって、おまけでカスタムリソース簡単作成というものだけ、詰め込んでおきました。ここでいうカスタムリソースは何かというと、CloudFormationカスタムリソースというものが、CloudFormationの機能として存在します。これが何かというと、CloudFormationに対応していないリソース操作を自分で作って定義して、CloudFormationで実行できるという機能になります。

これは専用のLambdaとかSNSを構築して、SDKなどを使ってその操作を実装するという仕組みです。これが、CDKだとLambdaを自前で作成せず、良い感じにカスタムリソースを作れます。ただしこれはAWS APIをただ呼ぶだけの限定の機能で、複雑な処理が必要なものは変わらず自前でLambdaを作成する必要があります。

カスタムリソースが必要な時はそんなにないと思いますが、ただ単にAWS APIを呼ぶだけの時はCDKで作れるという機能です。

(スライドを示して)このようにいい感じにサクッと定義ができます。これでいうと、Route53のなんとかというアクションを呼ぶだけのものが作れます。

ちょっと早口というか駆け足になってしまいましたが、3番はモリモリな感じで、2つの観点にしたがって紹介しました。

(次回に続く)