はじめに
こんにちは、フリューのソフトウェアエンジニアkitajimaです。ピクトリンクの開発を担当しています。
2025年10月、Amazon ECS標準のカナリアデプロイメント/リニアデプロイメント機能がサポートされました。
つい先日、2025年7月にECS標準のブルー/グリーンデプロイメントがサポートされたところです。 CodeDeployをデプロイコントローラーとした各種デプロイ戦略が、徐々にECS標準に置き換わっていく流れを感じます。
今回はカナリアデプロイメントに注目し、L2 Constructに実装される前のCDKで利用した事例を紹介します。
Amazon ECS カナリアデプロイメントとは
カナリアデプロイメントは、新バージョンへのトラフィックを段階的に増やしていくデプロイ戦略です。
Amazon ECSにおいては、最初に5%といった小さな割合(Canary percentage)のトラフィックだけを新バージョンに流し、一定時間(Canary bake time)問題がないことを確認してから残りのトラフィックを切り替えます。
さらに、新バージョンに100%切り替えた後も一定時間(Deployment bake time)様子を見て、問題があればデプロイのロールバックをして旧バージョンに戻すことができます。

また、デプロイをロールバックするための複数の方法が提供されています。
- ECSのデプロイサーキットブレーカー
- ECSタスクの起動に失敗し、しばらくサービスが安定状態にならないならロールバック(従来通り)
- CloudWatch アラーム
- 監視したい条件でアラームを作成しておき、発報されたらロールバック
- ライフサイクルフック
- 「本番トラフィックシフト後」など、各種ライフサイクルで実行されるLambda関数を用意できる。失敗したらロールバック
- 手動
- マネジメントコンソール ECSサービスの「ロールバック」ボタンで手動でロールバックを実行

CDKで実装したい場合
ECSマネジメントコンソールではデプロイ戦略「Canary」が選択可能です。

しかし、本記事執筆現在の最新であるCDK v2.222.0ではまだサポートされていません。
よって、CDKで実装したい場合現時点では2つの選択肢が考えられます。
A. CDK L2 Constructでのサポートを待つ
特に急がない限り、こちらをおすすめします。 ブルー/グリーンデプロイメントは2025年7月に発表され、約1ヶ月後の8月にCDKでサポートされました。
また、L2 ConstructをサポートするPRも既に上げていただいており、近いうちにリリースされると思います。
B. CDK上でCFnのプロパティを上書きする形で実装する
ちょうどECSでカナリアデプロイメントを試したい事情があったため、CDK上でCloudFormationのプロパティを上書きする形で検証してみました。
必要なリソース
カナリアデプロイメントを実現するには、以下のリソースが必要でした。
代替ターゲットグループ(Alternate Target Group)
通常のターゲットグループに加えて、新バージョン用の代替ターゲットグループが必要です。
1点注意として、代替ターゲットグループはデプロイ時の一時的なものではありません。 1度デプロイすると代替ターゲットグループが利用され続けます。デプロイごとに利用されるターゲットグループが入れ替わり続けるわけです。

リスナールール
明示的なリスナールールを作成し、weightedForwardを使って2つのターゲットグループを指定します。
ECSがルーティングの重みをデプロイイベント中に動的に変更してくれるおかげで、カナリアデプロイメントが実現される仕組みです。
IAMロール
ECSにルーティングの重みをいじってもらえるように、IAMロールが必要です。今回はAmazonECSInfrastructureRolePolicyForLoadBalancersマネージドポリシーをアタッチしましたが、実際は最小権限の原則に基づいてカスタムポリシーを作成するのが望ましいです。
ECSサービスの設定
ECSサービスに対して、以下のプロパティを設定します。 それぞれCloudFormationのL1リソースプロパティを直接上書きする形で設定します。
- DeploymentConfiguration
- CANARY戦略を指定し、CanaryPercentやBakeTimeInMinutesを設定
- AdvancedConfiguration
- 代替ターゲットグループ、リスナールールARN、IAMロールを指定
実装
実装は専用のスタックとして切り出しました。
propsで既存のECSサービスやALBリスナー、ターゲットグループを受け取る形にしています。
export class CanaryDeploymentResourcesStack extends Stack { constructor(scope: Construct, id: string, props: Props) { super(scope, id, props); // 代替ターゲットグループ const alternateTargetGroup = new ApplicationTargetGroup( this, `sample-ecs-alt-targetGroup`, { vpc: Vpc.fromVpcAttributes(this, ...), targetGroupName: `sample-ecs-alt-tg`, } ); // リスナールール const listenerRule = new ApplicationListenerRule( this, `sample-listener-rule`, { listener: props.listener, action: ListenerAction.weightedForward([ { targetGroup: props.originalTargetGroup, weight: 100, // 振る舞いに変化が無いように100%を元のTGに割り振るが、ECSがデプロイ時に動的に変更してくれる }, { targetGroup: alternateTargetGroup, weight: 0, // 同上 }, ]), priority: 1, conditions: [ // 必須項目だが特に条件は不要なため、すべてのパスにマッチさせる ListenerCondition.pathPatterns(['/*']), ], } ); // ECSがELBを操作するためのIAMロール const canaryDeploymentExecutionRole = new Role( this, `sample-canary-deploy-role`, { assumedBy: new ServicePrincipal("ecs.amazonaws.com"), managedPolicies: [ ManagedPolicy.fromAwsManagedPolicyName( "AmazonECSInfrastructureRolePolicyForLoadBalancers" ), ], } ); // ECSサービスのCFnリソースを取得してプロパティを上書きする const cfnService = props.ecsService.node.defaultChild as CfnService; if (props.enableCanaryDeployment) { cfnService.addPropertyOverride('DeploymentConfiguration', { 'Strategy': 'CANARY', 'BakeTimeInMinutes': 10, 'CanaryConfiguration': { 'CanaryBakeTimeInMinutes': 10, 'CanaryPercent': 5, }, }); cfnService.addPropertyOverride('LoadBalancers.0.AdvancedConfiguration', { 'AlternateTargetGroupArn': alternateTargetGroup.targetGroupArn, 'ProductionListenerRule': listenerRule.listenerRuleArn, 'RoleArn': canaryDeploymentExecutionRole.roleArn, }); } } }
なお、リリース担当者がデプロイ戦略を選べるように、Context変数でカナリアデプロイメントの有効化フラグを受け取るようにしました。
const enableCanaryDeployment = app.node.tryGetContext('enableCanaryDeployment') === 'true'; new CanaryDeploymentResourcesStack(app, `${env}-${projectName}-canary-deployment-resources-stack`, { // ...その他のプロパティ enableCanaryDeployment: enableCanaryDeployment, });
さいごに
ECS標準のカナリアデプロイメントをCDKで利用してみました。CDKでのL2 Constructのサポートはまだですが、CloudFormationのプロパティを直接上書きすることで実現できました。
ただ、正直なところCDKでのサポートを待つのが一番楽で安全だと思います。最新の機能を先取りできるのは良い反面、L2 Constructへのリファクタリングも後々やりたくなってきます。 どうしてもCDKでのサポートが待てない場合は、ぜひ参考にしてみてください。