Be an Engineer.

社会人からWEBエンジニアになった人間の備忘録的勉強記録

AWS ECS/FargateのデプロイタイプをBlue/Green(CodeDeploy)にしたときにデプロイ実行で叩くべきAPI

久しぶりにこちらに書きます。(関係ないですけど、QiitaとBlogの使い分けって難しいですよね。

主に自分のスキルアップを目的としてサンプルアプリ的に稼働させている https://jaaxman.shirakiya.com/ というWebサイトのFargate化を進めていたときにデプロイで少しハマったことを書きます。

したかったこと

Web appの実行環境をEC2からFargateに載せ替えるにあたり、デプロイの自動化も進めていました。

f:id:shirakiya:20190210221322p:plain:w600
CircleCI+ECSのデプロイフロー

Web appのデプロイの手順は上の図のような形で作戦を練っていました。

  1. productionブランチにpush
  2. テスト通過後にdocker image作成・ECRにpush
  3. タスク定義を更新(2のimageを使う)
  4. サービスを更新(3のタスク定義を使う)し、既存タスクを最新のサービスを使ったタスクに入れ替える

1はGitの操作なので除きますが、2〜4の操作はCI上(今回はCircleCIを使っています)で行う操作なので、AWSAPIを叩く必要があります。
2と3は普通にECRにpushし、タスク定義をupdateするためのAPIを叩くことで実現できます。公式にもドキュメントがあるのでこれらが参考になります。

イメージのプッシュ - Amazon ECR
RegisterTaskDefinition - Amazon EC2 Container Service

サービスのデプロイはデプロイタイプによって利用するAPIが異なる

今回の話題の中心は4のデプロイについてです。
Amazon ECSではサービスのデプロイ方法(=デプロイタイプ)は2種類の方法が利用できます。

  1. ローリング更新
    • サービスを更新すると最新版のサービスを使ったタスクを自動で入れ替える
  2. Amazon CodeDeployを利用したBlue/Greenデプロイ
    • 最新版サービスを使ったBlue環境を稼働し、その後に本番用トラフィックを流す
    • 本番用トラフィックを流す前に検証したりすることが可能

実はこの2種類のデプロイタイプのそれぞれで叩くべきAPIが異なります。

  1. ローリング更新 ⇒ ECSのUpdateService
  2. 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 に入れ替わっていることが見て取れます。

f:id:shirakiya:20190210221445p:plain

つまり「サービスをデプロイするにはサービスを更新(=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 CodeDeployを利用したBlue/Greenデプロイ
    • AWS CodeDeploy の CreateDeployment(=aws deploy create-deployment

以上、何かのご参考になれば幸いです。