CodeDeploy + ALBでEC2に1台ずつデプロイする

## はじめに

CodeDeployはALBを使って、複数台あるEC2を順次

1. 振り分け停止
2. デプロイ実施
3. 振り分け再開

する、といったデプロイ方法を取ることが可能です。

これを試してみたところ、想像していたよりもデプロイに時間がかかってしまいました。

また、ターゲットグループの設定を見直すことで処理時間を短縮できるので、その点も含めて記事化しています。

## 1. 構成

- ALB
- EC2インスタンス * 2

ALBのターゲットグループでは、以下の通り2台のEC2インスタンスを登録しています。

<img width="1086" alt="target group" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/349a33e6-f059-9cb6-7470-c3efca80d800.png">

この2台がCodeDeployのデプロイ対象です。

## 2. CodeDeployのデプロイグループの設定

ALBを使ったデプロイでのCodeDeployの設定です。

### 2.1. デプロイタイプ

デプロイタイプは`インプレース`としました。既存のEC2インスタンスに新しいアプリケーションをデプロイします。

<img width="746" alt="deploy type" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/0934da0b-347c-3239-0938-76181ea85988.png">

なお、`Blue/Green`だと、新しくEC2インスタンスを起動し、そこに新しいアプリケーションをデプロイします。

### 2.2. デプロイ設定

デプロイ設定は`CodeDeployDefault.OneAtATime`としました。これは1台ずつデプロイを行う設定です。

<img width="739" alt="setting" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/f256fb4d-66b4-b626-89eb-a6a52e60d964.png">

他には、1度に全台デプロイする設定や、1度に半分の台数にデプロイする設定などがあります。

- [CodeDeploy でデプロイ設定を使用する - AWS CodeDeploy](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/deployment-configurations.html)

#### 余談

なお、1度に全台デプロイする設定`CodeDeployDefault.AllAtATOnce`とALBを組み合わせると、全台をターゲットグループから削除してしまうので、この設定を組み合わせる意味は無さそうです。

👇2台ともデプロイが開始されている！？

<img width="576" alt="スクリーンショット 2020-05-11 0.36.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/c8c9fc3d-8dec-87d9-ab39-e2af0eff4bf4.png">

👇ターゲットグループにEC2インスタンスが1つもない。。。

<img width="996" alt="スクリーンショット 2020-05-11 0.36.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/4db8887c-26ba-47b9-b969-a5ef1bdfade2.png">


### 2.3. ロードバランサー

ロードバランサーは、`有効にする`にチェックを入れ、ALBを選択します。

また、ターゲットグループも、先ほどのものを選択します。

<img width="740" alt="lb" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/181aacb4-4fe0-d0b7-4fb3-f41ce141919f.png">

以上で準備は完了です。

## 3. デプロイの実施(1回目)

### 3.1. デプロイの開始

CodeDeployによるデプロイを開始します。

2台あるEC2インスタンスのうち、1台目のデプロイが`進行中`となりました。

もう1台は`保留中`となっています。

<img width="967" alt="deploy1" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/3914b287-50c9-337a-68e3-85a247aabdad.png">

ここでターゲットグループを見ると、(先ほどの画面とEC2インスタンスの並びが上下逆なのでわかりづらいですが)1台目のステータスが`draining`となったことを確認できました。

<img width="1079" alt="スクリーンショット 2020-05-10 23.22.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/96b7b7c5-06d8-66a0-2817-987e4ca86069.png">

### 3.2. ALBを使った場合のデプロイのイベント

1台目のデプロイ状況をさらに詳しく見るため、`View events`へ進みます。

<img width="967" alt="view events" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/f200027f-3bec-3da9-e5b6-2fda44e6f01f.png">

イベントがずらっと並んでいますが、ロードバランサーを使う場合はそうでない場合よりもイベントが増えます。

![events1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/70fbce91-68dc-16e7-bb08-9c489fe9ffc7.png)

以下はAWS公式ドキュメントからの引用ですが、トラフィックの停止や再開に関するイベントが最初と最後に増えています(以下の図ではClassic load blancerとありますがALBも同様)。

