【AWS】ECS構築の基礎 −Blue/Greenデプロイ編−


はじめに

前回の記事でCodeCommit, CodeBuild, CodePipelineを使って、AWSサービスのみでCI/CDパイプラインを構築しました。
今回は構築したパイプラインにBlue/Greenデプロイを追加して、CodeDeployから制御してみました。

ECS初心者向けの記事を何本か書いていますので、どれか参考になれば幸いです。

Blue/Greenデプロイ

Blue/Greenデプロイは、アプリケーションやマイクロサービスの古いバージョン(Blue環境)からテスト済の新しいバージョン(Green環境)に、ユーザートラフィックを徐々に転送するリリースモデルで、両バージョンが稼働中の状態で実施するものです。

BlueからGreenへのトラフィックの転送が完了すると、Blueはロールバックに備えてスタンバイさせるか、あるいはプロダクションからプルして更新し、次回の更新の際にテンプレートとして使用することができます。

ECSやFargateでBlue/Greenデプロイを実行するために、CodeDeployを使用します。

実装

前回の記事で作成したCI/CDパイプラインに以下の手順でBlue/Greenデプロイを追加します。

  1. IAMロールの作成
  2. ELBリスナーの作成
  3. サービスの作成
  4. buildspec.ymlの作成
  5. appspec.yamlの作成
  6. taskdef.jsonの作成
  7. Buildの編集
  8. Deployの編集
  9. パイプラインの実行

IAMロールの作成

CodeDeploy - ECSというユースケースを選択します。

この中にはAWSCodeDeployRoleForECSというポリシー(中身は以下)が含まれています。

CodeDeployServiceRoleと名付けます。

ELBリスナーの作成

次にELBでリスナーを作成します。
リスナーは設定したプロトコルとポートを使用して接続リクエストをチェックするプロセスです。
リスナーに対して定義したルールによって、ELBが登録済みターゲットにリクエストをルーティングする方法が決まります。

プロダクションリスナーを新しく追加します。

また、検証テストを使用するECSデプロイには2番目のリスナー(テストリスナー)が必要です。
このリスナーは、更新されたアプリケーションにテストトラフィックを提供するために置き換えタスクセットで使用されます。
検証テストは、テストトラフィックに対して実行されます。

HTTP:8088でTestリスナーを作成します。

サービスの作成

ECSクラスターecs-serviceに新しくサービスを作成します。
タスク定義やクラスターを選択して、サービス名を設定します。

デプロイメントタイプ、デプロイメント設定、CodeDeployのサービスロールをそれぞれ選択します。

ELBの設定で、プロダクションリスナーポートやテストリスナーポートを選択します。

以上の設定でサービスを作成します。
ELBのリスナーの中身をみてみると、ターゲットグループが正しく設定されています。

また、CodeDeployを開くと作成したアプリケーションの中身も確認できます。

buildspec.ymlの修正

artifactsの記述を修正します。

version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - aws --version
      - echo $AWS_DEFAULT_REGION
      - $(aws ecr get-login --region $AWS_DEFAULT_REGION --no-include-email)
      - REPOSITORY_URI=<<account-id>>.dkr.ecr.ap-northeast-1.amazonaws.com/ecr-simplehttp
      - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      - IMAGE_TAG=${COMMIT_HASH:=latest}
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build -t $REPOSITORY_URI:latest .
      - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
  post_build:
    commands:
      - echo Build completed on `date`
      - docker push $REPOSITORY_URI:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - printf '[{"name":"simplehttp-container","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
      - printf '{"ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json
artifacts:
  files:
    - 'image*.json'
    - 'appspec.yaml'
    - 'taskdef.json'
  secondary-artifacts:
    DefinitionArtifact:
      files:
        - appspec.yaml
        - taskdef.json
    ImageArtifact:
      files:
        - imageDetail.json

appspec.yamlの作成

ルートディレクトリに新しくAppSpecファイルappspec.yamlを作成します。
AppSpecファイルでは、ECSサービスの名前と、新しいタスクセットにトラフィックを送信するために使用されるコンテナ名とポートなどを指定します。

appspec.yaml
version: 0.0

Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: "simplehttp-container"
          ContainerPort: 8000

taskdef.jsonの作成

ルートディレクトリにtaskdef.jsonを作成し、タスク定義のJSONを貼り付けます。

imageの箇所を以下のように修正します。

"image": <IMAGE1_NAME>,

Buildの編集

CodeDeployからBuildの出力アーティファクトにDefinitionArtifactImageArtifactを追加します。

Deployの編集

Deployについても修正します。
入力アーティファクトにDefinitionArtifactImageArtifactを追加します。
その他にはCodeDeployアプリケーション名やデプロイグループの指定、DefinitionArtifactののファイル選択、ImageArtifactの選択などを行います。

パイプラインの実行

パイプラインを実行すると、CodeDeployからトラフィック移行の進行状況を確認することができます。

トラフィックの移行が終わると置き換えタスクセットの方が100 %と表示されます。

参考資料