AWS CDKの内部動作と設計ベストプラクティスを整理してみた
はじめに
AWS CDK(AWS Cloud Development Kit)でインフラを構築する際、コードの書き方だけでなく「スタックをどこで分けるか」「Construct をどうまとめるか」「コードが裏側でどうやって AWS リソースに変換されるのか」といった内部の仕組みと設計の判断基準に迷う場面は少なくありません。
CDK は TypeScript などの言語で直感的に書ける反面、合成(synth)フェーズでの値のプレースホルダ化や、アセットのパッケージング・アップロード、CloudFormation によるスタック操作など、デプロイに至るまでに複数の内部ステップを踏んでいます。これらの仕組みを理解していないと、意図しないリソースの置換(再作成)やデプロイエラー、過度な共通化による複雑化を招いてしまいます。
本記事では、AWS CDK の基本操作を把握している方を対象に、デプロイの内部動作と実践的な設計ベストプラクティスを統合してコンパクトに整理します。
- スタック分割と Construct 構造化: 分割すべき 4 つの基準と、論理 ID 変化による置換リスクの防ぎ方
- 値と設定の受け渡し: Token と Context の解決タイミング、パラメータ注入のルール
- デプロイとアセットの仕組み:
cdk bootstrapの役割、Asset の 2 段階処理、ステートフルスタックの保護 - 開発効率化・テスト・ガバナンス:
cdk watchと hotswap、アサーション主役のテスト、権限の多層防御
なお、本記事の解説にあたっては、主に以下の AWS 公式ドキュメント、Black Belt オンラインセミナー、およびベストプラクティス資料を参考にしています。
1. スタック分割と Construct 構造化の判断基準
1-1. スタックは原則「分けない」
ベストプラクティスにおける大原則は**「必要が生じるまで単一スタックで管理する」**です[1]。
責務ごとに細かくスタックを分けたくなりますが、スタックをまたいでリソースを参照すると「クロススタック参照」が発生します。参照関係が固定されると、Stack の削除や更新順序に制約が生じ、最悪の場合は循環依存によってデプロイ不能に陥るリスクがあります。
スタックを分けるべき明確なケースは、次の 4 つに集約されます[1:1]。
| 分割の理由 | 具体例 | 分割する目的・背景 |
|---|---|---|
| 1. ライフサイクルの分離 | ステートフル(DB)とステートレス(API) | DB を保護したまま、API 側を安全かつ自由に再作成するため |
| 2. CloudFormation の上限回避 | 500 リソース / 1 MB テンプレート超過 | 引き上げ申請ができない CloudFormation の上限を回避するため[2] |
| 3. 環境・アカウントの境界 | マルチアカウント / マルチリージョン展開 | スタックは単一のアカウント・リージョンにデプロイされる単位であるため |
| 4. デプロイ段階の分離 | バックエンド API デプロイ → ビルド → フロントエンド | バックエンドデプロイ後に決まる出力値(API URL 等)をフロントエンドのビルド時に環境変数として渡すため |
1-2. Construct でまとめ、論理 ID の変化を防ぐ
スタックを分けない代わりに、スタック内部を Construct で意味のある単位に構造化します。ただし、リファクタリング時に最も注意すべきなのが CloudFormation の論理 ID の変化です。
論理 ID はルート(Stack)からの階層パス全体をもとに生成されるため、別の親 Construct に移動させただけでも変わってしまいます。デプロイ済みのリソースを安全に Construct 化するには、次の 2 つの手法が有効です。
手法 1:子リソースの ID に Default を使う
切り出した Construct 内で、主要リソースの ID に Default を指定します。Default という文字列は論理 ID のパス計算から自動的に除去されるため、階層が 1 段深くなっても論理 ID が変化しません[3:1]。
// 【リファクタリング前】
new s3.Bucket(this, "DataBucket"); // 論理 ID 例: DataBucketE3889A50
// 【リファクタリング後】ラッパー Construct に切り出し
export class DataStorage extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);
// 'Default' を指定すると論理 ID の階層パスから除外される
new s3.Bucket(this, "Default");
}
}
// 呼び出し側:ラッパーに元の ID 'DataBucket' を渡す
new DataStorage(this, "DataBucket"); // 論理 ID 例: DataBucketE3889A50(変更前と一致)
手法 2:cdk refactor コマンドを使う
旧論理 ID と新論理 ID をマッピングし、物理的なリソース置換を回避しながら Construct 構造を変更できる機能です(Preview、--unstable=refactor が必要)[3:2]。
2. 値の解決タイミングとパラメータ設計
2-1. Token と Context の違い
CDK で値を扱う際は、**「その値がいつ必要になるのか」**を区別することが重要です。
| 仕組み | 値が必要になるタイミング | 役割と具体例 |
|---|---|---|
| Context | 合成が終わるまで | テンプレート生成に必要な値(環境名、既存 VPC ID など) |
| Token | デプロイ時(CloudFormation 側) | デプロイ時に決まる値(新規作成するバケット名、ARN など) |
- Token の正体: 新規リソースの物理名や ARN のように、デプロイ時まで確定しない値をコード上で扱うための一時的な引換券(プレースホルダ
${Token[...]})です[4]。合成時に CloudFormation のRefやFn::GetAttに変換されます。未解決のプレースホルダであるため、TypeScript のif条件や文字列長判定には使用できません(未解決判定にはcdk.Token.isUnresolved()を使用)。 - Context の役割: 外部から注入する値です。
Vpc.fromLookup()などを実行すると、AWS 環境から取得した値がcdk.context.jsonに保存されます。テンプレートの一貫性を保つため、cdk.context.jsonは Git にコミットするのが公式の推奨です。
2-2. パラメータ受け渡しのルール
「将来の再利用」を見越して最初から過度にパラメータ化すると、見通しが悪くなります。公式でも**「まずはベタ書きから始める」**ことが推奨されています[1:2]。
環境ごとの設定値を渡す際は、次の原則を守ります。
- Construct や Stack の内部で環境変数を直接読まない: 設定値は必ず constructor の
propsで渡します。 - 環境変数の読み込みは App 層(最上位)で行う:
bin/*.tsなどのエントリーポイントで環境差異を吸収し、下層の Construct に props 経由で注入します。 - 機密値は Secrets Manager を利用する: API キーやパスワードはコードに含めず、Secrets Manager や SSM Parameter Store の参照値(ARN やパラメータ名)を props で渡します。
2-3. 既存リソースの参照手段
既存リソースを参照する際は fromXxx() メソッド(例: Bucket.fromBucketName())を使います。
返ってくるのは共通インターフェース(IBucket 等)を実装した代理オブジェクトです。既存リソース本体は CDK の管理対象外であるため、コードから削除しても実際のリソースは削除されません。また、addToResourcePolicy() などを呼んでも外部リソース側のポリシーは変更されず、権限を付与される IAM 側のみが変更される点に注意してください。
なお、SSM パラメータの StringParameter.valueFromLookup() は合成時に値が固定されて便利ですが、解決された値がテンプレートやコンテキストに平文で保存されます。機密情報には絶対に使用してはいけません[4:1]。
3. デプロイのライフサイクルとリソース保護
3-1. cdk bootstrap が準備するもの
Asset をデプロイする前に、デプロイ先のアカウント・リージョンごとに cdk bootstrap を実行します。
npx aws-cdk bootstrap --termination-protection
実行すると、AWS 上に CDKToolkit スタックが作成され、次のリソースが配備されます[5]。
- アセット用 S3 バケット: Lambda の zip ファイル等を配置(
DeletionPolicy: Retain) - コンテナ用 ECR リポジトリ: Docker イメージを配置
- デプロイ用 IAM ロール(5 種): CloudFormation 実行、ファイル公開、イメージ公開、ルックアップなどの権限
- バージョン管理用 SSM パラメータ: bootstrap テンプレートのバージョンを記録
誤って bootstrap スタックを削除するとデプロイ不能に陥るため、--termination-protection(スタック削除保護)を有効にしておくことが推奨されます。
3-2. Asset がデプロイされる 2 段階の仕組み
Lambda コードや Docker イメージなどの Asset は、「① アップロード指示(assets.json)」と「② テンプレートからの参照(CloudFormation)」の 2 ステップで処理されます[6]。
- 合成時:
cdk synthを実行すると、cdk.out/<Stack>.assets.jsonにファイルパスやハッシュ値(AssetHash)、アップロード先 S3 / ECR の指示が出力されます。CloudFormation テンプレート側には、そのアップロード先を参照する記述(Fn::Sub等)が埋め込まれます。 - デプロイ時: CDK CLI が
assets.jsonを読み、S3 や ECR へアセットを発行します。S3 上にすでに同じ AssetHash のファイルが存在する場合はアップロードをスキップするため、デプロイが高速化されます。
特に Lambda の Construct は、ビルドの責務に応じて使い分けます。
Function: 開発者が zip ファイルを用意NodejsFunction: esbuild が TypeScript / JavaScript を自動バンドル(Tree shaking で軽量化)DockerImageFunction: ローカル Docker がイメージをビルドして ECR へ push
3-3. データの安全を守る 3 つの保護レイヤー
本番環境のデータベースなどを含むステートフルなスタックでは、データの安全を多層で守る必要があります[7]。
| 保護の仕組み | 設定対象 | 防ぐ対象 |
|---|---|---|
スタック削除保護 (terminationProtection) |
Stack | cdk destroy やコンソールからのスタック全体の誤削除 |
削除ポリシー (removalPolicy) |
リソース単位 (L2) | スタック削除時やコード削除時のリソース本体(データ)消失。RETAIN や SNAPSHOT を指定 |
| スタックポリシー | Stack / リソース | cdk deploy による意図しない DB インスタンス等の置換・削除 |
4. 開発効率化・テスト・ガバナンス
4-1. cdk watch と hotswap の仕組み
日常の開発サイクルを高速化するコマンドが cdk watch です。
npx aws-cdk watch --all
cdk watch の核となるのが hotswap です。Lambda コードや ECS タスク定義の変更時、CloudFormation を経由せず AWS API を直接呼び出して数秒でリソースを更新します[8]。
4-2. テストは細かいアサーションを主役にする
テスト戦略において、「スナップショットテストを主役に据える」のは推奨されません[9]。
スナップショットテストはテンプレート全体を文字列比較するため、CDK のバージョンアップやメタデータの変化など、動作に影響しない変更でも頻繁にテストが落ちてしまいます。
- 細かいアサーション(Fine-grained assertions): 日常的な単体テストの主役。
hasResourceProperties等を使い、意図したプロパティだけをピンポイントで検証します。条件分岐やパラメータなどのロジックをコードに追加したタイミングでセットで書きます。 - スナップショットテスト: リファクタリング時の安全網として限定的に利用します(use them sparingly)。
4-3. 権限管理と多層セキュリティガードレール
IAM ポリシーは手書きせず、L2 Construct の grants を利用します[1:3]。
// 推奨:grants プロパティ経由
bucket.grants.read(lambdaFunction);
ただし、grants で生成されるポリシーにはワイルドカードが含まれる場合があるため、生成結果を cdk synth で確認する習慣が重要です。
また、社内共通のラッパー Construct だけでは開発者にバイパスされる可能性があるため、セキュリティ統制は次の 3 段階で多層に設計します[1:4]。
- アプリ内チェック: CDK Nag や合成時 Validation(
cdk synth時の静的チェック)[10] - CI / パイプラインでの検証: CloudFormation Hooks やスナップショット検証
- 組織の絶対的ガードレール: サービスコントロールポリシー(SCP)や AWS Config
4-4. 実務で役立つ CLI コマンド
近年の CDK CLI には、運用の自動化やリファクタリングを支援する便利なコマンドが多数追加されています[3:3]。
| コマンド | 用途 |
|---|---|
cdk diff --method=auto |
読み取り専用の Change Set を裏で作成し、リソースの再作成(置換)を高精度に検知する |
cdk refactor |
リソースの物理的置換を避けつつ、論理 ID やスタック構成を変更する(Preview) |
cdk orphan |
リソースを削除せずにスタックの管理下から切り離す(Preview) |
cdk drift |
デプロイ済みスタックのドリフト(実リソースとの乖離)を検出する |
cdk migrate |
既存の AWS リソースから CDK アプリを自動生成する |
まとめ
今回は、AWS CDK のデプロイ内部動作と設計判断のベストプラクティスを整理しました。
- スタック分割と論理 ID: スタックは原則分けず、Construct で構造化する。階層移動時のリソース置換は
DefaultID やcdk refactorで防ぐ。 - 値とパラメータ: 合成時に必要な値は Context、デプロイ時に決まる値は Token で扱う。環境差異は App 層から props 経由で注入する。
- デプロイと保護: Asset は
assets.jsonを介した 2 段階で配置される。本番のステートフルスタックは 3 つの保護レイヤーで守る。 - 効率化とテスト: 開発時は
cdk watchの hotswap を活用し、テストは細かいアサーションを主役に据える。
内部で CloudFormation や Asset がどう処理されているかを把握しておくと、予期せぬリソース置換やデプロイエラーを未然に防ぎ、自信を持ってシンプルなインフラコードを維持できます。
本ブログが、AWS CDK の内部動作や設計判断を整理したい方の参考になれば幸いです。
さらにハンズオンや実践的な知見を深めたい方は、以下の資料もあわせてご覧ください。
クラスメソッドオペレーションズ株式会社について
クラスメソッドグループのオペレーション企業です。
運用・保守開発・サポート・情シス・バックオフィスの専門チームが、IT・AIをフル活用した「しくみ」を通じて、お客様の業務代行から課題解決や高付加価値サービスまでを提供するエキスパート集団です。
当社は様々な職種でメンバーを募集しています。
「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、クラスメソッドオペレーションズ株式会社 コーポレートサイト をぜひご覧ください。※2026年1月 アノテーション㈱から社名変更しました
AWS CDK Developer Guide Best practices for developing and deploying cloud infrastructure with the AWS CDK、初心者がおさえておきたい AWS CDK のベストプラクティス 2024(2026年8月11日参照) ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
AWS CDK Developer Guide AWS CDK Constructs、Preserve deployed resources when refactoring CDK code、CLI Reference cdk refactor(2026年8月11日参照) ↩︎ ↩︎ ↩︎ ↩︎
AWS Black Belt Online Seminar「AWS CDK の基本的なコンポーネントと機能 (Basic #2)」(資料 PDF)、AWS CDK Developer Guide Tokens and the AWS CDK(2026年8月11日参照) ↩︎ ↩︎
AWS CDK CLI Bootstrap your environment、AWS CloudFormation DeletionPolicy(2026年8月11日参照) ↩︎
AWS CDK Developer Guide Assets and the AWS CDK(2026年8月11日参照) ↩︎
AWS CloudFormation スタック削除保護、AWS CDK API Reference RemovalPolicy(2026年8月11日参照) ↩︎
AWS CDK CLI cdk watch - コマンドリファレンス(2026年8月11日参照) ↩︎
AWS CDK Developer Guide Test AWS CDK applications(2026年8月11日参照) ↩︎
AWS CDK Developer Guide Policy validation at synthesis time(2026年8月11日参照) ↩︎










