はじめに
タイトルの通りだが、2022/10時点におけるAWS CDKにおけるECSの Blue Green Deploymentの対応状況について記載する。
公式ドキュメント的に推奨されていないやり方だが、現状問題なく動作しているのでやったことをまとめておく。
概要
以下のIssueの通りAWS CDKにおいて、正式にはBlue Green Deploymentに対応していない。
しかし上記のIssueの中でも議論されている通り、CfnDeploymentGroup
を使用するとBlue Green Deploymentを実装することができる。
ただし、上記には以下の通りECSのBlue Green Deploymentには使うなという記載がある。そのため使用する際は自己責任で行うこと。
Amazon ECS blue/green deployments through CodeDeploy do not use the AWS::CodeDeploy::DeploymentGroup resource. To perform Amazon ECS blue/green deployments, use the AWS::CodeDeploy::BlueGreen hook. See Perform Amazon ECS blue/green deployments through CodeDeploy using AWS CloudFormation for more information.
※2022/11/2追記
本記事の内容は古い。v2.50.0でL2 Constructが実装されたので基本的にはそちらを使うのが良い。詳細は以下記事を参照。
実装方法
Blue Green Deploymentに直接関わる部分以外の実装は省略する(別途全体公開するかも)
1. CodeDeployのロールを作成する。
ECSにデプロイする権限を持つCodeDeployのIAMロールを作成する。
// CodeDeployのロール作成 const codeDeployRole = new iam.Role(this, 'CodeDeployRole', { assumedBy: new iam.ServicePrincipal('codedeploy.amazonaws.com'), managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName('AWSCodeDeployRoleForECS') ] })
2. CodeDeployのECSアプリケーションを作成する。
以下の通り。
// CodeDeployのECSアプリケーションを作成 const ecsApplication = new codedeploy.EcsApplication(this, 'EcsApplication', { applicationName: 'ECSServiceApp', // 名称は任意 });
3. デプロイメントグループを作成する。
問題の箇所。
ドキュメント上ではECSのBlue Green Deploymentに使うなと言われているCfnDeploymentGroup
を使用してDeployment Groupを作成する。
const deploymentGroup = new codedeploy.CfnDeploymentGroup(this, 'ECSDeploymentGroup', { applicationName: ecsApplication.applicationName, // 2で作成したECSアプリケーション名を設定 serviceRoleArn: codeDeployRole.roleArn, // 1で作成したIAMロールのARNを設定 autoRollbackConfiguration: { enabled: true, events: ['DEPLOYMENT_FAILURE'] }, blueGreenDeploymentConfiguration: { deploymentReadyOption: { actionOnTimeout: 'CONTINUE_DEPLOYMENT', waitTimeInMinutes: 0 }, terminateBlueInstancesOnDeploymentSuccess: { action: 'TERMINATE', terminationWaitTimeInMinutes: 5 // この辺りの設定はお好きに } }, deploymentConfigName: 'CodeDeployDefault.ECSAllAtOnce', deploymentGroupName: 'ecsDeployment', // 手順4で使用する。 deploymentStyle: { deploymentOption: 'WITH_TRAFFIC_CONTROL', deploymentType: 'BLUE_GREEN' }, loadBalancerInfo: { // ターゲットグループやリスナーは別途実装したALBのものを参照。 targetGroupPairInfoList: [{ targetGroups: [ { name: blueTargetGroup.targetGroupName }, { name: greenTargetGroup.targetGroupName } ], prodTrafficRoute: { listenerArns: [listener.listenerArn] }, testTrafficRoute: { listenerArns: [testListener.listenerArn] } }] }, ecsServices: [{ // クラスター名、サービス名は別途実装したものを参照。 clusterName: ecsCluster.clusterName, serviceName: ecsService.serviceName, }] })
4. CodePipelineにCodeDeployのステージを追加する
ここも若干癖あり。特にDeploymentGroupは正式なものが用意されていない感満載だが、一応下記の通り実装すれば実現できる。
CodePipelineのDeploy Actionに紐付けるためのDeployment Groupを作成して名称一致で無理やり3で作成したものと紐づけるイメージ。
以下参考。 docs.aws.amazon.com
// CodePipelineを定義 const pipeline = new codepipeline.Pipeline(this, 'CodePipeline', { pipelineName: 'CodePipeline' }); // CodePipelineにDeployステージを追加 const deployStage = pipeline.addStage({ stageName: 'Deploy' }); // DeploymentGroupを作成する。ここは名称を参照する形で力づくで作成している感ある。 const deploymentGroup: codedeploy.IEcsDeploymentGroup = codedeploy.EcsDeploymentGroup.fromEcsDeploymentGroupAttributes(this, 'EcsCodeDeploymentGroup', { deploymentGroupName: 'ecsDeployment', // 手順3で作成したDeploymentGroupの名前と一致させる application: ecsApplication // 手順2で作成したECSアプリケーションを設定 }); // CodeDeploy用のActionを作成する。 const deployAction = new codepipeline_actions.CodeDeployEcsDeployAction({ actionName: 'EcsCodeDeploymentAction', deploymentGroup, taskDefinitionTemplateInput: buildOutput, appSpecTemplateInput: buildOutput, containerImageInputs: [{ input: buildOutput, taskDefinitionPlaceholder: "IMAGE1_NAME" // taskdef.jsonに設定するアレ }] }); // CodePipelineにデプロイアクションを追加 deployStage.addAction(deployAction);
ここまでの1~4を実装すれば、フルCDKで(一応)ECSのBlue Green Deploymentを実現できる。
普通にできたけどなんで使っちゃいけないんだ・・・?
わかる人教えてください...
注意点
上記でBlue Green Deploymentを実装した後、タスク定義をCDK上で更新(例えばvCPUを変えるなど)して既存のECSリソースに適用しようとすると以下のエラーが出る。
Unable to update task definition on services with a CODE_DEPLOY deployment controller.
要はタスク定義はちゃんとCodeDeployで更新しろということであり、CDKでタスク定義を更新しようとするとInPlaceでの更新扱いになって、エラーになる(つまりリポジトリに置いたtaskdef.jsonを更新してCodePipeline経由で更新するとかしないとダメ)。
これはよく考えておかないと後々取り返しつかなくなる気がする。
サーキットブレーカーがある今、無理にBlue Green Deploymentにこだわる必要ない気がするけどね。
AWS Dev Day 2022において
ECSのCDKに関するセッションやBlue Green Deploymentに関するセッションあるのでCDKでECSやっている人は必見な気がする。
特に気になっているのは以下2つ。
- C-3: Blue/Green デプロイと安全性と複雑性と
- C-4: AWS CDKでECS on FargateのCI/CDを実現する際の理想と現実
C-4で登壇される方はBlue Greenの話もするらしい。期待大。
前出したAWS DevDayのCFPの投票(👍)の締切が今日の23:59なので再度宣伝です。AWS CDKとECS on FargateのCI/CDについて話をする予定です。B/Gデプロイの対応状況なども話せればと思ってます。興味あればGitHubのissueに👍 お願いします!https://t.co/An3p1EZQq0 https://t.co/tJlTBpxy7Z
— tmk@リモート (@tmk2154) 2022年8月24日