☕️

ecspresso advent calendar 2020 day 17 - CodeDeployとの連携

2020/12/17に公開

Amazon ECS のデプロイツールである ecspresso の利用法をまとめていく ecspresso Advent calendar 17日目です。

ECS のデプロイ方法

ECS のデプロイ方法は現在のところ3種類あります。

参考: Amazon ECS デプロイタイプ

  • ECS によるローリングデプロイ
  • AWS CodeDeploy による Blue/Greenデプロイ
  • 外部コントローラーによるデプロイ

ここでは、ecspresso がサポートしているデプロイ方法であるローリングデプロイと CodeDeploy による Blue/Green デプロイについて説明します。

ローリングデプロイ

ローリングデプロイは ECS 自身がデプロイを行います。ECS サービスに対して新しいタスク定義を設定すると、新しいタスク定義を使用したタスクを新しく立ち上げ、古いタスクを停止することでデプロイが行われます。

この方法では、デプロイ中は一時的に新旧のタスクが混在する時間があります。ロードバランサーに ECS サービスを登録している場合は、デプロイ中は新旧どちらのタスクにもリクエストが割り振られる可能性があります。

CodeDeploy による Blue/Green デプロイ

ローリングデプロイでは新旧両方のタスクが混在する時間帯があり、ロールバックを行いたい場合も同様に古いタスク定義を使用したタスクに入れ替わるまで時間が掛かります。このような挙動が問題になる場合の解決法として、Blue/Green デプロイがあります。

Blue/Green デプロイは以下のようにタスクを制御することで、新旧のタスク群が混在して処理する時間帯を最小限にし、またロールバックも即座に行える手法です。

  1. 新しいタスク定義を使用したタスク群を起動
  2. ロードバランサーの設定を切り替えることで、リクエストを新しいタスク群へルーティング
  3. 問題がなければ古いタスク群を停止
  4. 問題があった場合はロードバランサーの設定を戻し、リクエストを古いタスク群へルーティング

ECS は CodeDeploy と連携することで、Blue/Green デプロイをサポートしています。

制約として、ロードバランサー(ALB, NLB)が必須になります。ロードバランサー(ターゲットグループ)と関連付いていない ECS サービスは、Blue/Green デプロイを実行できません。

ecspresso での CodeDeploy サポート

ecspresso では、サービス定義の deploymentController.type 属性によって、ecspresso deploy 時の挙動が変わります。

値が ECS の場合(もしくは未指定の場合) はローリングデプロイを、CODE_DEPLOY の場合は CodeDeploy と連携したデプロイを行います。

ecspresso は ECS の管理に特化しているため、CodeDeploy のリソースについては作成や管理を行いません。CodeDeploy のアプリケーションとデプロイグループは別途用意する必要があります。

CodeDeploy によるデプロイの実例

ここでは 3日目 既存サービスの取り込み でコード化した ECS サービスに対して、CodeDeploy での Blue/Green デプロイを行う例を説明します。

デプロイ方法は ECS サービスの作成時にしか設定できないため、ECS サービスが存在している場合は一度サービスを削除する必要があります。サービスの削除方法は 16日目 delete を参照してください。

サービスの作成

ecs-service-def.json を編集し、deploymentController を追加します。

