AWS ECS/FargateのデプロイタイプをBlue/Green(CodeDeploy)にしたときにデプロイ実行で叩くべきAPI
久しぶりにこちらに書きます。(関係ないですけど、QiitaとBlogの使い分けって難しいですよね。
主に自分のスキルアップを目的としてサンプルアプリ的に稼働させている https://jaaxman.shirakiya.com/ というWebサイトのFargate化を進めていたときにデプロイで少しハマったことを書きます。
したかったこと
Web appの実行環境をEC2からFargateに載せ替えるにあたり、デプロイの自動化も進めていました。
Web appのデプロイの手順は上の図のような形で作戦を練っていました。
- productionブランチにpush
- テスト通過後にdocker image作成・ECRにpush
- タスク定義を更新(2のimageを使う)
- サービスを更新(3のタスク定義を使う)し、既存タスクを最新のサービスを使ったタスクに入れ替える
1はGitの操作なので除きますが、2〜4の操作はCI上(今回はCircleCIを使っています)で行う操作なので、AWSのAPIを叩く必要があります。
2と3は普通にECRにpushし、タスク定義をupdateするためのAPIを叩くことで実現できます。公式にもドキュメントがあるのでこれらが参考になります。
イメージのプッシュ - Amazon ECR
RegisterTaskDefinition - Amazon EC2 Container Service
サービスのデプロイはデプロイタイプによって利用するAPIが異なる
今回の話題の中心は4のデプロイについてです。
Amazon ECSではサービスのデプロイ方法(=デプロイタイプ)は2種類の方法が利用できます。
- ローリング更新
- サービスを更新すると最新版のサービスを使ったタスクを自動で入れ替える
- Amazon CodeDeployを利用したBlue/Greenデプロイ
実はこの2種類のデプロイタイプのそれぞれで叩くべきAPIが異なります。
- ローリング更新 ⇒ ECSのUpdateService
- Blue/Greenデプロイによる更新 => CodeDeployのCreateDeployment
ズバリここでハマってしまいました。
勉強がてら進めていたためローリング更新を試してからCodeDeployのBlue/Greenを試すという流れで作業をしていたのですが、CodeDeployを利用した場合はサービスを更新したいのに サービスを更新するAPIを叩く必要は無い のです。
もう少し具体的に見ていきましょう。
デプロイタイプ「ローリング更新」の場合
デプロイタイプを ローリング更新 にしている場合はAWS CLIを用いると以下のような操作でデプロイを行うことができます。(最小限のオプションです)
$ aws ecs update-service \ --cluster test-cluster \ --service test-rolling \ --task-definition test:2
これを叩いた後にサービスのイベントタブを開くと、以下のようにタスクが ea8369c11af3441e9128970e8f4562d6
から 4cd48c97bd3c4f55bc40b6e4a576d892
に入れ替わっていることが見て取れます。
つまり「サービスをデプロイするにはサービスを更新(=update-service
)すればよい」のです。まぁなんかイメージ通りですね。
デプロイタイプ「Blue/Greenデプロイによる更新」の場合
さて、デプロイタイプを Blue/Greenデプロイによる更新 にしている場合に上記のように update-service
を叩くとどうなるでしょうか。
$ aws ecs update-service \ --cluster test-cluster \ --service test-codedeploy \ --task-definition test:2 An error occurred (InvalidParameterException) when calling the UpdateService operation: Unable to update task definition on services with a CODE_DEPLOY deployment controller. Please use Code Deploy to trigger a new deployment.
結果、InvalidParameterExceptionで怒られてしまいました。デプロイするならCodeDeployのdeploymentをトリガーしろと言っていますね。
このようにCodeDeployを使っていると、UpdateServiceを叩いたところでデプロイすることはできません。デプロイする場合は以下のようにCodeDeployの create-deployment
を叩く必要があります。(一部マスクしてます)
$ aws deploy create-deployment \ --application-name AppECS-test-cluster-test-codedeploy \ --deployment-group-name DgpECS-test-cluster-test-codedeploy \ --revision '{"revisionType": "AppSpecContent", "appSpecContent": {"content": "{\"version\": 1, \"Resources\": [{\"TargetService\": {\"Type\": \"AWS::ECS::Service\", \"Properties\": {\"TaskDefinition\": \"<タスク定義ARN>\", \"LoadBalancerInfo\": {\"ContainerName\": \"nginx\", \"ContainerPort\": 80}}}}]}", "sha256": "192a44b8191ec68bb5bd4861d4960065bdb148d98e9ef74a5b4d9b6930f179b0"}}' { "deploymentId": "d-XXXXXXXXX" }
これでCodeDeployによるデプロイプロセスが開始されました。
まとめ
ECSのデプロイはデプロイタイプによって叩くべきAPIが異なります。
- ローリング更新
- ⇒ Amazon ECS の UpdateService(=
aws ecs update-service
)
- ⇒ Amazon ECS の UpdateService(=
- Amazon CodeDeployを利用したBlue/Greenデプロイ
- ⇒ AWS CodeDeploy の CreateDeployment(=
aws deploy create-deployment
)
- ⇒ AWS CodeDeploy の CreateDeployment(=
以上、何かのご参考になれば幸いです。