><img src="https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/images/lifecycle-event-order-in-place.png">
>
> - [AppSpec の「hooks」セクション - AWS CodeDeploy](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html#appspec-hooks-server)

### 3.3. BlockTrafficイベントとAllowTrafficイベント

さて、ALBを使うことで増えたイベントの`BlockTraffic`ですが、何とこちらに5分31秒もかかってしまいました。

![BlockTraffic](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/b3928bc0-6835-d9e0-819e-5a1721655b3b.png)

さらに終盤の`AllowTraffic`イベントでは2分30秒かかりました。

![AllowTraffic](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/ee53d203-2d96-dc2c-01fa-e9187d333dc2.png)

1台のEC2インスタンスのデプロイに8分30秒以上がかかっています。

ALBが賢く振り分けの停止・再開をやってはくれていますが、これは少し長い。。。

## 4. ターゲットグループの設定変更

デプロイにかかる時間を短縮するため、こちらの記事([AWS CodeDeployの速度改善(ALB)](https://qiita.com/tomozo6/items/1c436f594e2cce486153))を参考にターゲットグループの設定変更を行いました。

### 4.1. ヘルスチェック間隔の短縮

ターゲットグループ > ヘルスチェックタブ > ヘルスチェックの編集 で以下の通り、変更しました。

- タイムアウト: 5秒 -> 4秒(タイムアウトは`間隔`の秒数未満である必要があるため)
- 間隔: 30秒 -> 5秒(最小値)

#### 元々の設定

<img width="474" alt="スクリーンショット 2020-05-11 0.03.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/edcd45fb-7660-32aa-d850-40f524f7bd9c.png">

#### 変更後の設定

<img width="576" alt="スクリーンショット 2020-05-11 0.04.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/57bab556-9aa0-4ae4-ddd2-71b4b55fdc1b.png">

### 4.2. 登録解除の遅延の短縮

ターゲットグループ > 説明タブ > 属性 で以下の通り、変更しました。

- 登録解除の遅延: 300秒 -> 10秒

#### 元々の設定

<img width="930" alt="スクリーンショット 2020-05-11 0.01.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/5761e221-4f48-9900-8494-edc5685c89ad.png">

#### 変更後の設定

<img width="1222" alt="スクリーンショット 2020-05-11 0.02.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/fa272ddc-b284-fa65-a02e-87710a864fa7.png">

#### 登録解除の遅延とは

登録解除の遅延(Deregistration Delay)は、対象のEC2を振り分け停止(ターゲットグループから削除)するにあたり、未処理のリクエストやアクティブな接続が無かったとしても必ず待機する時間のことで、このデフォルトが300秒であるためにCodeDeployのBlockTrafficイベントが長期化しているようです。

>Elastic Load Balancing は、登録解除するターゲットへのリクエストの送信を停止します。デフォルトでは、Elastic Load Balancing 登録解除プロセスを完了する前に 300 秒待って、ターゲットへ処理中のリクエストが完了するのを助けることができます。
>(略)
>登録解除するターゲットに未処理のリクエストやアクティブな接続がない場合は、Elastic Load Balancing は登録解除の遅延時間が経過するのを待たずに、即時登録解除プロセスを完了します。ただし、ターゲットの登録解除が完了しても、ターゲットのステータスは、登録解除の遅延が経過するまで draining と表示されます。
>
>[登録解除の遅延 - AWS公式](https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/load-balancer-target-groups.html#deregistration-delay)


## 5. デプロイの実施(2回目)

以下の通り、大幅に短縮されました。

<img width="457" alt="スクリーンショット 2020-05-11 0.18.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/3de256b9-c739-aef6-86a8-b1cbc8bc68db.png">

- BlockTraffic: 5分31秒 -> 25秒
- AllowTraffic: 2分30秒 -> 30秒

となっています。

デプロイ処理全体で見ると、これだけの変化がありました。

### ビフォー

<img width="632" alt="スクリーンショット 2020-05-11 0.22.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/7c7e1bb8-3414-7e5d-2fd8-d06890ea7cc3.png">

### アフター

<img width="629" alt="スクリーンショット 2020-05-11 0.22.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317369/a8bf9405-ac00-8882-65c5-3b478ab783fc.png">

ALBの要件にもよりますが、CodeDeployでALBを利用したデプロイを行う場合は、ターゲットグループの設定も見直した方が良さそうです。