AWS CDKによるInfrastructure as Code
AWS CDKのApp・Stack・Constructの階層、CloudFormationとの関係、リソース参照とGrantによる権限設定、環境別コンテキスト、BootstrapからデプロイまでのCLI開発サイクルを解説します。
AWS CDKとCloudFormationの関係
AWS CDK(AWS Cloud Development Kit)は、TypeScript、Python、Java、C#、Goなどのプログラミング言語でAWSインフラを定義するオープンソースのInfrastructure as Code(IaC)フレームワークです。CloudFormationテンプレートを直接JSONまたはYAMLで記述する方法に対し、CDKではクラス、オブジェクト、関数など、開発者が使い慣れた言語の仕組みを使ってリソースを組み立てられます。Construct Libraryが提供する抽象化や既定値を活用できるため、設定の共通化や構成部品の再利用もしやすくなります。
CDKはCloudFormationの代替となる別のリソースプロビジョニングサービスではありません。CDKアプリケーションを実行すると、まずリソース定義がCloudFormationテンプレートへ合成(synthesize)されます。そのテンプレートをCloudFormationに渡すことで、AWSリソースの作成・更新・削除が行われます。したがって、実際のデプロイとスタック管理を担うのはCloudFormationであり、変更セットなどCloudFormationの機能も活用できます。
App・Stack・Constructの階層
CDKアプリケーションは、App → Stack → Constructを基本とするConstructツリーで構成されます。ツリーの親子関係はリソースの所有関係やコード上の構成を表し、Constructを移動すると合成されるリソース識別子に影響することがあります。
| 要素 | 役割 | 覚えておきたいこと |
|---|---|---|
| App | CDKアプリケーション全体のルート | 1つのAppに複数のStackを含められる。App自体は通常、AWSリソースを直接作るためのConstructではなく、アプリ全体をまとめて合成する |
| Stack | デプロイとCloudFormationスタック管理の基本単位 | App内に複数作成できる。アカウント、リージョン、環境、サービスなどの境界で分割し、独立した単位でデプロイできる |
| Construct | AWSリソースや関連設定を表す構成部品 | Stackの中に複数置ける。Constructの中に別のConstructを含める入れ子構造も作れ、再利用可能な独自部品も実装できる |
CDKのConstructは、AWSリソースを1つだけ表すとは限りません。抽象化の程度によって、CloudFormationリソースを直接表す低レベルのConstructから、複数リソースをまとめた高レベルのConstructまであります。Constructツリーの識別子は各スコープ内で一意である必要があり、CDKは親から子までのパスなどを使ってCloudFormationテンプレート内で必要となる識別子を生成します。CloudFormationテンプレート上の論理IDと関連しますが、Constructのidをそのまま論理IDとして固定的に使うという意味ではありません。
たとえば、社内向けのイベント処理基盤を作るAppに、検証環境用と本番環境用のStackを置き、それぞれにイベント受け付け用のキュー、処理用Lambda関数、監視設定のConstructを配置できます。サービスや環境をStackとして分割すれば、変更範囲やデプロイ時の境界を管理しやすくなります。一方、Stack間でリソースを参照する場合は依存関係が生じるため、結合度やデプロイ順序も考慮して分割します。
Constructの定義と引数
AWSリソースをConstructとして作るとき、一般的に次の3つの値をコンストラクタへ渡します。
| 引数 | 意味 | 設計上の役割 |
|---|---|---|
scope |
Constructの親となるスコープ | 通常は現在のConstructを表すthis(Pythonではself)を渡し、Constructツリー上の所属先を示す |
id |
その親スコープ内での識別子 | 同じ親の直下で一意にする。ConstructツリーのパスやCloudFormation側の識別子生成にも関係する |
props |
リソースの設定値をまとめたオブジェクト | リソースの種類に応じて、実行設定、暗号化、保持期間、ネットワークなどを指定する。省略可能なプロパティや既定値が用意されることもある |
次のTypeScriptは、別の用途例として、注文処理用のキューを暗号化して作成する定義です。
import * as cdk from 'aws-cdk-lib';
import * as sqs from 'aws-cdk-lib/aws-sqs';
const app = new cdk.App();
const stack = new cdk.Stack(app, 'OrderProcessingStack');
const orderQueue = new sqs.Queue(stack, 'OrderQueue', {
encryption: sqs.QueueEncryption.SQS_MANAGED,
visibilityTimeout: cdk.Duration.seconds(45),
});
この例では、stackがスコープ、OrderQueueがスコープ内のID、暗号化方式と可視性タイムアウトを含むオブジェクトがpropsです。QueueはConstruct LibraryのConstructであり、CDKは定義内容をCloudFormationリソースへ変換します。サービスごとにpropsの型や意味は異なるため、設定可能な項目や既定値をAPIリファレンスで確認して使います。
リソース間の参照
CloudFormationテンプレートでは、リソース間で値を受け渡すときにRef、Fn::GetAtt、Fn::Subなどの組み込み関数を使います。CDKでは、Constructが公開するプロパティを別のConstructのpropsに渡す形で関係を表現できます。CDKはその値を合成時にCloudFormationの参照表現へ変換し、CloudFormationに依存関係を伝えます。
たとえば、処理用Lambda関数を作成するときに、先に定義したDynamoDBテーブルの名前を環境変数として渡すことができます。コード内にテーブル名を文字列で複製する必要はなく、table.tableNameのようなプロパティを使うことで、デプロイ時に決まる値も参照として扱えます。ConstructのAPIに応じて、ARN、名前、URL、IDなど必要な属性を選びます。
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
const app = new cdk.App();
const stack = new cdk.Stack(app, 'JobProcessingStack');
const jobsTable = new dynamodb.Table(stack, 'JobsTable', {
partitionKey: { name: 'jobId', type: dynamodb.AttributeType.STRING },
});
const worker = new lambda.Function(stack, 'JobWorker', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'worker.handler',
code: lambda.Code.fromInline('exports.handler = async () => ({ statusCode: 200 });'),
environment: {
JOBS_TABLE_NAME: jobsTable.tableName,
},
});
jobsTable.grantReadData(worker);
jobsTable.tableNameは通常、ソースコードの評価時点で実際の物理テーブル名が確定している値ではありません。CDKがトークンとして扱い、CloudFormationテンプレート内に実行時解決される参照を出力します。リソースの参照は便利ですが、別Stackのリソースを参照すればStack間依存が生じます。また、異なるアカウントやリージョンのリソースは単純な同一Stack内参照と同じ扱いにはならず、明示的な連携方法が必要です。
GrantメソッドとIAM権限
CDKのConstruct Libraryには、リソースへのアクセス権を意図ベースで表現するGrantメソッドが用意されています。たとえば、Lambda関数がDynamoDBテーブルを読み取る必要がある場合、テーブル側のgrantReadDataにLambdaの実行ロールを渡すことで、必要な読み取り操作の許可を追加できます。
jobsTable.grantReadData(worker);
Grantを使うと、IAMポリシーのアクション名やリソースARNをすべて手作業で組み立てる代わりに、アクセスの意図をConstruct間で表現できます。Construct LibraryはGrantの内容をもとに、対象のプリンシパルへアイデンティティベースのポリシーを加えたり、サービスによっては対象リソースのリソースベースポリシーも変更したりします。どちらが必要になるか、またどの操作が追加されるかはサービスやConstruct、対象ロールの状況によって異なります。
Grantメソッドは権限設計そのものを不要にするものではありません。以下を必ず確認します。
- 付与対象が想定どおりのIAMロールまたはプリンシパルであること。Lambdaの場合は通常、その関数の実行ロールが権限付与先となる。
grantRead、grantReadDataなどのメソッド名が示す範囲と、生成されたIAMアクションがアプリケーションに必要な最小限の権限であること。- 暗号化されたデータを扱う場合、データ読み取り権限とは別にKMSキーの使用許可も必要になる場合があること。
- リソースポリシー、VPCエンドポイントポリシー、SCP、Permissions Boundary、明示的なDenyなど、ほかの認可条件によりアクセスが制限される可能性があること。
- 外部から参照したリソースやConstructによっては、CDKがポリシーを追加できない、または何も変更しない場合があること。
最終的な権限は、合成後のCloudFormationテンプレートやcdk diffでレビューします。書きやすさだけを理由に広範囲なGrantを選ばず、利用するAPIとデータ範囲に応じた許可を選択することが重要です。
環境ごとの設定とcontext
検証・本番などの環境でインスタンスタイプや設定値を変えたいとき、コードに環境名ごとの条件を大量に埋め込むと、変更時の見通しが悪くなります。設定をコードから分離する方法の一つが、プロジェクトのcdk.jsonにあるcontextです。Context値は文字列、数値、配列、オブジェクトなどのJSON値を扱え、アプリケーションコードから読み出せます。
{
"app": "npx ts-node bin/app.ts",
"context": {
"stageConfig": {
"test": { "instanceType": "t3.small" },
"production": { "instanceType": "m7i.large" }
}
}
}
const stage = app.node.tryGetContext('stage') ?? 'test';
const stageConfig = app.node.tryGetContext('stageConfig');
const instanceType = stageConfig[stage].instanceType;
実行時にcdk --context stage=production synthのように値を渡す方法もあります。Contextにより、環境ごとの構成値を外部化し、同じStackコードを保ちながら値を切り替えやすくできます。ただしContext値はデプロイ先環境の指定と同じものではありません。アカウントとリージョンを固定するにはStackのenvなどで環境を指定し、認証情報やデプロイ対象も別途正しく設定します。
またCDK CLIは、利用可能なAZやAMIなど、AWSアカウントから取得した情報をContextとしてキャッシュすることがあります。キャッシュにより、毎回変化しうるルックアップ結果を固定し、同じCDKコードから予測しやすいテンプレートを合成できます。自動取得される値はcdk.context.jsonで管理されることがあり、通常のプロジェクト設定として保持する値はcdk.jsonのcontextに分けておくと、キャッシュのクリア時に意図せず消えることを防げます。キャッシュされたContextを手で書き換えるのではなく、CDK CLIのContext管理機能で更新します。
CDK CLIを使った開発とデプロイ
CDKを使う開発は、プロジェクトを用意し、対象環境をBootstrapし、テンプレートを合成・確認してからCloudFormationでデプロイする反復作業です。代表的なコマンドは次のとおりです。
| コマンド | 目的 | 主な注意点 |
|---|---|---|
cdk init |
選択した言語のCDKプロジェクトひな形を作成する | 新規アプリケーション開始時に使う。作成後はコード、依存パッケージ、設定を管理する |
cdk bootstrap |
デプロイ用のBootstrapリソースをCloudFormationスタックとして作成・更新する | デプロイ対象のアカウントとリージョンごとに準備する。後から必要に応じて更新することもある |
cdk synth |
CDKコードを実行し、CloudFormationテンプレートとCloud Assemblyを生成する | 通常はローカルのcdk.outに出力する。AWSリソースをデプロイする操作ではない |
cdk diff |
ローカルで合成される定義と、デプロイ済みスタックとの差を確認する | 主に既存スタックの更新前レビューに使う。初回は比較対象のスタックがない |
cdk deploy |
選択したStackのテンプレートとアセットをAWSへ配備し、CloudFormationスタックを作成・更新する | CloudFormationの変更セットや承認オプションを利用できる。変更内容と権限を確認してから実行する |
cdk destroy |
Stackを削除し、削除対象となる管理リソースをCloudFormation経由で削除する | データ保持ポリシーなどにより残るリソースがあり、永続データを失う危険もあるため事前確認する |
基本的な初期化と反復の流れは次のようになります。
cdk initでプロジェクトの骨組みを作り、リソースやConstructを実装する。- デプロイ先として使うアカウント・リージョンを決め、その環境で
cdk bootstrapを実行する。 cdk synthでコードからCloudFormationテンプレートを作り、定義と出力を確認する。- 既存Stackの変更では
cdk diffで追加・変更・削除の候補をレビューする。 cdk deployで変更をCloudFormationへ渡し、Stackの作成または更新を実行する。- コード変更後はSynth、Diff、Deployを繰り返す。不要な環境を片付ける場合にのみ、影響を確認して
cdk destroyを使う。
Bootstrapとアセット
cdk bootstrapは、CDKアプリケーションをAWS環境へデプロイするための基盤を準備します。Bootstrap Stackは通常CDKToolkitという名前で作成され、アセットの保管・受け渡しに使うS3バケット、コンテナイメージ用ECRリポジトリ、デプロイを許可するIAMロールなどを含みます。実際の構成はBootstrapテンプレートのバージョンやオプションによって異なります。
CDKでは、Lambdaコード、ファイル群、コンテナイメージなど、デプロイに必要なファイルをアセットとして扱います。CLIはアセットを準備し、内容に応じてBootstrap環境のS3またはECRへアップロードします。その後、CloudFormationがテンプレートを処理する際に必要なアセットを参照します。従って、CDKコードがローカルにあるだけでは配備は完了せず、アセットの転送先を含むBootstrap環境と、その操作権限が必要です。
Bootstrapは「AWSアカウント全体で一生に一度だけ」行う操作ではありません。利用する各アカウント・リージョンは独立した環境なので、それぞれに準備が必要です。初回の利用時に実行するほか、より新しいCDK機能やデプロイ方式に対応するためBootstrap Stackを更新することもあります。
Synth・Diff・DeployとCloudFormationの変更セット
cdk synthはCDKコードをCloudFormationテンプレートに変換する工程です。構文や合成結果を確認するのに役立ちますが、生成しただけでAWS上のリソースは作成されません。cdk diffは合成結果を既存Stackの状態と比較し、リソースの追加、設定変更、削除などの差をレビューするためのコマンドです。比較対象となるStackがまだない初回デプロイでは通常、更新差分の確認には使えません。
cdk deployではCloudFormationがスタックの作成・更新を進めます。CloudFormationが内部で変更セットを使う構成では、リソースに適用される変更を実行前に調べられます。cdk diffとCloudFormation変更セットは関連するレビュー手段ですが、同一の機能ではありません。DiffはCDK CLIがローカルの合成結果とデプロイ済み状態を比較する操作で、変更セットはCloudFormationが変更を実行する前に評価する仕組みです。削除や置換、IAM権限の拡大など、影響の大きい差分を確認してから適用します。
Destroyとリソースのライフサイクル
cdk destroyは指定したStackをCloudFormation経由で削除するコマンドです。Stackが管理するリソースは削除対象になりますが、すべてのリソースが必ず消えるとは限りません。S3バケットやデータベースなどの保持設定(Removal Policy)がRETAINならStack削除後もリソースは残り、逆に破棄設定ではデータ消失につながる場合があります。たとえば、オブジェクトが残ったS3バケットは、そのままではCloudFormationから削除できない場合があります。したがってdestroyは一時環境の片付けに便利な一方、本番データを含むStackでは慎重な確認が必要です。
DVA試験で区別するポイント
- CDKとCloudFormation:CDKは使い慣れた言語による定義とテンプレート生成を担い、リソースのデプロイ・スタック管理はCloudFormationが担う。
- App・Stack・Construct:Appはアプリ全体のルート、StackはCloudFormationのデプロイ単位、Constructはリソースまたは再利用可能な構成を表す。
scope・id・props:親スコープ、スコープ内識別子、リソース設定値を表す。Construct IDはスコープ内で一意にする。- リソース参照:Constructプロパティの参照は、合成時にCloudFormationのRef/GetAtt等へ変換される。デプロイ時に決まる値はトークンとして扱われることがある。
- Grant:アクセス許可を簡潔に表現する仕組みであり、権限が自動で常に最小化される保証ではない。生成されたポリシーと他の認可条件を確認する。
- 環境別Context:
cdk.jsonやCLIオプションからアプリ設定を与える仕組み。ContextとStackのデプロイ先アカウント・リージョン指定は別の設定である。 - Bootstrap:デプロイ用のS3/ECRやIAMロールなどを対象環境に準備する。各アカウント・リージョン単位で必要となる。
- コマンドの役割:
synthはテンプレート生成、diffは変更比較、deployはCloudFormation経由の適用、destroyはStack削除である。
公式ドキュメント
重要ポイント
- ▸AWS CDKはTypeScriptやPythonなどでAWSインフラを定義するオープンソースのIaCフレームワークであり、CloudFormationを置き換えるのではなくテンプレート生成とデプロイを支援する
- ▸Appはアプリケーションのルート、StackはCloudFormationのデプロイ単位、Constructはリソースや再利用可能な構成を表す基本部品である
- ▸Constructのscope・id・propsはそれぞれ親、スコープ内識別子、設定値を表し、Constructの階層からCloudFormationのリソース識別子が合成される
- ▸Constructのプロパティによるリソース連携は、合成時にRefやFn::GetAttなどのCloudFormation参照へ変換される
- ▸Grantメソッドは権限付与を簡潔に表現するが、生成されるIAMポリシーを確認し、最小権限とリソースポリシーの要否を検討する
- ▸cdk.jsonのcontextは環境別設定やルックアップ値の管理に使えるが、デプロイ先アカウント・リージョンを自動で決めるものではない
- ▸cdk bootstrapは利用するアカウント・リージョンごとに必要なデプロイ基盤を用意し、init・synth・diff・deploy・destroyで開発とライフサイクルを管理する
このトピックの学習を完了しますか?
完了状態はいつでも切り替えられます
この試験ドメイン内で次の学習に進む
同じサービスの関連トピック
開発自動化と IaC に関連するトピックを続けて確認できます。