Amazon ECS の Blue/Green デプロイメントの動作は何が起こっているか解説したい

# はじめに

Amazon ECS は、コンテナを動かしうまく管理するためのコンテナオーケストレーションサービスです。新たなバージョンのコンテナをデプロイするときに、いろいろなデプロイの方法が取れますが、ECS 側で用意されているデプロイ戦略が3種類あります

- Rolling Update : Service の中で稼働しているタスクを少しずつ順繰りアップデートする方式
- Blue/Green Deployment : 新たな環境である Green 環境を用意して、LB レイヤーで切り替える方式
- External Deployment : 外部のサードパーティの何かでデプロイをコントロールする方式

こちらの Document に記載があります。 : https://docs.aws.amazon.com/AmazonECS/latest/userguide/deployment-types.html



Blue/Green Deployment の中でも、更に詳細な方式があります。CodeDeploy 側で用意されている5つのデプロイ方式の中で自分たちに合うものをチョイスできます。

| デプロイ設定                                        | 説明                                                         |
| :-------------------------------------------------- | :----------------------------------------------------------- |
| `CodeDeployDefault.ECSLinear10PercentEvery1Minutes` | すべてのトラフィックを移行するまで、1 分ごとにトラフィックの 10% を移行します。 |
| `CodeDeployDefault.ECSLinear10PercentEvery3Minutes` | すべてのトラフィックを移行するまで、3 分ごとにトラフィックの 10% を移行します。 |
| `CodeDeployDefault.ECSCanary10percent5Minutes`      | 最初の増分でトラフィックの 10% を移行します。残りの 90% は 5 分後にデプロイします。 |
| `CodeDeployDefault.ECSCanary10percent15Minutes`     | 最初の増分でトラフィックの 10% を移行します。残りの 90 パーセントは 15 分後にデプロイされます。 |
| `CodeDeployDefault.ECSAllAtOnce`                    | すべてのトラフィックを同時に更新済み Amazon ECS コンテナに移行します。 |



今回は、この Blue/Green の中で `CodeDeployDefault.ECSAllAtOnce` と `CodeDeployDefault.ECSLinear10PercentEvery1Minutes` の動きを紹介していきます。



# CodeDeployDefault.ECSAllAtOnce の動作について

まず、デプロイを行っていない、通常の状態の構成を見ていきます。細かい部分は正確ではない部分もありますので、詳細はぜひ触ってみてください。ALB と書いている Box は 正確には NLB も利用できますし、リスナーのポートは HTTPS も利用可能なので、細かい部分で違いがあるところもあります。

![image-20220321150230341.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/99a07cfc-f71b-3a86-7f8d-e21523cc6f14.png)



- ALB のリスナーについて
  - 1個の ALB に、2つのリスナーがあります。
  - 本番 Blue環境用のトラフィックが流れる Production リスナーと、バージョンアップ後の Green 環境用の Test リスナーです。
- Target Group について
  - Blue と Green の環境をコントロールするために、Target Group が2つ用意されています
  - 通常の構成では、Target Group 1 しか使いません
  - Target Group 1 が、ECS で稼働している Task(コンテナ)に紐づいています



ここで、新たなバージョンをデプロイを開始し始めると、以下の構成になります。ECS 環境上に、新たなバージョンの Task が立ち上がり、Target Group 2 に紐づけられます。紐づけられただけだと、まだ本番環境でのトラフィックは流れないため、エンドユーザーは引き続き version 1 の Blue 環境を触っています。

![image-20220321150713730.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/9743b744-0ec5-5901-7985-c9f0cd864845.png)





次に、Green 環境が立ち上がったので、ALB の Test 用のリスナーが Green 環境に紐づけられます。

