ALB のヘルスチェック失敗時に自動でメンテナンスページを表示させてみた

ALB のヘルスチェック失敗時に、リスナールールで設定したメンテナンスページに自動で切り替える方法を紹介しています。
2024.04.24

はじめに

アノテーション テクニカルサポートのShimizuです。

Application Load Balancer(ALB)でメンテナンス中の画面を表示させたいというお問い合わせをよくいただきます。
画面を表示させるのみならリスナールールの固定レスポンスで簡単に実装できますが、一方で ALB には「障害発生時などに自動でメンテナンス画面に切り替える」という機能はないため、実現するには複数の AWS サービスを組み合わせた実装が必要になります。

そこで今回は Lambda 関数と CloudWatch アラームを連携させて「ALB のヘルスチェック失敗時に自動でメンテナンスページに切り替える」という仕組みを構築してみました。 以下に手順をご紹介します!

手順1: ALB とターゲット EC2 を用意し、簡易的なテストページを表示させる

まず下記記事の「ALB の構築と表示確認」までの手順を参考に、簡易的なテストページを表示する ALB と EC2 を用意します。

NLB → ALB → EC2 の構成でHTTPS通信を設定してみた(2023年版) | DevelopersIO

ALB と EC2 を構築したら、ブラウザで ALB のデフォルト DNS 名にアクセスし、ターゲット EC2 上にあるテストページが表示されることを確認します。

ここまでできたら、次は ALB のリスナールールでメンテナンスページを表示させてみます。

手順2: リスナールールの固定レスポンスでメンテナンスページを表示させる

下記の画像を参考に、ALB のリスナールールで「只今メンテナンス中です!」と表示させる固定レスポンスのルール(rule-maintenance)を追加し、優先度を 10 に設定します。一方でターゲットグループに転送する通常時のルール(rule-normal)は、優先度を 20 に設定します。
※ 固定レスポンスの優先度を高くするという点がポイントなので、数値はこの通りでなくて構いません。

この状態で再度、ALB のデフォルト DNS 名にアクセスしてみます。
すると通常時のページではなく「只今メンテナンス中です!」という画面が表示されます。

これはリスナールールの優先順位により、通常時のルール(ターゲットグループへの転送)よりもメンテナンス時のルール方が優先して表示されている状態です。

いったん優先度を手動で変更し、通常時のルールが優先されるように順番を入れ替えます。元通りターゲットEC2上のテストページが表示されることを確認しましょう。

これでメンテナンスページを表示させることはできましたが、毎回手動で優先度を入れ替えなければなりません。
次の手順では、リスナールールの優先度を自動で変更する Lambda 関数の作成を行なっていきます。

手順3: ルール優先度を自動で切り替える Lambda 関数を作成する

まずは ALB の操作権限を持つ IAM ロールを作成し、続いて ALB のリスナールール優先順位を変更する Lambda 関数を「ChangeAlbRule」という関数名で作成します。下記の記事を参考にさせていただきました。

ALBリスナールールとLambdaだけでメンテナンスページへの切替が簡単にできる仕組みを作る | DevelopersIO

Lambda 関数に適用する IAM ロールのポリシー

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:Describe*",
                "elasticloadbalancing:SetRulePriorities"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

ALB リスナールールの優先順位を変更する Lambda 関数(Python)

import json
import boto3

def lambda_handler(event, context):
    client = boto3.client('elbv2')

    #リスナールールの優先順位切替(メンテナンスページを優先して開くようにする)
    responce = client.set_rule_priorities(
        RulePriorities=[
            {
                'RuleArn': 'テストページを表示(EC2 ターゲットグループに転送)するリスナールールのARN',
                'Priority': 2
            },
            {
                'RuleArn': 'メンテナンスページ(固定レスポンス)を設定したリスナールールのARN',
                'Priority': 1
            },
        ]
    )

    # 変更後の設定を表示
    result = client.describe_rules(
        ListenerArn='ALBリスナーのARN',
    )

    return result

上記の Lambda 関数を作成したら、コンソールから Test をクリックして関数を実行してみます。

正常に実行されれば、ALB のリスナールール画面でメンテナンスページを表示するルールの優先度が 1 に変更されているはずです。

