AWS CDK Deployment Best Practices¶
チェック¶
- [ ] 本文を確認した
- [ ] 概要を確認した
- [ ] タグを確認した
- [ ]
inbox/直下へ移行した
概要¶
AWS CDKのデプロイを安全・高速・再現可能にするためのベストプラクティス記事。
Stageを使った環境分離、cdk.out を使ったsynth/deploy分離、asset build/publishとdeployの分離、cdk.context.json のコミットが主題。
CI/CDでCDKを扱うときに、環境ごとの差分、非決定性、デプロイ時間、再現性をどう抑えるかの実装断片が載っている。
本文¶
この記事は、AWS CDKで複数環境にデプロイする際の実装・運用パターンを整理している。
Stageで環境を表現する¶
Stage は App と Stack の間に位置する概念で、複数Stackを環境単位にまとめる。Dev、Stg、Prodのような環境を明示的に作り、それぞれにリージョンやAWSアカウントを指定する。
const app = new cdk.App();
new MyStage(app, 'Dev', {
...getProps('Dev'),
env: {
region: 'us-east-1',
account: '111111111111',
},
});
new MyStage(app, 'Stg', {
...getProps('Stg'),
env: {
region: 'us-east-1',
account: '222222222222',
},
});
new MyStage(app, 'Prod', {
...getProps('Prod'),
env: {
region: 'us-east-1',
account: '333333333333',
},
});
個人用Dev環境を作る場合は、cdk deploy のcontextで所有者を渡し、Stack名を動的に変える。
const owner = app.node.tryGetContext('owner') as string;
const devStageName = owner ? `Dev-${owner}` : 'Dev';
new MyStage(app, devStageName, {
...getProps('Dev'),
env: {
region: 'us-east-1',
account: '111111111111',
},
});
個人ごとにAWSアカウントが分かれているなら、環境変数からaccountを渡す設計もできる。
const app = new cdk.App();
new MyStage(app, 'Dev', {
...getProps('Dev'),
env: {
region: 'us-east-1',
account: process.env.AWS_ACCOUNT_ID || '111111111111',
},
});
synthとdeployを分ける¶
cdk deploy は通常、synth、asset build/publish、CloudFormation deployをまとめて実行する。CIでは、まず cdk synth でCloud Assemblyを作り、その成果物 cdk.out を後続ジョブで使うと、デプロイ対象が固定される。
jobs:
synth:
steps:
- run: npm ci
- run: npx cdk synth
- uses: actions/upload-artifact@v4
with:
name: cdk.out
path: cdk.out
deploy-dev:
needs: synth
steps:
- uses: actions/download-artifact@v4
with:
name: cdk.out
path: cdk.out
- run: npx cdk deploy --app cdk.out --require-approval never Dev/*
deploy-stg:
needs: deploy-dev
steps:
- run: npx cdk deploy --app cdk.out --require-approval never Stg/*
deploy-prod:
needs: deploy-stg
steps:
- run: npx cdk deploy --app cdk.out --require-approval never Prod/*
この分離により、環境ごとにsynth結果が変わるリスクを避けやすくなる。
asset build/publishとdeployを分ける¶
LambdaやDocker imageなどのassetがある場合、cdk deploy 内でasset build/publishも実行される。これを分離すると、assetのビルドとアップロードを先にまとめて行い、その後のdeployではCloudFormation更新に集中できる。
jobs:
synth:
steps:
- run: npm ci
- run: npx cdk synth
publish-assets:
needs: synth
steps:
- run: npx cdk publish-assets --unstable=publish-assets --app cdk.out Dev/*
- run: npx cdk publish-assets --unstable=publish-assets --app cdk.out Stg/*
- run: npx cdk publish-assets --unstable=publish-assets --app cdk.out Prod/*
deploy-dev:
needs: publish-assets
steps:
- run: npx cdk deploy --app cdk.out --require-approval never Dev/*
同一job内で複数環境向けにasset publishすると、Docker layer cacheが効きやすく、2回目以降のbuildを短縮できる。環境ごとにAWSアカウントが分かれている場合は、必要に応じてロールを切り替える。
cdk.context.json をコミットする¶
cdk.context.json は、synthesis時にAWSアカウントから取得した値をキャッシュするファイル。Vpc.fromLookup() や StringParameter.valueFromLookup() のようなcontext methodを使うと、CDK CLIがAWS SDKで情報を取得して保存する。
const vpc = Vpc.fromLookup(this, 'Vpc', {
vpcId,
});
const parameter = StringParameter.valueFromLookup(this, parameterName);
このファイルをコミットする主な理由は2つ。
- 非決定的な挙動を避ける
- デプロイ速度を上げる
例えば最新AMIをlookupしている場合、実行時点によって取得されるAMIが変わり、意図せずEC2が置き換わる可能性がある。cdk.context.json をコミットしておけば、以後のsynthでは同じ値を参照し、構成が安定する。
また、contextが未キャッシュの場合、CDKは一度dummy値でsynthし、その後AWSから値を取得して cdk.context.json を更新し、再度synthする。コミット済みならこの往復を減らせる。
要点¶
- Stageで環境単位を明示し、複数Stackをまとめる。
- 個人Dev環境はcontextやAWS accountで分けられる。
- CIでは
cdk synthとcdk deploy --app cdk.outを分けると再現性が上がる。 - asset build/publishをdeployと分けると、デプロイ時間と失敗範囲を制御しやすい。
cdk.context.jsonは非決定性を抑え、synthの再実行を減らすためにコミットする。