
CodePipelineからECSにBlue/Greenデプロイする
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、かたいなかです。
以前、ECSがCodeDeployによるBlue/Greenデプロイに対応したことをお伝えしました。
今回は、CodePipelineからECS+CodeDeployへのデプロイを行うことで、CodeBuildでDockerイメージをビルドし、ビルドしたイメージをもとにタスク定義の新しいリビジョンを登録、ECSのサービスを更新するといった一連の流れを自動で行えるようにする方法をご紹介します。
構築するパイプラインの概要
今回は、以下のようなパイプラインを構成します。

GitHubの特定のブランチを変更を契機に処理を開始します。CodeBuildでイメージをビルドし、ECRにプッシュします。そして、最後にCodeDeploy + ECSを使用してデプロイを行うという流れです。
手順
では、実際にやっていきましょう。
設定としては以下の流れで進めます。
- CodeDeployにデプロイを行うための設定ファイル(appspec.yamlとtaskdef.json)をリポジトリに追加
- CodeBuild用の設定ファイル(buildspec.yml)をリポジトリに追加
- CodePipeline作成
前提条件
今回は、CodeDeploy + ECSのデプロイを行えるような、ECSのServiceやCodeDeployのデプロイグループが作成されている状態を前提として進めます。こちらの設定方法は以下のリンク先の記事を参考にしてください。
CodeDeploy用の設定ファイルをソースコードに追加
appspec.yaml
appspec.yamlというファイルを以下のような内容で作成し、リポジトリのルートに置いておきます。
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: "<TASK_DEFINITION>" ## <TASK_DEFINITION>という文字列を置き換えることなくそのまま使用してください。
        LoadBalancerInfo:
            ContainerName: "<ALBがトラフィックを流す対象とするコンテナの名前>" ##適切な名前に置き換えてください
            ContainerPort: "<ALBがトラフィックを流す対象とするポート>" ##適切なポート番号に置き換えてください
ハイライトした行のようにTaskDefinitionの部分を<TASK_DEFINITION>というプレースホルダにしておきます。ここは後ほどCodeDeployが置き換えてくれますのでそのままにしておきましょう。コンテナ名とポートは適切な値に置き換えてください。
taskdef.json
次にタスク定義の内容を設定するtaskdef.jsonを以下のような内容で作成し、リポジトリのルートに置いておきます。
{
  "executionRoleArn": "<ECSのタスク実行ロールのARN>",
  "containerDefinitions": [
    {
      "name": "fizzbuzz",
      "image": "<IMAGE1_NAME>",
      "portMappings": [
        {
          "containerPort": 80,
          "hostPort": 80,
          "protocol": "tcp"
        }
      ],
      "essential": true
    }
  ],
  "requiresCompatibilities": ["FARGATE"],
  "networkMode": "awsvpc",
  "cpu": "256",
  "memory": "512",
  "family": "<タスク定義のファミリー名>"
}
ハイライトした行のようにimageの部分を<IMAGE1_NAME>というプレースホルダにしておきます。ここは後ほどCodeDeployが置き換えてくれますのでそのままにしておきましょう。ECSのタスク実行ロールのARNとタスク定義のファミリー名の部分は置き換えてください。
CodeBuild用の設定ファイルを準備
CodeBuildで行う処理を指定するのbuildspec.ymlというファイルをリポジトリのルートに作成します。
version: 0.2
phases:
  pre_build:
    commands:
      ## ECRにログイン
      - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)
      ## Dockerイメージのタグとして使用するため、Gitのコミットハッシュを取得
      - IMAGE_TAG=$CODEBUILD_RESOLVED_SOURCE_VERSION
  build:
    commands:
      ## Dockerイメージのビルド
      - docker build -t $IMAGE_REPOSITORY_NAME:$IMAGE_TAG .
      ## DockerイメージのECRへのプッシュ
      - docker push $IMAGE_REPOSITORY_NAME:$IMAGE_TAG
      ## ECS+CodeDeployにどのイメージを使用するか指示するためのファイルを作成
      - printf '{"Version":"1.0","ImageURI":"%s"}' $IMAGE_REPOSITORY_NAME:$IMAGE_TAG > imageDetail.json
