EC2 Auto Scalingのヘルスチェックの落とし穴(デフォルトはEC2ステータスチェックのみだよ!)

CloudFormationでEC2 Auto Scalingを設定した際にハマりました..パラメーターの指定には気をつけましょう。
2022.09.14

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは!AWS事業本部のおつまみです。

皆さんお馴染みのWEBシステム構成「ALB+EC2+RDS」に冗長性を持たせるために「EC2 AutoScaling」を設定した際に盛大にハマったので、備忘録として残しておきます。

これだけは今日覚えて帰って欲しい

AutoScalingのヘルスチェックタイプはデフォルトだとEC2ステータスチェックのみだよ!
必要に応じて、ELBのヘルスチェックタイプも適切に設定しようね!
(私のことは忘れても、これだけは今日覚えて帰ってください。)

構築したAWS構成

今回このような構成を作成し、EC2の起動・停止に合わせて、EC2 AutoScalingがどのようにスケーリングするか確認しようとしました。

こちらの構成はCloudFormationで構築しました。 (今回の記事に関係するAutoScaling Groupの部分のみ一部抜粋しています)

# ------------------------------------------------------------# 
# AutoScaling Group
# ------------------------------------------------------------#    
  AutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      AutoScalingGroupName: !Sub "${PJPrefix}-autoscalinggroup"
      # Virtual Private Cloud (VPC) のサブネット ID のリスト
      # 起動させるサブネットを指定
      VPCZoneIdentifier:
        - !Ref Private1Subnet
        - !Ref Private2Subnet
      # 起動テンプレート
      LaunchTemplate:
        # 起動テンプレートのID
        LaunchTemplateId: !Ref 'EC2InstanceLaunchTemplate'
        # 起動テンプレートのバージョン番号
        Version: !GetAtt 'EC2InstanceLaunchTemplate.LatestVersionNumber'

      # ALBの場合紐づけるTargetGroupを指定する
      TargetGroupARNs:
        - !Ref TargetGroup
      # 台数設定
      DesiredCapacity: 2
      MaxSize: 4
      MinSize: 2
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-server"
          PropagateAtLaunch: true

あれ?スケーリングしないぞ..?

今回EC2にはユーザデータでApacheをインストールしたのですが、ELBのヘルスチェックにはunhealthyが返ってきてしまいました。

注意 今回の記事内容から逸れますが、ApachインストールのみではALBのヘルスチェックに失敗します。
理由:デフォルトだとドキュメントルート配下にテストファイルがないため。
対処:ヘルスチェックを成功にするためにも、ドキュメントルート配下に配下にindex.htmlを置きましょう。(Apacheの場合、/var/www/htmlです)

話は戻りますが、本来であれば、ELBがUnhealthyになっているのでEC2がスケールアウトしそうです。ですが、インスタンス2台のまま一向に増える気配がありません。。

なぜスケーリングしなかったのか?

はい、皆さんお気づきでしょうか。。
HealthCheckTypeの指定を忘れていました。

# ------------------------------------------------------------# 
# AutoScaling Group
# ------------------------------------------------------------#    
  AutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      AutoScalingGroupName: !Sub "${PJPrefix}-autoscalinggroup"
      # Virtual Private Cloud (VPC) のサブネット ID のリスト
      # 起動させるサブネットを指定
      VPCZoneIdentifier:
        - !Ref Private1Subnet
        - !Ref Private2Subnet
      # 起動テンプレート
      LaunchTemplate:
        # 起動テンプレートのID
        LaunchTemplateId: !Ref 'EC2InstanceLaunchTemplate'
        # 起動テンプレートのバージョン番号
        Version: !GetAtt 'EC2InstanceLaunchTemplate.LatestVersionNumber'

      # ALBの場合紐づけるTargetGroupを指定する
      TargetGroupARNs:
        - !Ref TargetGroup
      # 台数設定
      DesiredCapacity: 2
      MaxSize: 4
      MinSize: 2
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-server"
          PropagateAtLaunch: true

