ALBリスナールールとLambdaだけでメンテナンスページへの切替が簡単にできる仕組みを作る
どーもsutoです。
毎日決まった時間帯にWebサイトをメンテナンスページに自動切替を行う仕組みを構築する機会がありましたので、備忘録も含めて本記事に残そうと思います。
作成するリソース
今回作成するリソースは以下となります。(既にALB作成、Webサイト(EC2)へ転送するALBリスナールールを作成済であることを前提とします)
- メンテナンス画面を表示させるLambda(1)を作成
- Lambda(1)をターゲットグループに登録し、それをALBリスナールールに設定
- ALBリスナールールのPriority値を変更するLambda(2)を作成
- Lambda(2)を定期実行させるEventBridgeを作成
やってみた
メンテナンスページ用Lambdaとターゲットグループの作成
EC2メニューから「ターゲットグループの作成」をクリックし、ターゲットタイプでLambda関数を選択し、「ターゲットグループ名」を任意で入力し「次へ」をクリックします。
「関数を作成します」をクリックし、Lambda作成の画面に飛びます。関数作成の画面で「Serverless Application Repositoryの参照」で「ALB-Lambda-Target-HelloWorld」を検索して選択します。
AWS Lambda」の「関数」画面で、「アプリケーションの設定」の「アプリケーション名」を「ALB-Lambda-Target-HelloWorld」を任意の名前に書き換え(今回はALB-Lambda-Target-maintenanceとしました)デプロイをクリックします。
下記画面が表示され、メンテナンスページを表示させるためのLambdaが作成されました。
ちなみにこのLambdaは裏でCloudFormationスタックが作成しているリソースです。
ターゲットグループの作成の「ターゲットの登録」画面に戻り、先ほど作成したLambdaを選択して「ターゲットグループを作成」をクリックします。これでLambda用ターゲットグループ作成は完了です。
Lambda関数内のhtmlコードを編集する
Lambdaメニューから作成したLambda関数の関数名をクリックし、htmlコードの部分(下画像の11〜25行目)を編集してメンテナンスページを作成します。
今回は以下の例のようにコードを編集してみました。
# coding: UTF-8 def lambda_handler(event, context): response = { "statusCode": 200, "statusDescription": "200 OK", "isBase64Encoded": False, "headers": { "Content-Type": "text/html; charset=utf-8" } } response['body'] = """<html lang="ja"> <head> <meta charset="utf-8"> <title>ただいまメンテナンス中です</title> <meta name="description" content="システムメンテナンスのお知らせ"> <!--[if lt IE 9]> <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.js"></script> <![endif]--> </head> <body> <div style='max-width: 600px; margin: 30px auto;'> <div style='border: 1px solid #ccc; padding: 30px; margin-top: 30px;'> <h1 style="color: #F00">システムメンテナンスのお知らせ</h1> <p> いつもご利用いただき、誠にありがとうございます。<br /> このたびサービス向上のため、システムメンテナンスを実施させていただきます。<br /> 下記日時はサービスをご利用いただけません。</p> <ul> <li>2021/1/11(月)AM00:00~2021/1/11(月)AM3:00</li> </ul> <p>お客さまには大変ご迷惑をおかけいたしますが、何卒、よろしくお願い申し上げます。 </p> </div> </div> </body> </html>""" return response
ALBリスナールールを編集する
EC2メニューで対象のALBを選択し、リスナールールの編集画面を開きます。
「リスナーの追加」で、既存のEC2(Webサイト)が登録してあるターゲットグループ(test1-tg)を転送先とするルールと、先ほど作ったメンテナンスページ用Lambdaを登録したターゲットグループ(alb-tg-lambda)を転送先とするルールを作成します。
※IFの条件は例としてSourceIPで設定しています
リスナールールのPriority値を変更するLambdaを作成
LambdaメニューでALBリスナールールのPriority値を変更する処理を実行するためのLambdaを新規作成します。(例として関数名は「test-alb-rule」という名前にしています)
上記Lambdaの実行ロールには、ALBへのアクセス権限が必要なため以下のポリシーで作成しています。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "logs:CreateLogGroup", "Resource": "arn:aws:logs:ap-northeast-1:133998493178:*" }, { "Effect": "Allow", "Action": [ "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": [ "arn:aws:logs:ap-northeast-1:133998493178:log-group:/aws/lambda/test-alb-rule:*" ] }, { "Effect": "Allow", "Action": [ "elasticloadbalancing:Describe*", "elasticloadbalancing:SetRulePriorities" ], "Resource": [ "*" ] } ] }
変更処理のコードは以下となります。(今回は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': 'Lambda用ターゲットグループ転送するリスナールールのARN', 'Priority': 1 }, ] ) # 変更後の設定を表示 result = client.describe_rules( ListenerArn='ALBリスナーのARN', ) return result
実際に上記のLambda関数を手動で実行してみると、
リスナールールの優先順位が入れ替わったことが確認できました。
この状態でWebサイトのURL(ALBのDNS)へアクセスしてみると、
Lambda内に作成したhtmlページが表示され、通常のトップページにはアクセスされないようになりました。
あとは、このLambdaをスケジュール実行させるためにEventBridge等でトリガーを追加すれば完成です。
また、メンテナンスページ→通常のページに切り戻す処理を作りたい場合は、上記のLambda+EventBridgeの設定と同じ仕組みで、コード内の「Priority値」を逆にして作成すればOKです。
まとめ
メンテナンスページの作成に関しては、S3+Cloudfrontで作成する他、今回のようにALBとLambdaだけで比較的簡単に作れる方法もあります。
本記事がどこかでお役に立てれば幸いです。以上、メンテナンスページ自動切替の実装方法について一例のご紹介でした。