ECS FargateでBlue/Greenデプロイをする
- Blue/Greenデプロイについて
- アーキテクチャとデプロイフロー
- ALBとターゲットグループを作成する
- ECS Fargateのサービスを作成する
- CodePipelineについて
- CodeBuild
- CodeDeploy
- コンテナのログについて
- Blue/Greenデプロイの確認
- さいごに
- 参考
前回のブログでECS Fargateのローリングアップデートについて書きました。 今回はBlue/Greenデプロイについて異なる部分について書いていこうと思います。
Blue/Greenデプロイについて
■ Step1
デプロイ前の状態で、ALBのプロダクションポート80番、転送先がargetGroupAにトラフィックが流れている状態。
■ Step2
ALBのテストポート8000番、転送先がTargetGroupBにGreenをデプロイしてトラフィックが流れ動作確認できる状態。
■ Step3
Greenのデプロイが完了したらALBのプロダクションポートの転送先をTargetGroupBに向けてBlueにトラフィックが流れないようになる。
アーキテクチャとデプロイフロー
■ アーキテクチャ
■ デプロイフロー
ALBとターゲットグループを作成する
まずは TargetGroupA を作成。
次に TargetGroupB を作成。
次に ALB を作成します。プロダクションポートの80番とテストポートの8000番を追加して、それぞれの転送先は TargetGroupAとBにします。
これでECSのサービスを作成するときに指定するALBとTargetGroupの作成が完了です。
ECS Fargateのサービスを作成する
では、サービスを作成していきます。今回はBlue/Greenデプロイで作成します。
↓↓↓
CodeDeployのサービスロールを選択する必要があるんですが、AWSCodeDeployRoleForECS
の権限が必要になります。
以下の方法でIAMロールを新規作成しました。
作成したIAMロールを選択して次にすすみます。NWの設定をします。
ALBやターゲットグループの設定をしていきます。
↓↓↓
↓↓↓
CodePipelineについて
今回作成したCodePipeline。Sourceの部分は省略してます。
前回書いたローリングアップデートと異なるCodeBuildとCodeDeployについて書きます。
CodeBuild
buildspec.yml
ローリングアップデートからBlue/Greenデプロイにするためにbuildspec.ymlを修正します。
- buildspec.yml
version: 0.2 phases: install: runtime-versions: golang: 1.13 docker: 18 pre_build: commands: - echo Logging in to Amazon ECR... - aws --version - $(aws ecr get-login --region ap-northeast-1 --no-include-email) - REPOSITORY_URI=`aws sts get-caller-identity --query 'Account' --output text`.dkr.ecr.ap-northeast-1.amazonaws.com/go-scraping-api - 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` - echo Pushing the Docker images... - docker push $REPOSITORY_URI:latest - docker push $REPOSITORY_URI:$IMAGE_TAG - printf '{"Version":"1.0","ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json artifacts: files: imageDetail.json
ローリングアップデートと異なる部分は↓。 imagedefinitions.json
--> imageDetail.json
に変更する。このファイル名でないとエラーになります。
また、jsonの中身も変わるので注意。
- printf '{"Version":"1.0","ImageURI":"%s"}' $REPOSITORY_URI:$IMAGE_TAG > imageDetail.json artifacts: files: imageDetail.json
taskdef.jsonについて
次に、Blue/Greenデプロイにするために taskdef.jsonファイルが必要になります。yamlで記述してもOKです。今回はjson形式でやります。
XXXXXXXXXXXX
の部分はアカウント番号が入るためにマスクしました。
"image": "<IMAGE1_NAME>",
この部分でCodeBuildで作成されたコンテナイメージを参照します。 また、↓のtaskdef.jsonでは "mackerel-container-agent" をサイドカーとして追加しています。不要であればここの定義は削除してください。 このサイドカーでコンテナを監視する記事は別途作成します。
- taskdef.json
{ "executionRoleArn": "arn:aws:iam::XXXXXXXXXXXX:role/go-scraping-api", "containerDefinitions": [ { "name": "go-scraping-api", "image": "<IMAGE1_NAME>", "portMappings": [ { "containerPort": 3000, "hostPort": 3000, "protocol": "tcp" } ], "essential": true, "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/go-scraping-api", "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "ecs" } } }, { "name": "mackerel-container-agent", "image": "mackerel/mackerel-container-agent:latest", "essential": false, "logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/go-scraping-api", "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "ecs" } }, "memory": 128, "environment" : [ { "name": "MACKEREL_CONTAINER_PLATFORM", "value": "fargate" }, { "name": "MACKEREL_ROLES", "value": "dev:ecs" } ], "secrets": [ { "name": "MACKEREL_APIKEY", "valueFrom": "mackerel_agent_apikey" } ] } ], "requiresCompatibilities": [ "FARGATE" ], "networkMode": "awsvpc", "cpu": "256", "memory": "512", "family": "go-scraping-api" }
タスク実行のロールを↓で付与しています。
"executionRoleArn": "arn:aws:iam::XXXXXXXXXXXX:role/go-scraping-api",
SSMパラメータを参照する必要があるので、↓のポリシーを付与しています。
機密情報の取り扱いについて ( SSM連携 )
mackerel-container-agentをサイドカーとして動かしています。ここについては次のブログにて紹介します。
↓↓↓
CodeDeploy
次にCodeDeployの設定をしていきます。ECSのサービスを作ったときに生成されたCodeDeployのアプリケーションとデプロイグループを利用します。 デプロイプロバイダは ECS (ブルー/グリーン) を選択。 appspec.yaml のファイル名は固定ですが、taskdef.json のファイル名は任意に設定できるのでEnvで分けるときはenvごとに名前をつけることができます。 IAMロールのarnが入るため、envをまたぐときは複数ファイル用意してCodeDeployのファイル名で合わせればいいと思います。
↓↓↓
コンテナのログについて
CloudwatchLogsに今回はログを吐き出すようにしています。
- taskdef.jsonから一部抜粋
"logConfiguration": { "logDriver": "awslogs", "options": { "awslogs-group": "/ecs/go-scraping-api", "awslogs-region": "ap-northeast-1", "awslogs-stream-prefix": "ecs" } }
Blue/Greenデプロイの確認
検証でここまで設定してBlue/Greenデプロイを実行したので、80/8000番ポートのターゲットグループがそれぞれTargetGroupAになっています。 この状態からBlue/Greenデプロイを実施して動きを確認しようと思います。
ALBのTargetGroupの動き
ALBの設定されているTargetGroupは 80番 / 8000番 ポートに TargetGroupAがセットされています。
まず、テストポートである8000番ポートにGreenのTargetGroupBがセットされました。
次に、8000番ポートのTargetGroupBが正常であれば、プロダクションポートのTargetGroupAもGreenのTargetGroupBに変わります。 プロダクションポートとテストポートがそれぞれ、GreenのTargetGroupBに変わることが確認できました。
Fargateのタスクの動き
Greenのタスクの状態からBlueが追加されました。
BlueとGreenの状態からBlueが切り離されました。
動作確認
外部からプロダクションポートの80番とテストポートの8000番にヘルスチェックのAPIを叩いて確認しました。 BGデプロイ中にテストポートにトラフィックが流れるGreenに対して実行してもOKでした。
curl http://go-scraping-api-XXXXXXXXX.ap-northeast-1.elb.amazonaws.com/ping pong
curl http://go-scraping-api-XXXXXXXXX.ap-northeast-1.elb.amazonaws.com:8000/ping pong
さいごに
今回は、前回のローリングアップデートの続きとして、Goコンテナを使ってBlue/Greenデプロイについて検証してまとめました。 サイドカーを使ってmackerelで監視する方法については省略していますが、ssm連携と合わせて書こうと思います。 今回の環境構築は全体像を掴みたいところもあったのでwebコンソールでポチポチ作っていきましたが、CLIやTerraformで環境を作る ところも取り組んでいければと思います。 また、先日の re:Invent で EKSもかなりアップデートがあったので、そちらについても検証をすすめていきたいと思います。
参考
https://d1.awsstatic.com/webinars/jp/pdf/services/20190731_AWS-BlackBelt_AmazonECS_DeepDive_Rev.pdf