Amazon Web Services ブログ

[DevAx::connect番外編] CDK実践勉強会の資料およびQ&A公開

開発者の皆様こんにちは!プロトタイピングエンジニアの友岡です。

先日 (2021/12/14) DevAx::connect 番外編第1回として、CDK 実践勉強会というイベントを開催しました。
スライドやライブコーディングも交えて AWS Cloud Development Kit (CDK) に関する知識をお伝えし、多くの方に魅力をご理解いただけたのではないかと思います。イベントの録画および資料はこちらに公開されています

また、当日は非常に多くの質問をいただき (ありがとうございます!)、その場で回答差し上げられなかったものが多数ありました。それらのご質問へのプロトタイピングチームの見解を以下に示しますので、ご確認いただければ幸いです。ただし、同様の観点に関する質問も多数いただき、それらは適宜言い換えて1つの質問にまとめましたので、ご了承ください。

Q1. 既存の AWS リソース (他の CloudFormation テンプレートや CDK プロジェクト、あるいはマネジメントコンソールで作成したもの) を CDK から参照できますか?

はい、ある CDK プロジェクトの外部で管理されているリソースの多くは、Lookup 系のメソッドを使うことで参照できます。例えば Vpc.fromLookup などです。また、既存の CloudFormation テンプレートを CDK プロジェクト内に取り込んで、CFn テンプレート内のリソースを CDK から参照する CfnInclude という機能もご利用いただけます。

Q2. CDK で開発環境や本番環境などの環境ごとにそれぞれ異なるパラメータを適用させるおすすめの方法はありますか?

CDKで環境ごとの構成を管理する方法は様々ございます。

各方法は長所短所がございますので、ぜひそれぞれお試しいただき、お客様のユースケースでフィットするかをご検討ください。また、この辺りの議論は先月発売された The CDK Book という電子書籍にも良くまとまっておりました。もし興味がございましたら、ご参照いただければ幸いです。

Q3. VSCode 用の CDK の補完プラグインはありますか?

TypeScript であれば、VSCode は標準で補完機能を利用可能です。他の言語についても各言語の拡張機能をインストールすることで補完が効くかと思います。また、VSCode の Snippet 機能を利用することで、頻出のコードについてはさらに入力の手間を削減することができます。

さらに、補完とは直接関係しませんが AWS Toolkit for Visual Studio Code を使うと、CDK のコードで定義されるテンプレート内部の構造 (Construct tree) を可視化することができます。抽象度の高い CDK コードが具体的にどのような CloudFormation リソースを定義しているか確認できて非常に便利ですので、ぜひこちらもご活用ください。

Q4. CDK の実装と Lambda の実装は同じリポジトリに含めるべきでしょうか?

プロトタイピングチームでは、 Lambda のデプロイを CDK で行う場合はそれらの実装は同じリポジトリに含めます。CDK ではインフラのデプロイとアプリケーションのデプロイを同時に行うことになりますが、デプロイの単位でリポジトリが集約されている方が CI/CD パイプラインの構築もやりやすく便利が良いためです。このため、例えば ECS などでコンテナのデプロイに CDK 以外のツールを使うような場合は、アプリケーション(コンテナ)と CDK のリポジトリを分けることもありえます。

また少し論点は変わりますが、ライフサイクルや管理の主体が異なるインフラ(例えば DB や VPC など )を、別のスタックやリポジトリに切り出して分けることもあります。スタックの分割については、Q5. スタックを分割する基準やルールでおすすめはありますか? の回答も併せてご確認ください。

Q5. スタックを分割する基準やルールでおすすめはありますか?

まず、必要のない限りはスタックを分割しないことをおすすめします。スタックを分けると、スタック間の結合やスタックの役割など考えることが増えて複雑化しがちです。最初は1つのスタックからはじめて、CloudFormation のリソース数制限などで問題が発生しそうであれば分割を検討するくらいでも十分な場合も多いかと思います。

スタック分割のルールはいくつかありますが、原則としてスタック間参照 (Cross-stack reference) の数ができるだけ少なくなる分割方法がおすすめです。(スタック間参照によりスタック間の依存が生まれ、それが多いほどメンテナンスがしづらい状態になるため。) スタック間参照数の最小化を目指すと、多くの場合それぞれのスタックがアプリケーションの機能ごとに分割された状態になるかと思います。

CDK Best Practices にもこうした話が言及されています。ぜひご確認ください。

Q6. CloudFormation、SAM、Terraform、Amplify CLIなど、他のIaCツールとの使い分けについて知りたいです