EC2 AutoScalingのヘルスチェックについて調べてみた

EC2 AutoScalingはAutoScalingグループ内のEC2が全て正常な状態で起動されるように、インスタンスが正常か異常かを判断しています。この判断をヘルスチェックと呼びます。

参考:Auto Scaling インスタンスのヘルスチェック - Amazon EC2 Auto Scaling (日本語)

ヘルスチェックには全部で3つのパターンがあります。

  • Amazon EC2ステータスチェック (※デフォルトで有効)
  • Elastic Load Balancing(ELB)
  • カスタムヘルスチェック

※ちなみに、ヘルスチェックにより異常と判断されたEC2インスタンスをAutoScalingGroupから切り離し、正常なインスタンスをサービスインさせることをAuto Healingと呼びます。


・Amazon EC2ステータスチェック

・インスタンスの状態がrunnning以外の場合、もしくはステータスimpairedの場合に異常とみなされます。デフォルトで有効になっていて無効化が出来ません。
・単純にEC2インスタンス自体の状態確認をチェックすることができます。

・Elastic Load Balancing(ELB)

・ELBのターゲットグループのヘルスチェックでunhealthyとなったインスタンスを異常とみなします。デフォルトは無効になっています。
・Auto ScalingグループとELBが関連付けられている場合にオプションで選択可能です。
・OSレベルの状態確認だけではなく、EC2インスタンスのサービスが停止しているといったアプリケーションレベルでのチェックができます。

・カスタムヘルスチェック

・ユーザーが独自で用意した監視をヘルスチェックとして使用し、unhealthyとなったインスタンスを異常とみなします。こちらもデフォルトでは無効になっています。

つまり、デフォルトではEC2ステータスチェックしかありません。(覚えて帰って欲しいので何回もいいます) そのため今回はELBのヘルスチェックに失敗していても、EC2がステータスチェックOKだったため、AutoScalingはインスタンスを異常と判断しませんでした!

対応方法

ASGのセクションにHealthCheckTypeを指定して、環境を作り直します。

# ------------------------------------------------------------#
# AutoScaling Group
# ------------------------------------------------------------#    
  AutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      AutoScalingGroupName: !Sub "${PJPrefix}-autoscalinggroup"
      # Virtual Private Cloud (VPC) のサブネット ID のリスト
      # 起動させるサブネットを指定
      VPCZoneIdentifier:
        - !Ref Private1Subnet
        - !Ref Private2Subnet
      # 起動テンプレート
      LaunchTemplate:
        # 起動テンプレートのID
        LaunchTemplateId: !Ref 'EC2InstanceLaunchTemplate'
        # 起動テンプレートのバージョン番号
        Version: !GetAtt 'EC2InstanceLaunchTemplate.LatestVersionNumber'
     # ヘルスチェックタイプ
     HealthCheckType: ELB

      # ALBの場合紐づけるTargetGroupを指定する
      TargetGroupARNs:
        - !Ref TargetGroup
      # 台数設定
      DesiredCapacity: 2
      MaxSize: 4
      MinSize: 2
      Tags:
        - Key: Name
          Value: !Sub "${PJPrefix}-server"
          PropagateAtLaunch: true

無事、ELBのヘルスチェックが有効になりぼこぼこEC2が起動するようになりました!  

しばらく見守っていたところ、インスタンスの起動→ヘルスチェック失敗を検知→インスタンスを終了→新しいインスタンスを起動→・・の負のループに陥っていたので、そっとスタックを削除しました。  

最後に

Cloud Formationでの環境構築は大変便利ですが、必須ではないパラメータの指定が漏れがちになるなぁと改めて学びました。 これからはパラメータを1つ1つ確認してから設定していこうと思います。

最後までお読みいただきありがとうございました!
以上、おつまみ(@AWS11077)でした!

参考文献

ALBにアタッチしたEC2インスタンスの監視&修復方法について~Auto Healing編~