CloudFormationでのAutoScalingGroup配下のインスタンス入れ替え方法

`AWS::AutoScaling::AutoScalingGroup`の更新時にはインスタンスの入れ替えが発生する場合がある。
LaunchConfigurationに変更があった場合、VPCの設定が変わった場合など。

この時、どのようにインスタンスを入れ替えるかを`UpdatePolicy`属性で指定することができる。
指定できる方式は2種類。

- **AutoScalingRollingUpdate**
 既存のAutoScalingGroup配下のインスタンスを数台ずつ入れ替えていく方法。

- **AutoScalingReplacingUpdate**
 新しいAutoScalingGroupを作成して、新旧のグループを入れ替える方法。

どちらも指定しないとインスタンスの入れ替えが発生せず変更が反映されないので注意。
両方指定した場合は`AutoScalingReplacingUpdate`の`WillReplace`の値によってどちらの方式が優先されるか決まる。
`true`なら`AutoScalingReplacingUpdate`が優先、`false`なら`AutoScalingRollingUpdate`が優先、となる。

# AutoScalingRollingUpdate

下記の例では、最低1台は稼働させつつ、1台ずつ入れ替える。
`SignalResource`の受信を持って起動完了とみなす。
シグナル受信のタイムアウトは10分。

```yaml:AutoScalingRollingUpdate
Resources:
  ASG:
    Type: "AWS::AutoScaling::AutoScalingGroup"
    UpdatePolicy:
      AutoScalingRollingUpdate:
        MaxBatchSize: 1
        MinInstancesInService: 1
        PauseTime: PT10M
        WaitOnResourceSignals: true
          :
    Properties:
      :
```