プロトタイピングチームにおいては、お客様の得意な技術スタック・チーム構成・要件との相性などを考慮して、適材適所でIaCツールを使い分けています。その中でも CDK は、生産性と柔軟性のバランスが良いこと、アプリケーション開発の知見を流用できて手に馴染みやすいことなどを理由に採用される場合が多いです。

Q7. ハイレベルConstructは便利ですが、抽象度が高すぎる印象も受けます。細かいパラメータもCDKのコードで管理したい場合は、ハイレベルConstructではなく低レベルConstructを使用するしかないでしょうか?

いいえ、ハイレベル Construct を利用している場合でも、低レベル Construct (CloudFormationリソース) と同等の操作が可能です。

抽象化されたハイレベル Construct (L2以上のConstruct) を利用することで、開発者は効率的に AWS のリソースを定義することができます。多くの L2+ Construct では必要十分なインターフェースが定義されておりますが、ごくまれに生の CloudFormation パラメータを触りたいユースケースもあるかと思います。そのような場合は、次の方法を使うことで L2+ Construct の内部にある L1 Construct を取り出して、具体的な設定値を編集することが可能です: Modifying the AWS CloudFormation resource behind AWS constructs この方法により CloudFormation と同レベルの操作が常に CDK でも可能になるため、安心してハイレベル Construct をご利用いただけます。

Q8. 実運用ではCodePipelineなどを使ってリリースするのでしょうか?それともコマンドでリリースするのでしょうか?

実運用においては、CI/CD パイプラインを利用するのが Well-architected の観点でベストプラクティスとなります。CDK で CI/CD を行う際は、CDK Pipelines を利用することで簡単にパイプラインを構築することが可能です。CDK Pipelines については、こちらの記事もご参照ください: CDK Pipelinesのmodern APIを使ってCDKアプリケーションをデプロイする

一方で短期的な開発効率が重視される検証作業や PoC 開発作業においては、今回のライブコーディングでお見せしたようにコマンドでデプロイできるようにした方が良い場合もあるかと思います。適材適所での使い分けをお勧めいたします。

Q9. CDK を使用する際におすすめの Linter などはありますか?

プログラミング言語部分の Lint は、各言語で一般的に利用される Lint 及び Linter の利用をおすすめします。例えば TypeScript では ESLint などです。また Lint の文脈からは少し外れるかもしれませんが、Aspects を使って CDK の各リソース定義に任意のValidationを実行する方法や、cfn_nag のような CloudFormation のテンプレート静的解析ツールを利用し、セキュアな IaC の実装をサポートする方法もあります。

Q10. CDK でデプロイしたリソースの設定をマネジメントコンソールで変更するとどうなりますか?

Drift が発生し、CDKによる変更が適用されなくなる場合があります。Drift とは CDK (CloudFormation) テンプレートと実際のリソースの設定値が異なる状況を指します。多くの Drift は CloudFormation の機能で検知することができ、Drift の有無は AWS Configで監視することも可能です。CDK のデプロイは、現在デプロイされている CloudFormation テンプレートとの差分を変更として適用するものであり、実際のリソースとの差分を変更として適用するわけではありません。このため CDK で管理しているリソースは、マネジメントコンソール上では変更しないことを推奨します。

Q11. CDK は多言語で利用可能なようですが、言語間の機能差が大きいということはありますか?

CDK では TypeScript や Python、Java、Go、C# など多様な言語で利用できます。基本的に各言語間で機能面の差はありません。サードパーティの Construct ライブラリについても、jsiiで自動変換されるため、全言語で利用可能です。ただし、開発体験やデバッグ実行のしやすさなど細かな面で微妙に異なる可能性があります。また、Go 言語バージョンのみまだ Developer Preview (2021/12現在) のため、ご注意ください。

もし今のところ特に好みがないようであれば、現状最も利用者が多いTypeScriptをオススメいたします。

Q12. CDK で Lambda を管理する場合、S3 にアセットを配置するため、毎回差分でてしまうのはしょうがないのでしょうか?

CDK ではビルド時に Lambda のコード(アセット)のハッシュ値を計算して、差分の有無を判断しています。このアセットハッシュが同じである限りは、差分は発生しません。アセットのハッシュ値計算の方法はアセットにより異なるため、ご利用のアセットのアセットハッシュ計算方法をご確認ください (例えば、PythonFunction では assetHashType プロパティで明示的に指定可能です。)

また、例えば Node.js の Lambda 関数の場合、一部のパッケージは npm ci でインストールするたびに生成物が変化する(deterministic でない)ものもあるようです。このようなパッケージがアセットに含まれているとビルドのたびにアセットハッシュが変化し、毎回差分が発生してしまうと考えられます。