artifacts:
  ## buildの最後で作成したファイルをアーティファクトとして流す
  files: imageDetail.json
ハイライトした行で、以下のようなファイルをimageDetail.jsonという名前で作成し、アーティファクトとして指定しています。
{
    "Version":"1.0",
    "ImageURI": "<DockerイメージのURI>"
}
このようにしておくことで、後ほど、CodeDeploy+ECSでのデプロイ時にtaskdef.json内でプレースホルダにしておいた部分が、ここでビルドしたイメージの情報で置き換えることができます。
CodePipeline構築
最後に、CodePipelineを構築していきます。
デプロイの部分でCodePipelineの作成時のウィザードでは設定が行えない項目があるため、GitHubとCodeBuildのみのパイプラインを先に作成し、後からECS (Blue/Green) のステージを追加する形ですすめます。
GitHub + CodeBuildのパイプラインを先に作成
この部分に関してはCodeDeploy + ECSにデプロイする場合に限ったものではないためこの記事内では割愛します。例えば、以下の記事を参考にデプロイ部分の設定をスキップする形で設定してください。
パイプラインにECS (Blue/Green) でデプロイを行うステージ、アクションを追加
パイプラインの一番うしろに新しいステージを作成し、そのステージ内に以下のような設定でアクションを作成します。
| 設定項目 | 設定値 | 備考 | 
|---|---|---|
| アクション名 | <任意> | ここで行う処理がわかりやすい名前 | 
| アクションプロバイダ | Amazon ECS(Blue/Green) | |
| AWS CodeDeploy アプリケーション名 | <先に作成しておいたアプリケーション名> | |
| AWS CodeDeploy デプロイグループ | <先に作成しておいたアプリケーション名> | |
| Amazon ECS タスク定義 | SourceArtifacttaskdef.json | Sourceの出力アーティファクトと先に作っておいたファイルを指定 | 
| AWS CodeDeploy AppSpec ファイル | SourceArtifactappspec.yaml | Sourceの出力アーティファクトと先に作っておいたファイルを指定 | 
| 入力アーティファクトとイメージの詳細 | BuildArtifact | Buildの出力アーティファクト imageDetail.jsonを含む | 
| タスク定義のプレースホルダーテキスト | IMAGE1_NAME | taskdef.json内のプレースホルダ | 
| 入力アーティファクト | SourceArtifactBuildArtifact | Source,Buildの出力アーティファクト | 
動作確認
パイプラインの画面で変更のリリースボタンをクリックすると、新たなデプロイが開始されます。正しく設定が行われていれば、一連の処理が実行されECSへのデプロイが実行されます。

なお、CodeDeployで、置き換え先環境にトラフィックを向けるのを指示されるまで待つ設定や置き換え前の環境を一定時間残すように設定している場合は、トラフィックの向き先を変える処理や置き換え前の環境の削除が完了した時点でCodePipeline側で処理が完了した扱いになるようです。
まとめ
CodePipelineの一連の処理の中にECS+CodeDeployでのBlue/Greenデプロイを組み込む方法をご紹介しました。
CodePipelineから実行することで、ソースコードの変更からデプロイまでの一連の流れの中にECSへのBlueGreenデプロイを組み込むことができます。
参考
- チュートリアル: Amazon ECR ソースと、ECS と CodeDeploy 間のデプロイでパイプラインを作成する:ECRをソースとしてECS(Blue/Green)にデプロイを行うチュートリアルです。
- AWS CodeDeploy AppSpec File リファレンス:今回の記事の中でも作成したAppSpecファイルのリファレンスです。
- ECSでCodeDeployを使用したBlue/Green Deploymentがサポートされたので早速試してみた:ECS + CodeDeployでBlue/Greenデプロイメントを行えるようにする弊社記事です。