これでメンテナンスページの優先度を自動で切り替える仕組みは完成ですが、このままでは ALB のヘルスチェック状態と連動していません。
次の手順ではヘルスチェックを監視する CloudWatch アラームを作成し、Lambda 関数と連携を行なっていきます。

手順4: ヘルスチェック失敗を検知する CloudWatch アラームを作成し、Lambda 関数と連携する

まずは CloudWatch のコンソールからアラームの作成をクリックします。

監視対象のメトリクスは対象ターゲットグループの「UnhealthyHostCount」を選択し、次に進みます。

次はアラームが発動する条件を設定します。
今回はヘルスチェックが一度でも失敗すれば即座にアラーム状態に遷移させたいため、データポイントを 1/1 に設定して次に進みます。

次にアラーム状態になった時のアクションを設定します。
今回は通知は不要なため設定せず、「Lambda アクションの追加」をクリックします。

ターゲットとして手順3で作成した Lambda 関数(ChageAlbRule)を選択し、アラーム状態になった際にトリガーされるように設定します。

以上の設定で CloudWatch アラームを保存します。今回は「ChangeAlbRuleAlarm」というアラーム名で作成しています。

ここでもう一つ、忘れてはいけない設定があります。
それは Lambda 関数側に、CloudWatch アラームから関数をトリガーするための許可を付与することです。

下記の記事で紹介されているように、筆者も動作検証時に Lambda 関数が実行されずハマりましたが、記事に従って Lambda 関数のリソースベースポリシーで lambda.alarms.cloudwatch.amazonaws.com を許可したところ、正常に動作しました。

Amazon CloudWatch のアラームで、実行アクションに Lambda 関数を直接指定出来るようになりました

ここまで設定できたら、ALB のヘルスチェック失敗時に自動でメンテナンスページを表示させる仕組みの構築は完了です!

最後の手順では、意図的に ALB のヘルスチェックを失敗させて動作確認を行なっていきます。

手順5: 動作確認(意図的にヘルスチェックを失敗させ、メンテナンスページを自動で表示させる)

まずは ALB リスナールールの優先順位を、通常時のテストページが優先して表示されるように設定しておきましょう。

次にヘルスチェックを意図的に失敗させるため、EC2 インスタンスにアタッチされたセキュリティグループのインバウンドルール設定で「HTTP:80」を削除して、ヘルスチェックが遮断された状態にします。
※ ターゲットグループのヘルスチェックポートを「HTTP:80」以外に設定している場合は、適宜読み替えてください。

前手順で作成した CloudWatch アラームの画面を確認します。
しばらく待つと、セキュリティグループを遮断したことにより「UnhealthyHostCount」のメトリクスが 1 になり、アラーム状態になります。

アラーム状態になったら、ALB のリスナールール画面とブラウザからの確認をしてみましょう。
ここまでの設定に問題なければ、メンテナンスページを表示するリスナールールの優先度が自動で変更され、ブラウザでもメンテナンスページが表示されるはずです。

CloudWatch アラームの履歴画面でも、アラーム状態への遷移によって Lambda 関数がトリガーされたことを確認できます。

これで、ALB のヘルスチェック失敗時に自動でリスナールールの優先度を切り替え、メンテナンスページを表示することができました!

おわりに

いかがでしたでしょうか。
今回は「ALB のヘルスチェック失敗時にメンテナンスページへ切り替える」という方法をご紹介しましたが、同様の方法で「ヘルスチェックが正常に戻ったら通常ページに切り替える」という実装も可能なので、実運用でも応用ができそうです。

また、以前は CloudWatch アラームから Lambda 関数への連携に SNS トピックを経由する必要がありましたが、現在は Lambda 関数への直接連携が可能になっているので、かなり設定がしやすくなっていると感じました。

この情報がどなたかのお役に立てれば幸いです!

参考資料

アノテーション株式会社について

アノテーション株式会社はクラスメソッドグループのオペレーション専門特化企業です。サポート・運用・開発保守・情シス・バックオフィスの専門チームが、最新 IT テクノロジー、高い技術力、蓄積されたノウハウをフル活用し、お客様の課題解決を行っています。当社は様々な職種でメンバーを募集しています。「オペレーション・エクセレンス」と「らしく働く、らしく生きる」を共に実現するカルチャー・しくみ・働き方にご興味がある方は、アノテーション株式会社 採用サイトをぜひご覧ください。