aws-cdk について
AWS CDK と TypeScript で AWS インフラを構築するためのスキルで、アプリ、スタック、再利用可能なコンストラクトを作成・保守する開発者向けです。合成、テスト、差分確認、デプロイ前のレビューによる検証を重視します。
主な機能
- 01TypeScript による CDK アプリとスタックの指針
- 02L1、L2、L3 コンストラクトの選択
- 03再利用可能な構造とマルチスタックのパターン
- 04合成、アサーションテスト、差分確認
- 05デプロイとインフラの安全性チェック
活用シーン
- 01サーバーレス AWS API の作成
- 02再利用可能なインフラコンストラクトのリファクタリング
- 03クロススタック参照によるスタック接続
- 04デプロイ前のインフラ変更レビュー
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ giuseppe-trisciuoglio/ developer-kit --skill aws-cdkインストール後、Claude Code で/aws-cdkを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/core-concepts.mdnetworking-vpc.mdsecurity-hardening.mdserverless-patterns.mdtesting-strategies.md詳細
AWS CDK TypeScript
概要
再利用可能なコンストラクト、安全なデフォルト設定、検証を優先するデリバリーループを用いて、TypeScript で AWS インフラストラクチャを構築する際にこのスキルを使用します。
使用するタイミング
以下の場合にこのスキルを使用します。
- TypeScript で CDK アプリ、スタック、または再利用可能なコンストラクトを作成またはリファクタリングする
- L1、L2、L3 のコンストラクトから選択する
- サーバーレス、ネットワーキング、またはセキュリティを重視した AWS インフラストラクチャを構築する
- マルチスタックアプリケーションと環境に応じたデプロイを連携させる
cdk synth、テスト、cdk diff、cdk deployでインフラストラクチャの変更を検証する
手順
1. プロジェクトの初期化
# Create a new CDK app
npx cdk init app --language typescript
# Project structure
my-cdk-app/
├── bin/
│ └── my-cdk-app.ts # App entry point (instantiates stacks)
├── lib/
│ └── my-cdk-app-stack.ts # Stack definition
├── test/
│ └── my-cdk-app.test.ts # Tests
├── cdk.json # CDK configuration
├── tsconfig.json
└── package.json
2. コアアーキテクチャ
import { App, Stack, StackProps, CfnOutput, RemovalPolicy } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
// Define a reusable stack
class StorageStack extends Stack {
public readonly bucketArn: string;
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const bucket = new s3.Bucket(this, 'DataBucket', {
versioned: true,
encryption: s3.BucketEncryption.S3_MANAGED,
removalPolicy: RemovalPolicy.RETAIN,
blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
});
this.bucketArn = bucket.bucketArn;
new CfnOutput(this, 'BucketName', { value: bucket.bucketName });
}
}
// App entry point
const app = new App();
new StorageStack(app, 'DevStorage', {
env: { account: process.env.CDK_DEFAULT_ACCOUNT, region: 'us-east-1' },
tags: { Environment: 'dev' },
});
new StorageStack(app, 'ProdStorage', {
env: { account: '123456789012', region: 'eu-west-1' },
tags: { Environment: 'prod' },
terminationProtection: true,
});
app.synth();
3. コンストラクトのレベル
| レベル | 説明 | 使用する場面 |
|---|---|---|
L1 (Cfn*) | CloudFormation に直接対応し、完全な制御が可能 | L2 で公開されていないプロパティが必要な場合 |
| L2 | 適切なデフォルト設定とヘルパーメソッドを備えた厳選されたコンストラクト | 標準的なリソースのプロビジョニング(推奨) |
| L3(パターン) | 複数リソースから成るアーキテクチャ | LambdaRestApi などの一般的なパターン |
// L1 — Raw CloudFormation
new s3.CfnBucket(this, 'L1Bucket', { bucketName: 'my-l1-bucket' });
// L2 — Sensible defaults + grant helpers
const bucket = new s3.Bucket(this, 'L2Bucket', { versioned: true });
bucket.grantRead(myLambda);
// L3 — Multi-resource pattern
new apigateway.LambdaRestApi(this, 'Api', { handler: myLambda });
4. CDK ライフサイクルコマンド
cdk synth # Synthesize CloudFormation template
cdk diff # Compare deployed vs local changes
cdk deploy # Deploy stack(s) to AWS
cdk deploy --all # Deploy all stacks
cdk destroy # Tear down stack(s)
cdk ls # List all stacks in the app
cdk doctor # Check environment setup
5. 推奨するデリバリーループ
-
スタックを設計する
- L2 コンストラクトから始め、繰り返し使用するロジックはカスタムコンストラクトに抽出します。
-
cdk synthを実行する- チェックポイント:インポートの不足、不正なプロパティ、コンテキストの不足、未解決の参照がなく、合成が成功することを確認します。
- 失敗した場合:コンストラクトの設定またはコンテキスト値を修正してから、
cdk synthを再実行します。
-
インフラストラクチャのテストを実行する
- チェックポイント:アサーションで IAM のスコープ、ステートフルなリソース、重要な出力が検証されていることを確認します。
- テストが失敗した場合:スタックまたはテストの期待値を更新してから、テストスイートを再実行します。
-
cdk diffを実行する- チェックポイント:IAM 権限の拡大、リソースの置き換え、エクスポートの変更、ステートフルなリソースの削除を確認します。
- 差分にリスクがある場合:名前、依存関係、または
RemovalPolicyを調整してから、cdk diffを再実行します。
-
cdk deployを実行する- チェックポイント:スタックが
CREATE_COMPLETEまたはUPDATE_COMPLETEに到達することを確認します。 - デプロイが失敗した場合:CloudFormation のイベントを調べ、クォータ、権限、エクスポートの競合、またはブートストラップの問題を修正してから、
cdk deployを再試行します。
- チェックポイント:スタックが
-
実行時の結果を確認する
- 次に進む前に、スタックの出力、エンドポイント、アラーム、連携機能が想定どおりに動作することを確認します。
6. スタック間参照
// Stack A exports a value
class NetworkStack extends Stack {
public readonly vpc: ec2.Vpc;
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
this.vpc = new ec2.Vpc(this, 'Vpc', { maxAzs: 2 });
}
}
// Stack B imports it via props
interface AppStackProps extends StackProps {
vpc: ec2.Vpc;
}
class AppStack extends Stack {
constructor(scope: Construct, id: string, props: AppStackProps) {
super(scope, id, props);
new lambda.Function(this, 'Fn', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
vpc: props.vpc,
});
}
}
// Wire them together
const network = new NetworkStack(app, 'Network');
new AppStack(app, 'App', { vpc: network.vpc });
例
例 1:サーバーレス API
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
class ServerlessApiStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const table = new dynamodb.Table(this, 'Items', {
partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
const fn = new lambda.Function(this, 'Handler', {
runtime: lambda.Runtime.NODEJS_20_X,
handler: 'index.handler',
code: lambda.Code.fromAsset('lambda'),
environment: { TABLE_NAME: table.tableName },
});
table.grantReadWriteData(fn);
new apigateway.LambdaRestApi(this, 'Api', { handler: fn });
}
}
例 2:CDK アサーションテスト
import { Template } from 'aws-cdk-lib/assertions';
import { App } from 'aws-cdk-lib';
import { ServerlessApiStack } from '../lib/serverless-api-stack';
test('creates DynamoDB table with PAY_PER_REQUEST', () => {
const app = new App();
const stack = new ServerlessApiStack(app, 'TestStack');
const template = Template.fromStack(stack);
template.hasResourceProperties('AWS::DynamoDB::Table', {
BillingMode: 'PAY_PER_REQUEST',
});
template.resourceCountIs('AWS::Lambda::Function', 1);
});
ベストプラクティス
- スタックごとに関心事を分ける — ネットワーク、コンピューティング、ストレージ、モニタリングを分離します。
- L2 コンストラクトを優先する — サポートされていないプロパティが必要な場合に限り、
Cfn*を使用します。 - 環境を明示的に設定する — アカウントとリージョンを指定した
envを渡し、本番環境のターゲットが暗黙的に選ばれないようにします。 - grant ヘルパーを使用する — 可能な限り、手書きの IAM より
.grant*()を優先します。 - デプロイ前に差分を確認する — IAM 権限の拡大、置き換え、削除を必須のチェックポイントとして扱います。
- インフラストラクチャをテストする — 重要なリソースをきめ細かなアサーションで検証します。
- 値のハードコードを避ける — コンテキスト、パラメーター、または環境変数を使用します。
- 適切な
RemovalPolicyを使用する — 本番データにはRETAINを使用し、DESTROYは破棄可能な環境に限ります。
制約と警告
- CloudFormation の制限 — スタックあたりのリソースは最大 500 個です。大規模なアプリは複数のスタックに分割してください。
- 合成はデプロイではありません —
cdk synthはテンプレートを生成するだけで、変更を適用するにはcdk deployを実行します。 - スタック間参照は CloudFormation エクスポートを作成します。削除する際は慎重に順序を考慮する必要があります。
- ステートフルなリソース(RDS、DynamoDB、データを含む S3) — 本番環境では必ず
removalPolicy: RETAINを設定してください。 - ブートストラップが必要です — 初回デプロイの前に、アカウントとリージョンごとに一度
cdk bootstrapを実行します。 - アセットのバンドル — Lambda のコードと Docker イメージは CDK ブートストラップバケットにアップロードされます。
参考資料
詳細な実装ガイドは、references/ ディレクトリにあります。
- コア概念 — アプリケーションのライフサイクル、スタック、コンストラクト、環境、アセット
- サーバーレスのパターン — Lambda、API Gateway、DynamoDB、S3 イベント、Step Functions
- ネットワークと VPC — VPC の設計、サブネット、NAT、セキュリティグループ、VPC エンドポイント
- セキュリティの強化 — IAM、KMS、Secrets Manager、WAF、コンプライアンス
- テスト戦略 — アサーション、スナップショット、統合テスト、CDK Nag
コメント
Markdown 対応