0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ターゲットグループ障害発生時:Lambda関数でALBルールを制御し、障害時にメンテナンスページを表示する方法

Last updated at Posted at 2024-10-27

はじめに

この記事では、AWSのApplication Load Balancer (ALB) を使用し、ターゲットグループに紐づくすべてのEC2インスタンスが正常でない場合に、Lambda関数を利用して動的にメンテナンスページ(固定レスポンスページ)を表示させる手順を紹介します。

この設定により、アプリケーションの可用性を高めつつ、ユーザーに適切なメンテナンス情報を提供することが可能になります。

本記事が、誰かの技術の支えとなることを願っています!

前提:本記事は前回の検証の続きになります。

今回の内容は、以下の記事に続く検証内容です。

前回は、Application Load Balancer (ALB) を使用して複数のEC2インスタンスへの負荷分散を行い、CloudWatchの「HealthyHostCount」とEventBridgeを組み合わせてEC2障害を検知するシステムを構築しました。

ALBで複数EC2インスタンスを負荷分散する手順

CloudWatchの「HealthyHostCount」とEventBridgeを使ったEC2障害検知システムの作成手順

今回は、続きの検証として、すべてのEC2インスタンスが正常でない場合に、Lambda関数を利用してメンテナンスページを表示する手順を実装します。

事前準備

ALBでの固定レスポンス機能の設定

AWS Management Consoleにログインし、EC2ダッシュボードに移動し、左側のメニューからLoad Balancersを選択し、対象のALBを選択します。

スクリーンショット 2024-10-27 12.47.23.png

リスナーとルールのタブを開き、リスナーの設定を確認し、ルールを管理画面からルールを追加します。

スクリーンショット 2024-10-27 12.48.42.png

ルール名を「Sorry」とし、新規ルールを追加します。

スクリーンショット 2024-10-27 12.49.31.png

パスパターンには「*」を入力し、条件を追加します。

スクリーンショット 2024-10-27 12.52.00.png

ルールアクションの設定画面で「固定レスポンスを返す」を選択します。

スクリーンショット 2024-10-27 13.02.21.png

以下のHTMLファイルをレスポンス本文として入力します。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>障害発生中</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f8d7da;
            color: #721c24;
            text-align: center;
            padding: 50px;
        }
        h1 {
            font-size: 2em;
        }
        p {
            font-size: 1.2em;
        }
    </style>
</head>
<body>
    <h1>障害が発生中です</h1>
    <p>ご迷惑をおかけしております。復旧作業を行っておりますので、しばらくお待ちください。</p>
</body>
</html>

Sorry」ルールの優先度を「3」に設定し、内容を確認したら作成をクリックします。

スクリーンショット 2024-10-27 12.59.38.png

これで、ALBが特定の条件下でメンテナンスページを表示できるようになります。

ALBの通常ルール作成

現在のALBのリスナーとルールの設定は以下のようになっています。

スクリーンショット 2024-10-27 13.05.27.png

この設定では、すべてのアクセスに対して「*」が指定されているため、「Sorry」ルールが適用されてしまいます。

ALBのロードバランサーのDNS名にブラウザでアクセスしてみると、以下の通り、先ほど作成したメンテナンスページが表示されることを確認できます。

スクリーンショット 2024-10-27 13.07.13.png

次に、優先度「2」で新規の「通常パターン」ルールを作成します。

リスナーとルールのタブから「ルールを追加」を選択し、ルール名を「Normal」として作成します。

スクリーンショット 2024-10-27 13.09.10.png

最終的に、以下のようにパスパターン設定を「*」とし、優先度を「2」に設定します。ターゲット先としては、EC2インスタンスが紐づいているターゲットグループを選択します。

スクリーンショット 2024-10-27 13.10.54.png

これにより、優先度が高い「Normal」ルールが適用される仕組みとなります。

スクリーンショット 2024-10-27 13.15.51.png

実装手順

Lambda関数でALBの優先度変更プログラムを作成

次に、CloudWatchの「HealthyHostCount」とEventBridgeを使用したEC2障害検知システムの一部として、Lambda関数を作成します。

[変数]として設定する値は、ご自身の環境に合わせて適宜修正してください。

import json
import boto3