<u>デフォルトの状態だとコンテナの中のアプリケーションが正常に稼働しているかは CodeDeploy は気にしていません。</u>アプリケーションが異常状態であっても次のプロセスに進みます。ALB の Health Check の機能自体はありますが、ALB 側の Health Check は CodeDeploy は気にしていないように見えています。正しく稼働しているか自動的に確認するために、CodeDeploy のライフサイクルフックで `AfterAllowTestTraffic` のフェーズで Lambda を動かす機能が使えますが、今回は取り上げません。気になる場合は[このあたり](https://docs.aws.amazon.com/codedeploy/latest/userguide/deployment-steps-ecs.html#deployment-steps-what-happens)を確認してみましょう。

![image-20220321151154806.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/3d28d887-663c-c64f-796f-a2ef9154d343.png)



次に、本番用の Production 用のリスナーが Green 環境に紐づきます。このタイミングで、初めて本場利用のユーザーが新しいバージョンを利用し始めます。`CodeDeployDefault.ECSAllAtOnce` の方式の場合は、全員のユーザーがこのタイミングで Green 環境に切り替わります。徐々に切り替えていきたい場合は、これ以外の方式を選択すると良いでしょう。

Blue 環境を削除するまで、CodeDeploy の画面上でロールバックボタンを押せます。1ボタン押すだけで Blue 環境に切り戻しもできるので、便利に利用できそうです。

![image-20220321152044469.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/27f17097-5e78-781e-fe33-2d7214bad968.png)



その後、Blue 環境が不要になった Blue 環境を削除します。Blue 環境の削除は主に以下の2つのトリガーがあります

- 手動で削除
- 保存期間を超えたら削除。デフォルトは1時間まで平行稼働してくれる

![image-20220321152730654.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/1e689ecc-b843-1523-b7ad-c3e364307e5d.png)



# CodeDeployDefault.ECSLinear10PercentEvery1Minutes の動作について

`CodeDeployDefault.ECSAllAtOnce の動作について` との差分のみ記載します。

ALB の Production リスナーを、Green 環境に切り替える部分についてです。

![image-20220321153126216.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/3b34a37c-2cab-e8f2-0868-1a0023acfa2b.png)



ALB の重みづけの機能を活用して、本番環境にアクセスしにきたユーザーを徐々に Green 環境に寄せていきます。これにより、影響のでるユーザーを出来るだけ少ない状態にしておき、何か問題があればすぐに切り戻しを行うことが出来ます。`CodeDeployDefault.ECSLinear10PercentEvery1Minutes` の名前にもある通り、1分おきに、10% ずつ Green 環境へのアクセスが増えていく形ですね。

初めは、Blue 環境へのアクセスが 100% で、Green 環境へのアクセスが 0% となっています。1分ごとにこの重みづけが 10% ずつ偏りが変わっていく形ですね。最終的には、Green 環境に完全に切り替わります。

- 100% : 0%
- 90% : 10%
- 80% : 20%
- 70% : 30%

more....





# Blue/Green Deployment : 環境作成

ここまで概念的な話でした。これからは、実際に環境を作成してみる手順を紹介していきます。手順に興味がない場合は、この部分は無視してもらって大丈夫です。



## ALB 作成

まず、ECS Service を作成する前に、紐づける ALB を作成しておく必要があります。

Create Load Balancer を押します。

![image-20220321080700552.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/3b7620da-56de-fcd3-8c01-448d0eff6cdd.png)



ALB を選択します。

![image-20220321080730130.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/ae1c3bb8-b8cb-9d90-ba9f-1d2280a483d5.png)



名前を指定

![image-20220321080822035.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/379f2464-4bc2-17be-3244-39e7a21b60a3.png)



Listener は適当に指定しないといけないので、Dummy のものを指定

![image-20220321080919251.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/452a0643-2973-b356-3443-3b193c25f9f2.png)



Create

![image-20220321080933331.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/5f72b3a3-d5f6-3db2-3ce9-0f377dbcf610.png)



ALB が作成できました。Dummy で作成した Listener は削除しておきます。

![image-20220321081010361.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/428f6a35-faf1-ca77-8e45-b16bc4d6cff2.png)



## ECS Service 作成

次に、ECS Service を作成していきます。Blue/Green Deployment の方式は、2022年3月現在、旧コンソールでないと設定できませんでした。

Service Create 

![image-20220321081050189.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/3c16ea23-3d22-3eb1-8de2-77d9a861e6b8.png)



- Task Definition
- Service name

![image-20220321092358650.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/a56b8378-3147-d144-842b-fde8783040b0.png)



<u>Deployment Type を指定可能</u>

- Blue/green deployment を選択

![image-20220321081321062.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/a6a24b73-a7d6-0d88-a732-ec6ac0694ffb.png)



VPC や Subnet を指定

![image-20220321081415124.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/3f79bb23-2b27-d9d5-bb32-da0d63310133.png)



連携する ALB を指定

![image-20220321081452581.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/a23937aa-dca0-6168-9830-21e4aed6b3e6.png)



Load Balancer に対して、2つのリスナーを用意する

- Blue 環境用の Production listener
- Green 環境用の Test listener

![image-20220321081643682.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/9063c1da-1f01-3f37-5d2d-bfd24d813754.png)





2 つの Target Group の指定。デフォルトのままにしておく。

![image-20220321081804799.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/bd65b811-2588-b9d5-87bf-c5b33903be6c.png)



Service の作成

![image-20220321081847206.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/ef00327c-3a29-88be-5724-7711d25b6e79.png)



Service が作成されました

![image-20220321082157288.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/f829f1dc-0c3e-a16e-de03-d3b23871a5a2.png)



## 自動設定 : ALB

ALB には 2 つの Listener が自動設定されています

![image-20220321082259938.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/e637fcd4-9dd5-1de3-48dd-4b0cc0c50060.png)



ALB にアクセスすることも出来ます

![image-20220321092424396.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/1a5a8abe-21a7-b3c3-4e74-ea032bfbf09c.png)



## 自動設定 : Target Group

Target Group1 には、2つの Task が紐づいています

![image-20220321082418446.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/67dca01b-9230-86d2-5941-7863cced8a11.png)



Target Group 2 には、なにも Task は居ません

![image-20220321082456152.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/ecd7fb16-eefd-7ffd-e50f-9a545fed5f2c.png)



## 自動設定 : CodeDeploy

CodeDeploy の Application の定義が1個作成されています

![image-20220321083718914.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/08ead710-b196-a5c5-fc49-5619cbc474b1.png)



Application の中に、Deployment Group が作成されています

![image-20220321083815184.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/2919df91-aeca-d866-2fe4-80075bf11bcf.png)



詳細な中身を確認するために、Edit を押します

![image-20220321083850359.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/939864ee-722e-dbc5-7813-eef9c0e46f6b.png)



2つの設定値を確認できます。

- Traffic rerouting : Blue 環境から Green 環境にトラフィックを切り替えるときの猶予時間についての設定。デフォルトの設定は、Reroute traffic immediately なので、すぐに切り替える設定になっている。
- Original revision termination : Blue 環境から Green 環境に切り替えたあとに、Blue 環境をどれくらいの時間残しておくかの指定。この指定した時間は手動でロールバックボタンを押すことが出来る。

![image-20220321083950323.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/5d2cd103-3763-ff3c-e773-3e6d165c2342.png)



なお、自動ロールバックについても設定があり、デプロイメントに失敗したときは自動的にロールバックされる

![image-20220321084211021.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/a535b9e1-28ef-d0b0-4fbf-7f5afefd6f0a.png)



# 動作確認 : Blue/Green を試す

対象の Service を選択して、Update を押す

![image-20220321084931004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/c4aaf3f4-cadc-9fa6-d1c8-2f2298985ef1.png)



Task Definition を Revision 9 から 10 に変更します

![image-20220321092806532.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/1fdaa756-3696-e537-3ba1-848209e6f15b.png)



CodeDeploy に対する動作を指定できます。このままデフォルトでいきます。Deployment configuration でデプロイ方式を選択できるので、そのときの状況に合わせて最適なものを選びましょう。

![image-20220321085148379.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/c7544dbb-1b3e-a9b8-4f8f-173217641f97.png)



Next Step

![image-20220321085229594.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/1716f7f1-21f0-f7c5-b282-2770b19ec08e.png)



Next Step

![image-20220321085250033.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/0b41d8b5-6897-012a-6485-fd34faddcd57.png)



Update Service

![image-20220321085310128.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/5d1d593f-d6f4-405d-ce12-3f2390d83d09.png)



Service のアップデートを開始したので、Blue/Green Deployment が始まりました。

![image-20220321085324851.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/37ec91ce-efd0-9dec-54ef-b5afe6cae313.png)



ECS Task が 2 個から 4 個に増えている

![image-20220321085542484.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/573afec7-155f-3f90-1303-d8cfe7b06864.png)



CodeDeploy では、Deployment が進んでいることがわかる

![image-20220321085400815.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/fd2bffc6-6041-7016-ee18-f1c27d8e375a.png)



Green 用の Target Group に新たな Task が登録される

![image-20220321085447396.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/d37d9359-f61b-09db-1736-4f10889c35f5.png)



CodeDeploy 上では、Reroute が切り替わっている。切り替わってから1時間は Blue 環境を残す設定にしているので、Blue 環境が残っている。Terminate original task set を手動で押すことで、Blue 環境の手動削除が可能。

![image-20220321085646435.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/96e7286c-9c13-4eda-db4e-446a004ae632.png)



ALB の HTTP 80 Listener の宛先 Target Group が切り替わっている

![image-20220321093449522.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/65cc7ca8-d2b2-0bef-fef6-9167d37f9d5d.png)



CodeDeploy 上では、何にどれくらいの時間が掛かっていたかを確認可能

![image-20220321093645451.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/41a8ce95-03fb-d289-cfba-fad17f6e62cd.png)



# わかったこと

- CodeDeploy の Appllication 配下にある Deployment Group の設定 `Original revision termination` は、Blue から Green に切り替え終わった後に、Blue の環境をどれだけ保持しておくかの設定となっている。
- Blue の環境を保持している期間は、新たなデプロイが出来ない。新たにデプロイしたい場合は、手動で Terminate ボタンを押す必要がある
![image-20220321095818846.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/fdba3884-a009-aad4-5f68-9991b5ef99c5.png)

- 重みづけをした場合は、Target Group の重みづけが入る
  - CodeDeployDefault.ECSLinear10PercentEvery1Minutes
  - 90 : 10 → 80 : 20 → 70 : 30 と徐々に切り替わっていく
![image-20220321101233371.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/f0478bc5-af92-c6af-1ad4-2ec56f25d3e9.png)

- Blue/Green Deployment の場合、ALB の Health Check にある Interval や、Healthy threshold など設定値は、影響しない。Interval をいくら伸ばしても、Healthy threshold の回数を増やしても、Deployment の時間には影響しなかった。CodeDeploy は、ALB の Health Check は無視しているのだと思われる。
- CodeDeploy による Blue/Green デプロイは、Green 環境が正常に稼働しているかは気にしないで切り替えを行う。これを検証して、異常な場合は自動ロールバックするために、CodeDeploy のライフサイクルフックを利用可能
  - `AfterAllowTestTraffic` のタイミングを利用することで、Lambda 上で Green 環境の正常性を確認できる
  - https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/deployment-steps-ecs.html#deployment-steps-what-happens
  - https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html



# 参考URL

https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/deployment-steps-ecs.html#deployment-steps-what-happens

https://docs.aws.amazon.com/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html#appspec-hooks-ecs