AWS FargateでBlue/Greenデプロイを行う

## 概要

CodeDeployを利用したFargateでのBlue/Greenデプロイメントをコンソールから実装します。

基本的な内容は下記の記事を参考にしています。記事には書かれていないECRリポジトリのイメージの更新も含めて記載し、デプロイの流れを説明しています。
[AWS CodeDeploy による AWS Fargate と Amazon ECS でのBlue/Greenデプロイメントの実装 | Amazon Web Services](https://aws.amazon.com/jp/blogs/news/use-aws-codedeploy-to-implement-blue-green-deployments-for-aws-fargate-and-amazon-ecs/)

## 全体の流れ

FargateでBlue/Greenデプロイメントを実装するための前提条件と、全体の流れを把握します。

### 前提条件
- ECRにリポジトリが作成されていること
- ECRにリポジトリに`latest`タグがついたDockerメージがpushされていること
- ECSクラスターが作成されていること

ECRにリポジトリを作成しDockerイメージをpushする方法については、下記の記事で手順を書いていますので、よろしければご覧ください。
[LaravelアプリケーションをAWS上のDockerで動かす](https://qiita.com/kobayashi-m42/items/95ba3f611b3def27241e#ecr%E3%81%ABdocker%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%82%92push%E3%81%99%E3%82%8B)

### Blue/Greenデプロイに必要なリソースを作成

- IAMロールの作成
- ALBの作成
- タスクの定義の作成
- ECSサービスの作成

詳細は後述しますが、ECSサービスの作成の中で、`Deployment type`に`Blue/Green deployment`を選択することで、CodeDeployアプリケーションとデプロイメントグループが自動的に作成されます。CodeDeployを手動で作る必要がなく、とても便利です。

### Blue/Greenデプロイをする

- ECRのリポジトリに新しいDockerイメージをpushする
- タスク定義のリビジョンを作成
- 新しいリビジョンのタスクの定義を使用し、ECSサービスを更新する

ECSサービスを更新した時点で、CodeDeployによるBlue/Greenデプロイが実行されます。

これより先は、具体的な手順を解説していきます。

## Blue/Greenデプロイに必要なリソースを作成

### IAMロールの作成

ECSサービスが更新されると、CodeDeployによってECSへのデプロイが行われます。
そのため、CodeDeployがECSへのデプロイに関する操作を行えるようにIAMロールの作成を行います。

- CodeDeploy用のIAMロールを作成し、`AWSCodeDeployRoleForECSLimited`管理ポリシーをアタッチ
- タスク実行ロールまたはタスクロール上書きに対する iam:PassRole アクセス許可を、CodeDeploy用のIAMロールにインラインポリシーとして追加

Fargateの場合、タスク実行ロールが追加されていると思いますので、2つめの手順も忘れずに実行してください。

詳細な手順については、「Amazon ECS 開発者ガイド」の[Amazon ECS CodeDeploy IAM Role](https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/codedeploy_IAM_role.html) を参照して下さい。

### ALBの作成

443/tcp、8080/tcpを受け付けるALBを作成します。
この手順ではアプリケーションの都合上443/tcpとしていますが、80/tcpでも問題ありません。

ALBの作成の中で、セキュリティグループも新規作成します。
8080/tcpを任意の場所 (0.0.0.0/0) でも使用できるように、ルールを追加します。
<img width="1432" alt="スクリーンショット 2019-03-17 16.28.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/b65c9260-433f-e293-dd8e-c81315ffebad.png">

ルーティングの設定で、新しいターゲットグループを作成します。
名前は、Blue/Greenデプロイのためのターゲットグループであることがわかるように、`stg-fargate-blue`としてます。Blue/Greenデプロイにおいて、ターゲットを切り替えるためのもう１つのターゲットグループは、ECSサービスの作成において作成するため、現時点ではターゲットグループは１つで大丈夫です。
<img width="1426" alt="スクリーンショット 2019-03-17 16.36.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/578ab062-d6b5-d484-a107-b82eb6f0b8e3.png">

「ステップ 5: ターゲットの登録」は、特に設定は必要ありません。確認画面で設定を確認し、ALBを作成してください。
また、必要に応じてRoute53のレコードセットの追加を行います。

### タスクの定義の作成

Fargateのタスクの定義の作成方法については省略させていただきます。

### ECSサービスの作成

**サービスの設定**

| 項目 | 値 |
| --- | --- |
| 起動タイプ | FARGATE |
| タスク定義 | 上記で作成したタスクの定義を選択|
| プラットフォームのバージョン | LATEST|
| クラスタ | 作成済みのクラスタを選択 |
| サービス名 | 任意のサービス名 |
| タスクの数 | 1 |

**サービスの設定**

| 項目 | 値 |
| --- | --- |
| Deployment type | Blue/green deployment (powered by AWS CodeDeploy) |
| Service role for CodeDeploy | 上記で作成したCodeDeploy用のIAMロール選択 |

**VPC とセキュリティグループ**
VPCは、ALB作成で指定したVPC指定。
セキュリティグループは、作成済みのECSサービスのセキュリティグループを指定。

**Elastic Load Balancing（オプション）**

| 項目 | 値 |
| --- | --- |
| ELB タイプ | Application Load Balancer |
| ELB 名 | 上記で作成したALBを選択 |

「負荷分散用のコンテナ」をクリックして、`負荷分散用のコンテナ`を登録します。

| 項目 | 値 |
| --- | --- |
| リスナーポート | 443:HTTPS をドロップダウンリストから選択 |
| リスナープロトコル | HTTPS |
| Test listener | チェックあり |
| Test listener port | 8080 |
| Test listener protocol | HTTP |

<img width="878" alt="スクリーンショット 2019-03-17 17.04.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/d2d97e95-3581-f756-a5d0-00d474c7bc67.png">

**Additional configuration**
ここでは、Blue/Greenデプロイで使用する2つのターゲットグループに関する設定を行います。
このターゲットグループをCodeDeployが切り替えることによって、Blue/Greenデプロイが可能になります。

ターゲットグループ1は、ALB作成時に作成した`stg-fargate-blue`を選択します。
<img width="911" alt="スクリーンショット 2019-03-17 17.06.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/2db0c82a-98e0-2dcc-5980-e93ef5d207b5.png">

ターゲットグループ2は、新規で作成します。名前は、`stg-fargate-green`としておきます。なお、ターゲットグループ名、ヘルスチェックパスについては環境に合わせて変更してください。
<img width="944" alt="スクリーンショット 2019-03-17 17.08.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/b3c4cc5b-85c8-835c-6d49-25deca5cd283.png">

上記の設定が完了したら、ECSサービスを作成します。
この時点で、ALBを確認するとターゲットグループが作成されていることが確認できます。
![スクリーンショット 2019-03-17 17.12.13.png](https://qiita-image-store.s3.amazonaws.com/0/206741/752f975f-7fef-9c3d-51e3-b879f02ce824.png)

CodeDeployについても確認してみると、アプリケーションとデプロイグループが作成されています。(この例だと名前が微妙ですね。)
<img width="1095" alt="スクリーンショット 2019-03-17 17.19.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/0e508112-fc0a-551a-80ce-810704808b42.png">

### デプロイグループのデプロイ設定を変更

デプロイグループのデフォルトの設定では、デプロイされた際に、新しくデプロイが行われた側のターゲットグループに、トラフィックが自動で流れ始めてしまいます。
今回は、動作確認をしてからターゲットグループの変更を行いたいため、トラフィックの再ルーティングするタイミングを指定します。今回は15分後に、再ルーティングされるように変更します。この設定をすることで、15分間待たなくても手動で再ルーティングすることも可能です。詳細は後述。

また、デフォルトの設定では、タスクの正常な展開後(再ルーティング後)1時間待ってから元のタスクが終了します。今回は30分後にタスクが終了するように設定を変更します。

デプロイグループを選択し、「編集」ボタンを押下することで、デプロイ設定画面が表示されます。

<img width="1063" alt="スクリーンショット 2019-03-17 18.03.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/946ba78f-53dc-3867-5ee8-2f939168b9d7.png">
<img width="815" alt="スクリーンショット 2019-03-17 17.59.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/fd181745-e3d3-98fd-dded-92d1bce8283f.png">

## Blue/Greenデプロイをする

### ECRのリポジトリに新しいDockerイメージをPushする

ECRのリポジトリは下記の通りとなっています。
<img width="358" alt="スクリーンショット 2019-03-17 17.36.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/c56430a5-fc4d-6eb9-19cc-2804f23ba49e.png">

タグ`1.0.2`,`latest`をつけたDockerイメージをECRのリポジトリにpushします。
`latest`が最新のイメージのみについています。古いイメージについていた`latest`は自動的に剥がされています。
<img width="355" alt="スクリーンショット 2019-03-17 17.53.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/0c360751-caeb-cf23-831f-f42d741b64c6.png">

### タスク定義のリビジョンを作成し、ECSサービスを更新する

タスクの定義の新しいリビジョンを作成し、ECSサービスを更新します。
このサービスを更新した時点で、CodeDeployによるデプロイが開始されます。

CodeDeployからデプロイのステータス、トラフィック移行の進行状況を確認できます。
<img width="1080" alt="スクリーンショット 2019-03-17 18.10.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/cc009e36-64fb-99df-f865-27742eab3062.png">

タスクを確認すると、新旧のタスクのリビジョンが起動していることを確認できます。
<img width="1139" alt="スクリーンショット 2019-03-17 18.12.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/7e0bb1a9-ecbd-0afd-9782-930801bc88fe.png">

ALBのエンドポイントの8080番ポートにアクセスし、正常に動作していることを確認します。
問題がなければ、デプロイしたターゲットグループにトラフィックを向け、リリースを実施します。

CodeDeployの「トラフィックの再ルーティング」ボタンを押下することで、デプロイしたターゲットグループにトラフィックが流れ始めます。
<img width="694" alt="スクリーンショット 2019-03-17 18.19.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/0e016821-d9ac-bac0-0ded-280710b85329.png">

<img width="688" alt="スクリーンショット 2019-03-17 18.21.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/6f5991dd-8970-fc79-5992-0621ece74d0d.png">

ALBのリスナーを確認すると、ターゲットグループが変更されていることを確認できます。
HTTPSの転送先のターゲットグループが`stg-fargate-blue`から`stg-fargate-green`に変更されています。
![スクリーンショット 2019-03-17 18.24.30.png](https://qiita-image-store.s3.amazonaws.com/0/206741/c68ddd10-f9fb-7b6e-21b1-3f0efa3bde0f.png)

旧タスクの待機時間が終了すると、旧タスクが停止されデプロイが完了します。
<img width="1073" alt="スクリーンショット 2019-03-17 18.50.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/82ce41f4-4653-044d-1441-d398fb16206b.png">

## ロールバック機能

デプロイに問題が発生した場合は、展開を停止してロールバックすることができます。
サービスの`デプロイ`タブに表示されている「Stop and rollback deployment」ボタンを押下することで、展開が停止されます。

<img width="1178" alt="スクリーンショット 2019-03-17 18.17.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/206741/f97ef8a8-214f-616e-66f0-0aaebacb7d82.png">

## まとめ

ECSでCodeDeployを使用したBlue/Greenデプロイメントを利用することで、簡単にBlue/Greenデプロイができました。CodePipelineを利用したデプロイもサポートされているので、さらにデプロイが簡単になりますね！

## 参考記事

参考にさせていただきました。ありがとうございます。
[AWS CodeDeploy による AWS Fargate と Amazon ECS でのBlue/Greenデプロイメントの実装](https://aws.amazon.com/jp/blogs/news/use-aws-codedeploy-to-implement-blue-green-deployments-for-aws-fargate-and-amazon-ecs/)
[ECSでCodeDeployを使用したBlue/Green Deploymentがサポートされたので早速試してみた #reinvent ｜ DevelopersIO](https://dev.classmethod.jp/cloud/aws/ecs-codedeploy-blue-green-deployment/)