AWS EC2 AutoScalingグループを更新するときの各種パラメータの挙動調査(CloudFormation)

# サマリ
## この記事で得られること
* AutoScalingグループの更新方法について2種類があることがわかる
* AutoScalingグループの更新時の挙動に関わるパラメータについて一部理解できる（CFnシグナル関連）
* 検証結果から、上記のパラメータの理解について深められる

## 読むのにかかる時間
10分

## 前提知識
* EC2 AutoScalingの基礎知識
    * 参考：https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/what-is-amazon-ec2-auto-scaling.html
* cfn-signalの基礎知識
    * 参考：https://dev.classmethod.jp/articles/cfn-helper-scripts/

# AWS EC2 AutoScalingグループを更新するときの各種パラメータ
AWSにて、EC2のAutoScalingグループ（※）をCloudFormationで新規作成後、同AutoScalingぐるーｐのEC2の入替を行う際の挙動に関連するパラメータについて本ブログで確認する。
※https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-autoscaling-autoscalinggroup.html

具体的には以下のパラメータである。

## CreationPolicy
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-attribute-creationpolicy.html#w34aac23c19b7c13

| パラメータ名 | パラメータ概要 | 本ブログでの扱い |
|:-:|:-:|:-:|
| AutoScalingCreationPolicy | AutoScalingグループのステータスをCREATE_COMPLETEに設定する前に成功を通知する必要のあるインスタンス数を指定 | - |
| MinSuccessfulInstancesPercent | AutoScalingグループのステータスをCREATE_COMPLETEに設定する前に成功を通知する必要のあるインスタンスの割合。Timeoutプロパティで指定された時間内にインスタンスから信号が送信されない場合、CFnはインスタンスが作成されなかったとみなす。 | 扱う |
| ResourceSignal | CloudFormationで関連リソースを作成する際に、必要な成功シグナル数とCloudFormationがシグナルを待機する時間を設定 | - |
| Count | CloudFormationがリソースステータスをCREATE＿COMPLETEに設定する前に必要な成功シグナルの受信数。失敗シグナルを受信するかタイムアウトするまでに指定数のシグナルを受信しなかった場合、リソースの作成は失敗となりCloudFormationはスタックをロールバックする。 | 扱う |
| Timeout | CloudFormationがCountプロパティで指定された数のシグナルを待つ時間 | 扱わない | 

## UpdatePolicy
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-attribute-updatepolicy.html#cfn-attributes-updatepolicy-replacingupdate

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-attribute-updatepolicy.html#cfn-attributes-updatepolicy-rollingupdate

| パラメータ名 | パラメータ概要 | 本ブログでの扱い |
|:-:|:-:|:-:|
| AutoScalingReplacingUpdate | - | - |
| WillReplace | AutoScalingグループとその中のインスタンスが更新時に置き換えられるかどうかの指定。trueの場合、新しいASグループの作成が完了するまで古いASグループを保持する。更新に失敗した場合、古いASグループにロールバックする。必ずCreationPolicyの指定が必要。falseの場合、AutoScalingグループの置き換えは発生せず、インスタンスのみを置き換える(RollingUpdate)。 | 扱う |
| AutoScalingRollingUpdate | - | - |
| MaxBatchSize | CloudFormationが更新するインスタンス数の最大数 | 扱わない |
| MinInstancesInService | 古いインスタンスを更新している間、CloudFormationグループ内で使用中となる必要があるインスタンス数の最小数 | 扱わない | 
| MinSuccessfulInstancesPercent | 更新を成功させるための成功のシグナルを送信する必要があるインスタンスのローリング更新における割合。PauseTimeプロパティの時間内にシグナル送信がなかった場合、インスタンスが更新されなかったとみなす。WaitOnResourceSignals、PauseTimeプロパティを有効にする必要がある。 | 扱う |
| PauseTime | CloudFormationが一時停止する時間の長さ。WaitOnResourceSignalsプロパティを有効にした場合、置き換えられたインスタンスから有効なシグナルを必要な数受け取るのをCloudFormationが待機する時間。| 扱わない |
| SuspendProcesses | スタックの更新中にAutoScalingのスケーリングプロセスが停止されるように指定する。例えば、アラームに関連付けられたスケーリングポリシーの停止など。 | 扱わない |
| WaitOnResourceSignals | Auto Scaling グループが更新中に新しいインスタンスからのシグナルを待機するかどうかを指定します。 | 扱う |


