この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
どーも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だけで比較的簡単に作れる方法もあります。
本記事がどこかでお役に立てれば幸いです。以上、メンテナンスページ自動切替の実装方法について一例のご紹介でした。