--- a/ecspresso-demo/ecs-service-def.json
+++ b/ecspresso-demo/ecs-service-def.json
@@ -1,13 +1,12 @@
 {
   "createdBy": "arn:aws:iam::314472643515:role/KayacInfraTeam",
   "deploymentConfiguration": {
-    "deploymentCircuitBreaker": {
-      "enable": false,
-      "rollback": false
-    },
     "maximumPercent": 200,
     "minimumHealthyPercent": 100
   },
+  "deploymentController": {
+    "type": "CODE_DEPLOY"
+  },
   "desiredCount": 1,
   "enableECSManagedTags": false,
   "healthCheckGracePeriodSeconds": 0,

この時にもし deploymentConfiguration.deploymentCircuitBreaker 要素が定義されていた場合は、要素ごと削除してください。deploymentCircuitBreaker 機能は ECS のローリングデプロイでのみ使用できます。

その後、ecspresso create を使用してサービスを作成します。

$ ecspresso --config config.yaml create

ターゲットグループの作成

Blue/Green デプロイでは、ELB のターゲットグループを2つ用意する必要があります。

それぞれのターゲットグループに新旧のタスク群を所属させ、ELBのリスナールールの変更によってトラフィックを切り替えるためです。

作成したサービスにはターゲットグループがひとつ定義されているので、それと同じ設定のターゲットグループをあらたに作成してください。

CodeDeploy の設定

AWS コンソールの CodeDeploy から、アプリケーションを作成します。コンピューティングプラットフォームは Amazon ECS を選択します。

次に、そのアプリケーション内にデプロイグループを作成します。

  • ECSクラスター、ECSサービスは ecspresso の設定ファイルに記述してあるもの(いま作成したサービスのもの)を指定します
  • Load balancer には、ターゲットグループを2つ(元からあったものとあらたに作成したもの)を指定します
  • デプロイ設定はここでは特に変更せず、デフォルトの ECSAllAtOnce のままにします
    • 変更しても問題ありません

これで、CodeDeploy の準備は完了です。

ecspresso でデプロイを行う

ecspresso でデプロイを行います。

CodeDeploy でデプロイを行う設定になっているサービスに対して ecspresso deploy を実行すると、以下の処理が行われます。

  • 新しいタスク定義の登録
  • サービス定義の更新 (更新する項目があれば)
  • CodeDeploy AppSpec を作成して CodeDeploy でデプロイを開始
    • 使用する CodeDeploy アプリケーションとデプロイグループは、自分自身のサービスをデプロイ可能なものが自動的に選択されます
  • CodeDeploy の AWS コンソールへの URL を表示
    • ecspresso が端末で動作していて、かつ open コマンドが使用可能な場合は URL を開く
$ ecspresso --config config.yaml deploy
2020/12/16 23:35:04 nginx-service/ecspresso-demo Starting deploy
Service: nginx-service
Cluster: ecspresso-demo
TaskDefinition: first-run-task-definition:10
TaskSets:
   PRIMARY first-run-task-definition:10 desired:1 pending:0 running:1
Events:
2020/12/16 23:35:05 nginx-service/ecspresso-demo Registering a new task definition...
2020/12/16 23:35:05 nginx-service/ecspresso-demo Task definition is registered first-run-task-definition:12
2020/12/16 23:35:05 nginx-service/ecspresso-demo Updating service attributes...
2020/12/16 23:35:08 nginx-service/ecspresso-demo desired count: 1
2020/12/16 23:35:08 nginx-service/ecspresso-demo updating desired count to 1
2020/12/16 23:35:09 nginx-service/ecspresso-demo Deployment d-34OS110T7 is created on CodeDeploy:
2020/12/16 23:35:09 nginx-service/ecspresso-demo https://ap-northeast-1.console.aws.amazon.com/codesuite/codedeploy/deployments/d-MAX8DF0T7?region=ap-northeast-1

表示される URL を開くと、CodeDeploy でデプロイが開始しています。

この状態で ecspresso status を実行すると、新旧両方のタスクが起動していることが分かります。

$ ecspresso --config config.yaml status
Service: nginx-service
Cluster: ecspresso-demo
TaskDefinition: first-run-task-definition:12
TaskSets:
   PRIMARY first-run-task-definition:12 desired:1 pending:0 running:1
    ACTIVE first-run-task-definition:11 desired:1 pending:0 running:1

その後のデプロイの進行、ロールバックなどは CodeDeploy 上で行います。

デプロイがすべて完了すると、ecspresso status では新しいタスクのみが動いているのが分かります。

$ ecspresso --config config.yaml status
Service: nginx-service
Cluster: ecspresso-demo
TaskDefinition: first-run-task-definition:12
TaskSets:
   PRIMARY first-run-task-definition:12 desired:1 pending:0 running:1

CodeDeploy 特有の事項

Blue/Green デプロイの制約

ローリングデプロイと比較して、CodeDeploy による Blue/Green デプロイには制約がいくつかあります。ドキュメントを参照してください。
https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/userguide/deployment-type-bluegreen.html#deployment-type-bluegreen-considerations

deploy のオプション --suspend-autoscaling

Blue/Green デプロイを設定したサービスは、オートスケーリングが有効な状態ではデプロイが行えません。

ecspresso deploy --suspend-autoscaling を指定することで、デプロイ前に Application Autoscaling を一時的に停止できます。

ただし、v1.2.1 の時点では ecspresso ではオートスケーリングの再開(resume)を行えません。

deploy のオプション --rollback-events

デプロイが失敗した場合に、自動的にロールバックを行うイベント名を登録できます。
https://docs.aws.amazon.com/ja_jp/codedeploy/latest/APIReference/API_AutoRollbackConfiguration.html

DEPLOYMENT_FAILURE DEPLOYMENT_STOP_ON_ALARM DEPLOYMENT_STOP_ON_REQUEST の値を、複数指定する場合は , で連結して指定します。

デプロイ完了を待つ

CodeDeploy でのデプロイの場合、ecspresso deploy は CodeDeploy でのデプロイが開始すると、完了を待たずに終了します。

別途 ecspresso wait コマンドを使用することで、現在進行中の CodeDeploy によるデプロイが完了するまで待つことができます。

CodeDeploy を利用したサービスのロールバック

サービスが CodeDeploy を利用している場合、ecspresso rollback によるロールバックは行えません。ロールバックは CodeDeploy の機能を使用して行ってください。

フックの追加

CodeDeployでは、デプロイ操作の各フェーズで Lambda 関数を呼び出すことができます。
https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/tutorial-ecs-with-hooks-create-hooks.html

ecspresso でフックの設定を行うためには、設定ファイルに appspec.Hooks 要素を定義してください。

cluster: default
service: test
service_definition: ecs-service-def.json
task_definition: ecs-task-def.json
appspec:
  Hooks:
    - BeforeInstall: "LambdaFunctionToValidateBeforeInstall"
    - AfterInstall: "LambdaFunctionToValidateAfterTraffic"
    - AfterAllowTestTraffic: "LambdaFunctionToValidateAfterTestTrafficStarts"
    - BeforeAllowTraffic: "LambdaFunctionToValidateBeforeAllowingProductionTraffic"
    - AfterAllowTraffic: "LambdaFunctionToValidateAfterAllowingProductionTraffic"

18日目は、CodeDeploy AppSpec ファイルの生成機能について説明します。

https://zenn.dev/fujiwara/articles/ecspresso-20201218

Discussion