ENGINEER BLOG ENGINEER BLOG
  • 公開日
  • 最終更新日

Auto Scaling の Instance Refresh が CloudFormation の UpdatePolicy で書けるようになったので試してみた

この記事を共有する

目次

はじめに

こんにちは!パーソル&サーバーワークスの野間です。
先日、Amazon EC2 Auto Scaling(以下、Auto Scaling)の Instance Refresh を AWS CloudFormation(以下、CloudFormation)の UpdatePolicy から実行できるようになりました。

Amazon EC2 Auto Scaling が CloudFormation のインスタンスの更新をサポート開始

何が新しいのか

Auto Scaling グループの UpdatePolicy には、以前から次の 2 つがありました。

  • AutoScalingRollingUpdate:グループはそのままに、インスタンスだけをローリングで置き換える
  • AutoScalingReplacingUpdate:グループごと新しく作り直して置き換える

つまり「起動テンプレートを更新したらローリングで入れ替える」こと自体は、これまでも AutoScalingRollingUpdate でできていました。
今回追加された AutoScalingInstanceRefresh は、AutoScalingRollingUpdate では使えなかった、次のような制御が UpdatePolicy に書けるようになりました。

  • チェックポイント:指定した割合で一度止める
  • ベイク時間:完了前に待機する
  • launch before terminate:新しいインスタンスを起動してから古いものを終了する
  • 自動ロールバック:Amazon CloudWatch アラームと連動した

Instance Refresh が走るのは、Auto Scaling グループの次のいずれかのプロパティを更新したときです。

  • LaunchTemplate
  • MixedInstancesPolicy
  • VPCZoneIdentifier
  • AvailabilityZones
  • AvailabilityZoneIds
  • PlacementGroup

指定できるプロパティの一覧は UpdatePolicy 属性のドキュメント にまとまっています。

検証してみた

今回は Application Load Balancer(以下、ALB)配下に Auto Scaling グループを置く、ごく一般的な構成で試します。

  • ALB とターゲットグループ(HTTP のヘルスチェックあり)
  • 起動テンプレート(Amazon Linux で簡単な Web サーバを起動する UserData)
  • Auto Scaling グループ(希望台数 2 台、ALB のターゲットグループに紐付け)

Auto Scaling グループに UpdatePolicy を付けた部分は次のようになります。
50 パーセントまで入れ替えたところで 300 秒(5 分)待ち、問題なければ残りを入れ替える、という設定です。

ExampleAutoScalingGroup:
  Type: AWS::AutoScaling::AutoScalingGroup
  Properties:
    MinSize: 2
    MaxSize: 2
    DesiredCapacity: 2
    VPCZoneIdentifier: !Ref SubnetIds
    TargetGroupARNs:
      - !Ref ExampleTargetGroup
    HealthCheckType: ELB
    HealthCheckGracePeriod: 60
    LaunchTemplate:
      LaunchTemplateId: !Ref ExampleLaunchTemplate
      Version: !GetAtt ExampleLaunchTemplate.LatestVersionNumber
  UpdatePolicy:
    AutoScalingInstanceRefresh:
      Strategy: Rolling
      Preferences:
        MinHealthyPercentage: 50
        CheckpointPercentages:
          - 50
          - 100
        CheckpointDelay: 300
        InstanceWarmup: 60

Strategy は必須で、通常の入れ替えなら Rolling を指定します。
CheckpointPercentages は昇順で指定し、全台を入れ替えるために最後は必ず 100 にします。
ここで一つ注意点があります。CheckpointPercentages を指定して CheckpointDelay を省略すると、待機時間が既定で 3600 秒(1 時間)になります。
5 分だけ待たせたい場合は、上記のように CheckpointDelay を明示してください。

チェックポイントで段階的に入れ替える

起動テンプレートを新しいバージョンにして、スタックを更新します。
今回は UserData のバージョン表記を変えてバージョンを 1 つ上げました。

