# CloudFormation の更新、ついに Instance Refresh で賢くなったよ！

やっほー、しぃちゃんだよ！今日はCloudFormationでインスタンス更新するときの選択肢が増えたよっていうニュースを見つけたの。地味に見えて運用してる人にはかなり刺さる話だから、さっそく紹介しちゃうね！

## なにが発表されたの？

AWS What's New によると、Amazon EC2 Auto Scaling が新しい AWS CloudFormation 更新ポリシーとして「Instance Refresh」をサポートしたよ。テンプレートに `AutoScalingInstanceRefresh` という新しい更新ポリシーを設定しておくと、インスタンスの置き換えが必要なプロパティ（`LaunchTemplate` や `VPCZoneIdentifier` など）を更新したときに、CloudFormation が自動で Instance Refresh をトリガーしてくれるようになるの。

この機能自体はすべての AWS リージョンで、追加料金なしで使えるよ。

## 今までどうだったの？

これまで CloudFormation で Auto Scaling グループのインスタンスを入れ替える更新をするときは、`AutoScalingRollingUpdate`（ローリングアップデート）を使うのが定番だったの。でも、このローリングアップデートには結構クセがあって、CloudFormation の公式ドキュメントにもはっきり書いてあるんだけど、

> Rolling updates don't honor the instance maintenance policy configured on your Auto Scaling group. During a rolling update, healthy capacity can drop below the MinHealthyPercentage set on the group, and CloudFormation doesn't launch new instances before terminating existing ones, regardless of MaxHealthyPercentage.

つまり、Auto Scaling グループ側でせっかく設定した「インスタンスメンテナンスポリシー」が無視されちゃったり、新しいインスタンスを先に起動してから古いのを消す（launch-before-terminate）ができなかったりしたんだよね。しかも、更新中に Auto Scaling の処理（スケーリングポリシーやヘルスチェックなど）が邪魔しないように `SuspendProcesses` でわざわざ一時停止させる必要があったの。ターミネーションポリシーやスケールイン保護みたいな Auto Scaling の便利機能も、ローリングアップデート中は使えなかったんだって。

## これで何が変わるの？

`AutoScalingInstanceRefresh` ポリシーを使うと、CloudFormation の更新が Auto Scaling 本来の Instance Refresh の仕組みに乗っかる形になるから、こんな機能がまとめて使えるようになるよ。

- **ルートボリュームの置き換え**（`ReplaceRootVolume` 戦略）でインプレース更新ができる
- **launch-before-terminate**（新しいインスタンスを先に立ち上げてから古いのを終了）
- **アラームベースのモニタリング**（CloudWatch アラームを見張って、しきい値を超えたら自動でロールバック）
- **チェックポイント＋ベイク時間**による段階的なロールアウト

しかも Auto Scaling のスケーリングポリシーやヘルスチェックは更新中もそのまま動き続けるから、デプロイのあいだサービスの安全網が外れる心配がないの。プロセスをいちいち `SuspendProcesses` で止めなくていいのも地味に嬉しいポイントだよ。ロールバックも CloudFormation のスタックロールバックの仕組みにそのまま乗るから、失敗したときの挙動もシンプルになるの。

## 深く潜ってみよう

設定は `UpdatePolicy` の中に `AutoScalingInstanceRefresh` を書くだけ。こんなイメージだよ。

```yaml
UpdatePolicy:
  AutoScalingInstanceRefresh:
    Strategy: Rolling
    Preferences:
      MinHealthyPercentage: 90
      MaxHealthyPercentage: 120
      InstanceWarmup: 300
      CheckpointPercentages:
        - 50
        - 100
      CheckpointDelay: 3600
      BakeTime: 600
      SkipMatching: true
      ScaleInProtectedInstances: Wait
      StandbyInstances: Wait
      AlarmSpecification:
        Alarms:
          - my-error-rate-alarm
```

CloudFormation ドキュメント（Template Reference）の情報を拾うと、細かい仕様も結構はっきりしてるよ。

- `Strategy` は必須で、`Rolling` か `ReplaceRootVolume` のどちらかを指定する
- `AutoScalingInstanceRefresh` と `AutoScalingRollingUpdate` は同じ Auto Scaling グループに同時指定できない（両方書くとスタック更新が失敗する）
- Instance Refresh がトリガーされるのは、`LaunchTemplate` / `MixedInstancesPolicy` / `VPCZoneIdentifier` / `AvailabilityZones` / `AvailabilityZoneIds` / `PlacementGroup` のいずれかを変更したときだけ
- `MinHealthyPercentage` と `MaxHealthyPercentage` の差は 100 以内にする必要があり、範囲を広げるほど同時に置き換えられるインスタンス数が増える
- `BakeTime`（完了とみなすまでの待機時間）と `CheckpointDelay`（チェックポイント後の待機時間）はどちらも最大 172800 秒（48 時間）まで指定可能
- `CheckpointPercentages` はチェックポイントのしきい値リストで、全台を置き換えるなら最後の値を 100 にする必要がある
- `ScaleInProtectedInstances` と `StandbyInstances` はそれぞれ `Refresh` / `Ignore` / `Wait` から選べ、デフォルトは両方とも `Wait`（1 時間待って解除されなければ失敗）
- Auto Scaling グループは同時に 1 つしか Instance Refresh を実行できないので、手動で Instance Refresh を走らせている最中にこのポリシーでスタック更新すると失敗することがある
- 従来の `cfn-signal` ヘルパースクリプトは使えず、インスタンスの準備完了を待ちたい場合は `autoscaling:EC2_INSTANCE_LAUNCHING` ライフサイクルフックを使う
- フォワード・ロールバックそれぞれ CloudFormation のリソースタイムアウト（36 時間）の制約を受けるので、長時間かかる Instance Refresh を組む場合はスタックにサービスロールを設定しておくのが推奨されている（一時クレデンシャルの期限切れ対策）

## まとめ

- CloudFormation に新しい更新ポリシー `AutoScalingInstanceRefresh` が追加され、Auto Scaling の Instance Refresh をそのままスタック更新に使えるようになった
- ルートボリューム置き換え・launch-before-terminate・アラーム監視・チェックポイント＋ベイク時間などが使え、更新中もスケーリングポリシーやヘルスチェックが有効なまま
- ロールバックは CloudFormation のスタックロールバックに統一され、全リージョンで追加料金なしで使える
- 従来の `AutoScalingRollingUpdate` は同時指定不可で、`SuspendProcesses` などの制約もそのまま残る

CloudFormation で Auto Scaling グループを運用してて、更新のたびにヒヤヒヤしてる人にはかなり刺さる話だと思うよ！