Q13. ウェブ API 開発の際に SAM CLI を使用すると sam local api でローカルで動作確認しながら開発ができると思いますが、CDK の場合はローカルで動作確認する方法はあるでしょうか?

ローカルでの動作検証はいくつか方法がありますが、一つはモックなどを使って単体テストを実装する方法です。長期的な運用を見据えれば単体テストは必要と思いますので、整備をおすすめします。具体的な方法は 2021年版、サーバーレスのテスト手法を考える のスライドなどもご参照ください。

また、SAM CLI は CDK とも併用可能です。例えば、SAM CLI に CDK で作成した Lambda 関数の ARN を渡すと、その Lambda のログを tail 表示することもできます。さらに、SAM のベータリリースでは、CDK との統合を強化する機能も検討されています: Better together: AWS SAM and AWS CDK もし SAM がお好きでしたら、試してみると良いかもしれません。

また、CDK では hotswap 機能を使うことで、非常に高速に Lambda のデプロイが行なえます。さらに、CDK の watch 機能では、ローカルでのファイル変更を監視して、変更が検知されるごとに自動でデプロイすることも可能です。これらの機能を活用して、ローカルでの動作確認にはこだわらず、実際にデプロイされたリソースで素早く検証するのも有効でしょう。 watch や hotswap については、こちらの記事もご参照ください: Increasing development speed with CDK Watch

Q14. aws-lambda-nodejs を利用して Lambda のコードをビルド・デプロイすると、ビルド後のコードサイズが肥大化して、Lambdaのマネジメントコンソール上でコードが読めないことがあります。対策はありますか?

Lambda のマネジメントコンソールでは、一定のサイズを超えたコードは表示・編集できなくなります。コードをマネジメントコンソールで表示する必要がある場合は、次の方法で Lambda 関数のコードサイズを削減することも可能です。npm ライブラリを Lambda Layers に配置し、bundling オプションの externalModules に対象の npm ライブラリを指定します。これにより、指定したライブラリは Layer から参照されLambda のコードには 直接含められなくなるため、マネジメントコンソールから見える Lambda のコードの肥大化が抑えられます。

ただし、Lambda レイヤーを使うことで生まれる複雑性もあります。マネジメントコンソール上でコードを表示するのではなく、ローカルのエディタや GitHub などのリポジトリ管理ツール上でコードを表示・編集することもご検討いただくと良いと思います。

Q15. DynamoDB の同一テーブルにて2つ以上の GSI を操作すると CloudFormation でエラーとなりますが、CDK はその点同じ制約でしょうか?

はい、CDK も AWS リソースのデプロイ自体は CloudFormation を利用しているため、CloudFormation と同一の制約が課されます。ただし (DynamoDB の GSI では現状使えませんが、) CDKの hotswap 機能 では CloudFormation を介さないデプロイとなるため、CloudFormation の制約に縛られずデプロイが非常に高速などのメリットがあります。

Q16. CDK の API Reference は v1.134 までは従来のページにも公開されるが、v1.135 以降は Construct Hub にのみ公開されるということでしょうか?

いいえ、CDK V1 についても引き続き同サイト上に公式リファレンスが提供されます。Construct Hub は CDK の API リファレンスではなく、オープンソース化された CDK の Costruct ライブラリを検索可能にするポータルサイトです。

Q17. 既存の EC2 インスタンスを lookup できないのは何か理由があるのでしょうか?

p2 のラベルが付けられているため、開発の優先度が下げられていると考えられます。CDK の開発チームでは機能開発の優先度を決める際に、開発者からどれくらい需要があるのかも参考にしています。GitHub の Issue に Thumbs up👍  絵文字をつけることで、開発の優先度が上がる場合があります。また、欲しい機能を自ら実装して Pull Request を作成することも可能です。具体的な方法は CONTRIBUTING.md をご参照ください。

Q18. Snapshot tests の実装について、こちらのガイドと勉強会内で説明された実装が異なります。どう使い分けますか?

ガイドに乗っている方法でもテストできますが、TypeScript でスナップショットテストを行う場合はJest等の機能を使ったほうが記述量を少なくできます。@aws-cdk/assertions module のページも合わせてご参照ください。

Q&A は以上になります。

開催後のアンケートでは次回を期待する声が多数寄せられました (ありがとうございます!) ぜひ次回開催も前向きに検討していければと思います!

それでは、引き続き CDK 開発をお楽しみください!