デプロイを始めると、まず半分のインスタンスが新しいバージョンに入れ替わり、チェックポイントで待機状態に入ります。 autoscaling-instance-refresh.png

実際に試したところ、2 台構成では 50% ではなく 33% で止まりました。
これは MinHealthyPercentage: 50 のもとで入れ替えが行われる際、古いインスタンスを終了する前に新しいインスタンスを起動するため、瞬間的に 3 台になるためです。

5 分が経過すると残りのインスタンスが入れ替わり、Instance Refresh が完了します。 チェックポイントで止まっている間に新しいバージョンの動作を確認できるため、問題があればここでスタックの更新をキャンセルできます。 autoscaling-instance-refresh-02.png

わざと失敗させてロールバックを確認する

次はあえて失敗する起動テンプレートをデプロイして挙動を確認します。

今回は AlarmSpecification を使って CloudWatch アラームと連動させました。
ターゲットグループの UnHealthyHostCount >= 1 を監視するアラームを用意し、それを AlarmSpecification に指定します。

  UnhealthyHostAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: asg-refresh-unhealthy-host
      Namespace: AWS/ApplicationELB
      MetricName: UnHealthyHostCount
      Dimensions:
        - Name: TargetGroup
          Value: !GetAtt TargetGroup.TargetGroupFullName
        - Name: LoadBalancer
          Value: !GetAtt ApplicationLoadBalancer.LoadBalancerFullName
      Statistic: Maximum
      Period: 60
      EvaluationPeriods: 1
      Threshold: 1
      ComparisonOperator: GreaterThanOrEqualToThreshold
      TreatMissingData: notBreaching
  AutoScalingGroup:
    ...
    UpdatePolicy:
      AutoScalingInstanceRefresh:
        Strategy: Rolling
        Preferences:
          MinHealthyPercentage: 50
          CheckpointPercentages:
            - 50
            - 100
          CheckpointDelay: 300
          InstanceWarmup: 60
          AlarmSpecification:
            Alarms:
              - !Ref UnhealthyHostAlarm

注意点としては AlarmSpecification に指定するアラームは Instance Refresh 開始時点で OK 状態でなければならないことです。
アラームが存在しない状態でスタック更新すると、アラーム作成直後は INSUFFICIENT_DATA になるため Instance Refresh が開始できません。
今回は先にアラームだけを追加するスタック更新を行い、アラームが OK になってから更新を流しました。

次に、新しい UserData で httpd を起動後すぐ停止するバージョンをデプロイします。
新しいインスタンスは ALB のヘルスチェックを通らず unhealthy になり、アラームが ALARM 状態になります。 autoscaling-instance-refresh-03.png

アラームが ALARM になると Instance Refresh は即座に Failed となり、CloudFormation はスタックのロールバックを開始します。

autoscaling-instance-refresh-04.png

autoscaling-instance-refresh-05.png

ポイントは、ロールバックを担うのが CloudFormation のスタックロールバックであることです。

Instance Refresh が失敗すると、Auto Scaling 側でロールバックするのではなく、スタックが巻き戻り、その巻き戻し分の Instance Refresh が改めて実行されます。
挙動の詳細は Instance Refresh のユーザーガイド で確認できます。

まとめ

AutoScalingInstanceRefresh を使うと、これまで手動やスクリプトに頼っていた段階的な入れ替えや待機を、CloudFormation のテンプレートだけで表現できました。
今回はチェックポイント、ロールバック、CloudWatch アラームと連動した自動 Failed まで一通り試せました。

同じように Auto Scaling を IaC で管理している方の参考になれば幸いです。

この記事は私が書きました

野間 太一

記事一覧

猫とCloudFormationが好きです。

野間 太一

この記事を共有する

クラウドのご相談

CONTACT

クラウド導入や運用でお悩みの方は、お気軽にご相談ください。
専門家がサポートします。

サービス資料ダウンロード

DOWNLOAD

ビジネスをクラウドで加速させる準備はできていますか?
今すぐサービス資料をダウンロードして、詳細をご確認ください。