shiichan

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

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

AWS What's New aws.amazon.com

なにが発表されたの?

AWS What's New によると、Amazon EC2 Auto Scaling が新しい AWS CloudFormation 更新ポリシーとして「Instance Refresh」をサポートしたよ。テンプレートに AutoScalingInstanceRefresh という新しい更新ポリシーを設定しておくと、インスタンスの置き換えが必要なプロパティ(LaunchTemplateVPCZoneIdentifier など)を更新したときに、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 を書くだけ。こんなイメージだよ。

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 は必須で、RollingReplaceRootVolume のどちらかを指定する
  • AutoScalingInstanceRefreshAutoScalingRollingUpdate は同じ Auto Scaling グループに同時指定できない(両方書くとスタック更新が失敗する)
  • Instance Refresh がトリガーされるのは、LaunchTemplate / MixedInstancesPolicy / VPCZoneIdentifier / AvailabilityZones / AvailabilityZoneIds / PlacementGroup のいずれかを変更したときだけ
  • MinHealthyPercentageMaxHealthyPercentage の差は 100 以内にする必要があり、範囲を広げるほど同時に置き換えられるインスタンス数が増える
  • BakeTime(完了とみなすまでの待機時間)と CheckpointDelay(チェックポイント後の待機時間)はどちらも最大 172800 秒(48 時間)まで指定可能
  • CheckpointPercentages はチェックポイントのしきい値リストで、全台を置き換えるなら最後の値を 100 にする必要がある
  • ScaleInProtectedInstancesStandbyInstances はそれぞれ 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 グループを運用してて、更新のたびにヒヤヒヤしてる人にはかなり刺さる話だと思うよ!