上記のパラメータ次第で、AutoScalingグループの更新は以下の2つの構成をとることができる。それぞれについて検証する。
* ローリングアップデート：UpdatePolicy > AutoScalingReplacingUpdate > WillReplace = false
    * AutoScalingグループは既存のものを利用し、置き換えが発生しない。
    * 新しいEC2インスタンスがAutoScalingグループに追加され、それに伴い古いEC2インスタンスはAutoScalingグループからデタッチされ、終了する。
* AutoScalingグループごと入替：UpdatePolicy > AutoScalingReplacingUpdate > WillReplace = true
    * AutoScalingグループを新規に作成し、AutoScalingグループごと置き換えが発生する。
    * 新規のAutoScalingグループとEC2インスタンスが作成され、正常なことを確認後、新規のAutoScalingグループを正式なリソースとし、古いAutoScalingグループを削除する。

# ローリングアップデートでの挙動
## 実機検証
ローリングアップデートに関わるパラメータについて、以下の通り実機検証を行った。

| 検証番号 | WillReplace | MinSuccessfulInstancesPercent | WaitOnResourceSignals | 成功シグナル数/失敗シグナル数/インスタンス総数 | スタック状態 | 検証結果 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| No.1 | false | 100 | true | 2/0/2 | COMPLETE | すべてのインスタンスが成功シグナルで100%を満たすためデプロイ成功 |
| No.2 | false | 100 | true | 0/1/2 | ROLLBACK | 1つ目に作成したインスタンスが失敗シグナルだったため、条件を満たさずデプロイ失敗 |
| No.3 | false | 100 | true | 1/1/2 | ROLLBACK | 2つ目に作成したインスタンスが失敗シグナルだったため、条件を満たさずデプロイ失敗 |
| No.4 | false | 50 | true | 1/1/2 | COMPLETE | 成功シグナル、失敗シグナルが1つずつであるが、50%を満たすためデプロイ成功 |
| No.5 | false | 50 | true | 0/2/2 | ROLLBACK | 2つ目に作成したインスタンスが失敗シグナルのときに、条件を満たさなくなったためデプロイ失敗 |

# AutoScalingグループごと入替での挙動
## 実機検証
AutoScalingグループごと入替に関わるパラメータについて、以下の通り実機検証を行った。
| 検証番号 | WillReplace | MinSuccessfulInstancesPercent | Count | 成功シグナル数/失敗シグナル数/インスタンス総数 | スタック状態 | 検証結果 |
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| No.1 | true | 100 | 1 | 2/0/2 | COMPLETE | すべてのインスタンスが成功シグナルで100%を満たすためデプロイ成功 |
| No.2 | true | 100 | 1 | 1/0/2 | COMPLETE | Count=1であり、1つ目のインスタンスが成功シグナルだったため、デプロイ成功 |
| No.3 | true | 100 | 1 | 1/1/2 | ROLLBACK | 100%を満たさず、デプロイ失敗。No.2との差分は、No.2は失敗シグナルを受信しなかった点 |
| No.4 | true | 100 | 1 | 0/2/2 | ROLLBACK | すべてのインスタンスが失敗シグナルだったため、条件を満たさずデプロイ失敗 |
| No.5 | true | 50 | 1 | 2/0/2 | COMPLETE | すべてのインスタンスが成功シグナルで50%を満たすためデプロイ成功 |
| No.6 | true | 50 | 1 | 1/1/2 | ROLLBACK | 50%は満たしているように思うが、ROLLBACKとなる |
| No.7 | true | 50 | 1 | 0/2/2 | ROLLBACK | 50%を満たさず、デプロイ失敗 |

# まとめ
実機検証の結果より、cfnシグナルの成功/失敗の割合により、AutoScalingグループの更新を成功、失敗の制御を行えることを確認した。
基本的には、「MinSuccessfulInstancesPercent」の通りの結果となる。
一方で、「AutoScalingグループごと入替」のNo.6の結果は直観通りではなかった。こちらについては追加の仕様確認が必要である。

※「AutoScalingグループごと入替」のNo.6のUPDATE_FAILEDの理由は以下の通りで、現時点ではCOUNTが1であることに起因しているように考える。
`Received 1 FAILURE signal(s) out of 1. Unable to satisfy 50% MinSuccessfulInstancesPercent requirement`