Application Load Balancer (ALB) のリスナー設定で「固定レスポンス」を使うと ALB から直接 HTML を返せる❗️
「固定レスポンス」は2018年7月頃にリリースされていて,さらに2019年3月頃にリリースされた「高度なリクエストルーティング(送信元 IP アドレスなど)」と組み合わせたメンテナンス画面の仕組みを使うことがある✌️過去に NGINX の rewrite
で頑張ってメンテナンス画面を制御してた経験があるからこそ便利に感じるのかも〜 \( 'ω')/
設定
最終的には要件次第ではあるけど,個人的によく使っている設定を単純化したサンプルを載せる👇
通常時は Forward
(優先度 1)ですべてのリクエストをターゲットグループ(アプリケーション)に転送する.そして Maintenance Bypass
(優先度 101)と Maintenance
(優先度 102)は使わずとも設定としては仕込んでおく✔️
そしてメンテナンス時は以下のように優先度を更新すれば OK👌
Forward
: 優先度 1 → 優先度 101Maintenance Bypass
: 優先度 101 → 優先度 1Maintenance
: 優先度 102 → 優先度 2
AWS CLI で優先度を更新するなら aws elbv2 set-rule-priorities
コマンドを使えば簡単❗️
$ FORWARD=xxx $ BYPASS=yyy $ MAINTENANCE=xxx # メンテナンス ON $ aws elbv2 set-rule-priorities --rule-priorities \ RuleArn=${BYPASS},Priority=1 \ RuleArn=${MAINTENANCE},Priority=2 \ RuleArn=${FORWARD},Priority=101 # メンテナンス OFF $ aws elbv2 set-rule-priorities --rule-priorities \ RuleArn=${FORWARD},Priority=1 \ RuleArn=${BYPASS},Priority=101 \ RuleArn=${MAINTENANCE},Priority=102
ちなみにメンテナンス画面を表示する "だけ" なら固定レスポンスを返す Maintenance
があれば十分だけど,運用面を考えると管理者はメンテナンス中にも動作確認をする必要があるため「送信元 IP アドレス(100.100.100.100/32
はサンプル)」によってメンテナンス画面を迂回できるように設定している❗️ちなみに IP ではなく「特定の HTTP ヘッダー」などでも実現できる👌
Terraform コード
キャプチャを載せたサンプルを Terraform で構築する場合は以下のリソースを使って設定できる.
- aws_lb | Resources | hashicorp/aws | Terraform | Terraform Registry
- aws_lb_listener | Resources | hashicorp/aws | Terraform | Terraform Registry
- aws_lb_listener_rule | Resources | hashicorp/aws | Terraform | Terraform Registry
- aws_lb_target_group | Resources | hashicorp/aws | Terraform | Terraform Registry
resource "aws_lb" "sandbox" { name = "sandbox" load_balancer_type = "application" drop_invalid_header_fields = true subnets = [ "subnet-xxxxxxxxxxxxxxxxx", "subnet-xxxxxxxxxxxxxxxxx" ] security_groups = [ "sg-xxxxxxxxxxxxxxxxx" ] } resource "aws_lb_listener" "sandbox" { load_balancer_arn = aws_lb.sandbox.arn port = "80" protocol = "HTTP" default_action { type = "forward" target_group_arn = aws_lb_target_group.sandbox.arn } } resource "aws_lb_listener_rule" "forward" { listener_arn = aws_lb_listener.sandbox.arn priority = 1 condition { path_pattern { values = ["*"] } } action { type = "forward" target_group_arn = aws_lb_target_group.sandbox.arn } tags = { name = "Forward" } } resource "aws_lb_listener_rule" "bypass" { listener_arn = aws_lb_listener.sandbox.arn priority = 101 condition { source_ip { values = ["100.100.100.100/32"] } } action { type = "forward" target_group_arn = aws_lb_target_group.sandbox.arn } tags = { name = "Maintenance Bypass" } } resource "aws_lb_listener_rule" "maintenance" { listener_arn = aws_lb_listener.sandbox.arn priority = 102 condition { path_pattern { values = ["*"] } } action { type = "fixed-response" fixed_response { content_type = "text/html" message_body = file("maintenance.html") status_code = "503" } } tags = { name = "Maintenance" } } resource "aws_lb_target_group" "sandbox" { name = "sandbox" vpc_id = "vpc-xxxxxxxxxxxxxxxxx" target_type = "ip" port = 80 protocol = "HTTP" }
maintenance.html
は適当に👀
<html> <head> <title>Under Maintenance</title> <style> body { font-family: Arial, sans-serif; text-align: center; padding: 50px; } </style> </head> <body> <h1>The site is currently undergoing maintenance.</h1> </body> </html>