def lambda_handler(event, context):
    # [変数] ALB ARN
    alb_arn = "arn:aws:xxx"

    # [変数] リスナーARN
    alb_listener_arn = "arn:aws:xxx"

    # [変数] ターゲットグループルールARN
    target_group_rule_arn = "arn:aws:xxx"
    
    # [変数] ALBエラーページルールARN
    sorry_rule_arn = "arn:aws:xxx"

    # 1. CloudWatchの対応するアラームを確認
    cloudwatch = boto3.resource('cloudwatch')
    # [変数] CloudWatchアラーム
    alarm = cloudwatch.Alarm("HealthlyHostCount")
    
    client = boto3.client('elbv2')
    current_rule_arn = client.describe_rules(ListenerArn=alb_listener_arn)['Rules'][0]['RuleArn']

    # すでにSorryページが表示されている場合は処理を中断
    if alarm.state_value == "ALARM" and current_rule_arn == sorry_rule_arn:
        return {
            'statusCode': 200,
            'body': 'Sorryページはすでに表示されています'
        }
    elif alarm.state_value == "OK" and current_rule_arn == target_group_rule_arn:
        return {
            'statusCode': 200,
            'body': '通常ページはすでに表示されています'
        }

    # 2. Application Load Balancerのルールのプライオリティを入れ替える
    target_group_rule_priority = 2
    sorry_rule_priority = 3
    if current_rule_arn == target_group_rule_arn:
        target_group_rule_priority = 3
        sorry_rule_priority = 2

    response = client.set_rule_priorities(
        RulePriorities=[
            {
                'RuleArn': target_group_rule_arn,
                'Priority': target_group_rule_priority
            },
            {
                'RuleArn': sorry_rule_arn,
                'Priority': sorry_rule_priority
            },
        ])

    return {
        'statusCode': 200,
        'body': json.dumps(response)
    }

この関数は、ALBのルールを動的に切り替え、ヘルスチェックの結果に基づいて「Sorry」ルールと「Normal」ルールを切り替えます。

作成したLambda関数のデフォルトタイムアウトは「3秒」になっているため、「30秒」などに変更することをおすすめします。

スクリーンショット 2024-10-27 13.42.18.png

テスト実行を行ったところ、以下のエラーが発生しました。調査したところ、Lambda関数に関連付けられているIAMロールの権限が不足していました。

[ERROR] ClientError: An error occurred (AccessDenied) when calling the DescribeRules operation: User: arn:aws:sts::xxx:assumed-role/HealthlyHostCount-Lambda-role-lsp6fcvh/HealthlyHostCount-Lambda is not authorized to perform: elasticloadbalancing:DescribeRules because no identity-based policy allows the elasticloadbalancing:DescribeRules action
Traceback (most recent call last):

この問題を解決するために、カスタムIAMポリシーを作成し、IAMロールにアタッチしました。

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

Lambda関数とEventBridgeの統合

Lambda関数をEventBridgeと統合することで、ALBのターゲットグループの状態がすべて正常でない場合に自動でメンテナンスページを表示することができます。

先ほど作成したLambda関数の画面からトリガーを追加します。

スクリーンショット 2024-10-27 13.46.14.png

一つのLambda関数の処理に対して、EventBridge (CloudWatch Events)のルールを2つ設定します。

スクリーンショット 2024-10-27 13.47.44.png

検証確認

障害発生時のパターン

ALBに紐づくターゲットグループがすべてNGとなった場合に、メンテナンスページ(503エラー)が表示されるかどうかを検証します。

まず、sudo systemctl stop httpd.serviceコマンドを使用してhttpdサービスを明示的に停止します。

スクリーンショット 2024-10-27 13.56.41.png

ターゲットグループのヘルスチェックが全台NGになったことがCloudWatchで検知されました。

スクリーンショット 2024-10-27 14.18.48.png

その後、EventBridgeのルールが正常に動作していることが確認できました。

スクリーンショット 2024-10-27 14.20.28.png

Lambda関数内でリスナーとルールの設定(優先度)が変更されていることも正常に確認できました。

スクリーンショット 2024-10-27 14.22.10.png

最後に、ブラウザでアクセスした際にメンテナンスページが表示されることも確認できたため、障害発生時のパターンは成功です!

スクリーンショット 2024-10-27 14.22.57.png

障害復旧時のパターン

ALBのターゲットグループが正常に戻った際に、通常ページが表示されるかどうかを確認します。

今回は、あえてApacheサービスが1台のみ起動している場合でも動的に切り替えが行われるかを検証します(2台復旧時については動作確認済みです)。

次に、sudo systemctl start httpd.serviceコマンドを使用してhttpdサービスを明示的に起動します。

スクリーンショット 2024-10-27 14.27.41.png

ターゲットグループのヘルスチェックで1台のみOKになったことがCloudWatchで検知され、アラート状態が復旧したことが確認できました。

スクリーンショット 2024-10-27 14.30.42.png

その後、EventBridgeのルールが正常に動作し、Lambda関数内でリスナーとルールが変更(優先度)されていることも確認できました。

スクリーンショット 2024-10-27 15.23.08.png

最後に、ブラウザでアクセスした際に通常ページが表示されることも確認できたため、障害復旧時のパターンも成功です!

スクリーンショット 2024-10-27 15.23.54.png

まとめ

ここまで読んでいただきありがとうございました。

今回は、ターゲットグループ全台NG時にメンテナンスページが表示され、復旧後に通常ページへ自動切り替えできるかを検証しました。

ヘルスチェック、EventBridgeルール、Lambda関数の動作を確認する工程が多く難易度が高かったものの、すべて正常に動作し、検証をやり切ることができました。

過去の関連記事

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?