その他の設定はドキュメントを参照。
[AutoScalingRollingUpdate Policy](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-updatepolicy.html#cfn-attributes-updatepolicy-rollingupdate)

実行時のCloudFormationのイベントはこんな感じ。下に行くほど古いイベント。
新旧インスタンスの起動と停止は同時に行われる。

```
Received SUCCESS signal with UniqueId i-555...
New instance(s) added to autoscaling group - Waiting on 1 resource signal(s) with a timeout of PT10M.
Successfully terminated instance(s) [i-222...] (Progress 100%).
Terminating instance(s) [i-222...]; replacing with 1 new instance(s).

Received SUCCESS signal with UniqueId i-444...
New instance(s) added to autoscaling group - Waiting on 1 resource signal(s) with a timeout of PT10M.
Successfully terminated instance(s) [i-111...] (Progress 67%).
Terminating instance(s) [i-111...]; replacing with 1 new instance(s).

Received SUCCESS signal with UniqueId i-333...
New instance(s) added to autoscaling group - Waiting on 1 resource signal(s) with a timeout of PT10M.
Successfully terminated instance(s) [i-000...] (Progress 33%).
Terminating instance(s) [i-000...]; replacing with 1 new instance(s).

Rolling update initiated. Terminating 3 obsolete instance(s) in batches of 1, while keeping at least 1 instance(s) in service. Waiting on resource signals with a timeout of PT10M when new instances are added to the autoscaling group.
```

## ロールバック時の挙動

スタック更新失敗時のロールバックの挙動について。
デフォルトの設定では1台でも入れ替えに失敗するとロールバックされる。
`UpdatePolicy`の`MinSuccessfulInstancesPercent`が100%の場合（デフォルトで100%）。

```yaml:MinSuccessfulInstancesPercent
UpdatePolicy:
  AutoScalingRollingUpdate:
    MinSuccessfulInstancesPercent: 100
```

それまでに起動に成功したインスタンスがあれば数台ずつ停止され、前回の設定を使って起動したインスタンスに入れ替わっていく。
ロールバック時も`UpdatePolicy`の設定に従って入れ替えられる。

前回の設定でインスタンスを起動できるようにしておかないとロールバックに失敗するので注意。
参考：[CloudFormationのロールバック時に設定ファイルも元に戻す](http://qiita.com/ryo0301/items/c2141d05eda63b2d2bad)

## メリット

- **余分なインスタンスの起動がない**
 数台ずつ入れ替えるのでインスタンスの同時起動数がさほど増えない。
 なのでEC2のリミットに引っかかりにくい。

- **暖機運転が不要**
 これは作りと設定次第。
 徐々に入れ替わるので、キャッシュなどが消えても結果的に影響が少なくなる。

## デメリット

- **入れ替え完了まで時間がかかる**
 徐々に入れ替わるので当然時間がかかる。
 `MaxBatchSize`を最大にして`MinInstancesInService`を0にすれば全台一斉に入れ替えることもできる。
 サービスは死ぬ。すでに死んでいる時などに有効。

- **入れ替え中は新旧インスタンスが混在する**
 アプリケーションの作りによってはデータの整合性が取れなくなったりする。

- **途中で起動失敗するとロールバックにも時間がかかる**
 起動時と逆に数台ずつ古いインスタンスに入れ替わっていくため。

- **ロールバック時に旧設定で起動できるよう工夫する必要がある**
 「ロールバック時の挙動」に書いた通り。

# AutoScalingReplacingUpdate

下記の例では、新規AutoScalingGroupを作成し、3台分の`SignalResource`の受信をもって作成完了とする。
シグナル受信のタイムアウトは10分。
`CreationPolicy`を指定しないと`SignalResource`で`FAILURE`を送信してもロールバックが行われず入れ替えが完了してしまうので注意。

```yaml:AutoScalingReplacingUpdate
Resources:
  ASG:
    Type: "AWS::AutoScaling::AutoScalingGroup"
    CreationPolicy:
      ResourceSignal:
        Count: 3
        Timeout: PT10M
    UpdatePolicy:
      AutoScalingReplacingUpdate:
        WillReplace: true
    Properties:
      :
```

その他の設定はドキュメントを参照。
[AutoScalingReplacingUpdate Policy](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-updatepolicy.html#cfn-attributes-updatepolicy-replacingupdate)

実行時のCloudFormationのイベントはこんな感じ。下に行くほど古いイベント。

```
Received SUCCESS signal with UniqueId i-555...
Received SUCCESS signal with UniqueId i-444...
Received SUCCESS signal with UniqueId i-333...

Resource creation Initiated
Requested update requires the creation of a new physical resource; hence creating one.
```

## ロールバック時の挙動

スタック更新失敗時のロールバックの挙動について。
デフォルトの設定では1台でも入れ替えに失敗するとロールバックされる。
`CreationPolicy`の`MinSuccessfulInstancesPercent`が100%の場合（デフォルトで100%）。
`UpdatePolicy`ではないので注意。

```yaml:MinSuccessfulInstancesPercent
CreationPolicy:
  AutoScalingCreationPolicy:
    MinSuccessfulInstancesPercent: 100
```

新規のAutoScalingGroupと配下の新規インスタンスは削除される。
インスタンス起動時にELBには登録されるが、InServiceになる前に外される。

## メリット

- **入れ替え完了まで時間がかからない**
 全台同時に入れ替えるので完了までの時間が短い。

- **入れ替え中に新旧インスタンスが混在しない**
 新旧インスタンスが共存している時間が短いので、混在することによるリスクが少ない。

- **ロールバック時に現行システムに影響がない**
 スタックの更新に失敗しても、現行のインスタンスは影響を受けない。

## デメリット

- **一時的なインスタンス同時起動数が2倍になる**
 全台同時に入れ替えるので一時的に2倍のインスタンス数が必要になる。
 なのでEC2のリミットに引っかかりやすい。

- **暖機運転が必要**
 これは作りと設定次第。
 全台同時に入れ替わるので、例えば全サーバでキャッシュが消えてサービスに影響がでたりする。
 その場合、暖機運転を行ったあと`SignalResource`を送信するなどの対応が必要。