#1. はじめに
Lightsailで個人ブログをホスティングしているのですが、メンテナンス時はWordPressの標準機能でメンテナンスページを表示させていました。
今後、LightsailをALBと連携させたいと考えています。
その際、ALB側でメンテナンスページをコントロールできた方がページコントロールの観点から統一性があって良いかなと思い、ALBのリスナールールでメンテナンスページを表示させるようにしようと思いました。
メンテナンスページを表示させる方法は色々ありますが、(CloudFront+S3, 単純にS3から引っ張るetc..)ALBのリスナールールで表示させる方が一番簡単な気がするので、その方法を採用しました。
本記事では単純にALBのリスナールールでメンテナンスページを表示させる方法を公開したいと思います。
#2. 概要
ALBのリスナールールを利用し、静的なメンテナンスページを作成します。
また、リソース作成にはCloudFormationを使用します。
#3. ALBのみで実装するメンテナンスページに関して
##3.1 メリット
- 運用が楽
メンテナンスページを表示させたい時は、単純にリスナールールの順位を変更すればいいだけ - 実装が簡単
ALBに新規リスナールールを追加すればいいだけ
##3.2 デメリット
- html/cssの最大文字数が1024文字
1024文字以内だとかなり簡易的なページしか作成できない・・(本番利用には向いていない)
#4. メンテナンスページの作成
基本的なVPC環境やセキュリティグループの設定に関しては、既に構築済である前提とします。
CloudFormationテンプレート
AWSTemplateFormatVersion: '2010-09-09'
Description: "Launch a SorryPage to ALB"
# ------------------------------------------------------------
# Metadate
# ------------------------------------------------------------
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Parameters:
- PJPrefix
- ALBSubnetIDs
- ACM
- VPCID
# ------------------------------------------------------------
# Input Parameters
# ------------------------------------------------------------
Parameters:
### Share Param ###
PJPrefix:
Type: "String"
ALBSubnetIDs:
Type: "List<AWS::EC2::Subnet::Id>"
Description: "Select a subnet from two or more availability-zones."
VPCID:
Type: "AWS::EC2::VPC::Id"
Description: "Select at your VPC."
ACM:
Type: "String"
Description: "Select at your ACM ARN."
### Resources ###
Resources:
# ------------------------------------------------------------
# TargetGroup
# ------------------------------------------------------------
TargetGroup:
Type: "AWS::ElasticLoadBalancingV2::TargetGroup"
Properties:
VpcId: !Ref VPCID
Name: !Sub "${PJPrefix}-tg"
Protocol: HTTP
Port: 80
HealthCheckProtocol: HTTP
HealthCheckPath: "/"
HealthCheckPort: "traffic-port"
HealthyThresholdCount: 2
UnhealthyThresholdCount: 2
HealthCheckTimeoutSeconds: 5
HealthCheckIntervalSeconds: 10
Matcher:
HttpCode: 200
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-tg"
TargetGroupAttributes:
- Key: "deregistration_delay.timeout_seconds"
Value: 300
- Key: "stickiness.enabled"
Value: false
- Key: "stickiness.type"
Value: lb_cookie
- Key: "stickiness.lb_cookie.duration_seconds"
Value: 86400
# ------------------------------------------------------------
# ALB
# ------------------------------------------------------------
### ALB ###
ALB:
Type: "AWS::ElasticLoadBalancingV2::LoadBalancer"
Properties:
Name: !Sub "${PJPrefix}-ALB"
Tags:
- Key: Name
Value: !Sub "${PJPrefix}-ALB"
Scheme: "internet-facing"
LoadBalancerAttributes:
- Key: "deletion_protection.enabled"
Value: false
- Key: "idle_timeout.timeout_seconds"
Value: 60
- Key: "access_logs.s3.enabled"
Value: false
SecurityGroups:
- !Ref "ALBSG"
Subnets: !Ref "ALBSubnetIDs"
### HTTP通信のリスナー設定 ###
ALBListenerHTTP:
Type: "AWS::ElasticLoadBalancingV2::Listener"
Properties:
# HTTP通信でのアクセスはHTTPSへリダイレクトさせる
DefaultActions:
- Type: "redirect"
RedirectConfig:
Protocol: "HTTPS"
Port: "443"
Host: "#{host}"
Path: "/#{path}"
Query: "#{query}"
StatusCode: "HTTP_301"
LoadBalancerArn: !Ref "ALB"
Port: "80"
Protocol: "HTTP"
### HTTPS通信のリスナー設定 ###
ALBListenerHTTPS:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
Port: 443
Protocol: HTTPS
DefaultActions:
- Type: "forward"
TargetGroupArn: !Ref TargetGroup
Certificates:
- CertificateArn: !Ref ACM
LoadBalancerArn: !Ref ALB
### 通常パターンのリスナールール ###
ALBListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
Conditions:
- Field: path-pattern
Values:
- '*'
ListenerArn: !Ref ALBListenerHTTPS
Priority: 1
### メンテナンスモードのリスナールール ###
ALBListenerRule503:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: "fixed-response"
FixedResponseConfig:
ContentType: 'text/html'
MessageBody: |
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>メンテナンスのお知らせ</title>
<style>
html {
text-align: center;
}
body {
margin: 0;
padding: 0;
background: #eee;
}
#conainer {
margin: 0 auto;
padding: 20px;
width: 600px;
max-width: 600px;
}
h1 {
font-size: 2em;
}
.warn {
padding: 1em;
background: #ff7;
}
#footer {
text-align: center;
}
</style>
</head>
<body>
<div id="container">
<h1>ただいまメンテナンス中です</h1>
<p>
システムアップデートのためサービスを停止しています。<br>
ユーザーの皆様にはご不便をおかけしますが、メンテナンス終了まで今しばらくお待ち下さい。<br>
</p>
<h2>メンテナンス期間</h2>
<p class="warn">
<strong>202x年x月x日(x) xx:xx 〜 xx月xx日(x) xx:xx</strong><br>
</p>
<h2>
お問い合わせ
</h2>
<p>
メンテナンスに関するお問い合わせは<a href="xxxxxxxx@gmail.com">xxxxxxxx@gmail.com</a>までお願いします。
</p>
<hr>
<div id="footer">
© 2021~2022
</div>
</div>
</body>
</html>
StatusCode: 503
Conditions:
- Field: path-pattern
Values:
- '*'
ListenerArn: !Ref ALBListenerHTTPS
Priority: 2
#5. 動作確認
とりあえずメンテナンスページを表示させたい。
しかし、作成時のリスナールールの順位だと、443の方にアクセスが流れてしまうため、リスナールールの順位を変更する必要があります。
作成したリスナールールの優先順位を入れ替えましょう。
参照:https://blog.serverworks.co.jp/alb-fixed-response
入れ替え後、ALBのDNS名へアクセスし、無事以下のような画面が表示されれば動作確認完了。
※ 1024文字だとこのレベルが限界(汗)
#6. まとめ
とても簡易的で便利な方法ですが、やはり1024文字制限が痛すぎる・・
個人利用レベルならともかく、現場で本番を想定したような場面には向かないでしょう。。