前提

・AWS CLIがインストールされて、初期設定が完了できていること
・実行OS:RedhatLinux 8.2
・jqがインストールされていること
・ALBが作成されていること
・EC2AutoScalingが作成されていること

※下記の記事を参考
AWS CloudFormationでALBを作成してみました(CLI)

AWS CloudFormationでEC2AutoScalingを作成してみました(CLI)

概要

Web サイトを運用するケースでメンテナンスやサーバーの障害が発生した時に Sorry ページを返したいという要件ってよくあると思います。
AWSコンソール上で手動でもルールの優先順位を変更できますが、今回はシェルを作って自動化したいと思います。

使い分け

通常時

・ルール:[HTTPSリスナールール1]のルールを使います。
・シェル:ALB閉塞(AlbBlockSorryPage.sh)

障害時

・ルール:[HTTPSリスナールール2]のルールを使います。
・シェル:ALB閉塞解除(AlbReleaseSorryPage.sh)

ALB初期構築の設定

ALB初期構築時、各HTTPSリスナールールのPriority値を下記のように設定します。
HTTPSリスナールール1:業務アプリページのPriority値:200
HTTPSリスナールール2:SorryページのPriority値:900
HTTPSリスナールール3:業務アプリページのPriority値:default(デフォルトトールのため、変更・削除できません)

ALB閉塞時の設定

ALB閉塞時、HTTPSリスナールール2のみを下記のように変更します。
HTTPSリスナールール2:SorryページのPriority値:900 ⇒ 100

ALB閉塞解除時の設定

ALB閉塞解除時、HTTPSリスナールール2のみを下記のように変更します。
HTTPSリスナールール2:SorryページのPriority値:100 ⇒ 900

閉塞シェル

ファイル名:AlbBlockSorryPage.sh

ファイル名内容

#!/bin/bash
############################################################################
## 事前準備 
#    実行ユーザ:root
#     引数例:ALBのName
#          cpi-dev-alb-test01
###############################################
#環境変数
OK_HTTPS_LISTENER_NUM=3
SET_SORRY_PRIORITY_VAL=100

#シェルの引数チェック
if [ $# -ne 1 ]; then
    echo "usage:" "`basename $0` <ALBのNameタグ>"
    exit
fi

#シェルの戻り値
status=0

echo L_ALB_NAME:"${1}"

#処理対象ALBのNameで単語マッチして、結果をファイルに出力
GET_ALB_ARN_CMD="/usr/local/bin/aws elbv2 describe-load-balancers | jq -r '.LoadBalancers[].LoadBalancerArn' | grep -w "${1}""
echo GET_ALB_ARN_CMD:"${GET_ALB_ARN_CMD}"

#GET_ALB_ARN_CMDを実行し、ALB_ARNを取得
ALB_ARN="$(eval "${GET_ALB_ARN_CMD}")"
echo ALB_ARN:"${ALB_ARN}"

#ALB_ARNの文字数を取得(echo -n改行を除く)
ALB_ARN_LENGTH=`echo -n "${ALB_ARN}" | wc -c`
echo ALB_ARN_LENGTH:"${ALB_ARN_LENGTH}"

if [ "${ALB_ARN_LENGTH}" -eq 0 ]; then
    status=1
    echo "###### error:"${1}" が存在しておりません。######"
else
    echo "###### info:"${1}" が存在しているので、後続処理を行います。######"

    #HTTPSのリスナーARNを取得
    HTTPS_LISTENER_ARN=`/usr/local/bin/aws elbv2 describe-listeners --load-balancer-arn "${ALB_ARN}" | jq -r '.Listeners | map({ListenerArn: .ListenerArn, Protocol: .Protocol})' | jq [.[]] | jq 'map(select(.Protocol == "HTTPS"))' | jq -r .[0].ListenerArn`
    echo HTTPS_LISTENER_ARN:"${HTTPS_LISTENER_ARN}"

    #SorryページのRuleArnを取得
    HTTPS_LISTENER_SORRY_RULE_ARN=`/usr/local/bin/aws elbv2 describe-rules --listener-arn "${HTTPS_LISTENER_ARN}" | jq '.Rules | map({RuleArn: .RuleArn, Priority: .Priority, Type: .Actions[].Type})' | jq 'map(select( .Type == "fixed-response" ))' | jq -r .[].RuleArn`
    echo HTTPS_LISTENER_SORRY_RULE_ARN:"${HTTPS_LISTENER_SORRY_RULE_ARN}"

    #SorryページのPriorityを取得
    HTTPS_LISTENER_SORRY_PRIORITY_VAL=`/usr/local/bin/aws elbv2 describe-rules --listener-arn "${HTTPS_LISTENER_ARN}" | jq '.Rules | map({RuleArn: .RuleArn, Priority: .Priority, Type: .Actions[].Type})' | jq 'map(select( .Type == "fixed-response" ))' | jq -r .[].Priority`
    echo HTTPS_LISTENER_SORRY_PRIORITY_VAL:"${HTTPS_LISTENER_SORRY_PRIORITY_VAL}"

    #HTTPSのリスナーの数を取得
    GET_HTTPS_LISTENER_NUM=`/usr/local/bin/aws elbv2 describe-rules --listener-arn "${HTTPS_LISTENER_ARN}" | jq '.Rules | map({RuleArn: .RuleArn, Priority: .Priority, Type: .Actions[].Type})' | jq '[.[]] | length'`
    echo GET_HTTPS_LISTENER_NUM:"${GET_HTTPS_LISTENER_NUM}"

    #HTTPSのリスナーの数が正しい場合、ALBの閉塞処理を行う
    if [ "${GET_HTTPS_LISTENER_NUM}" -eq "${OK_HTTPS_LISTENER_NUM}" ]; then
        #SorryページのPriorityが100の場合
        if [ "${HTTPS_LISTENER_SORRY_PRIORITY_VAL}" -eq "${SET_SORRY_PRIORITY_VAL}" ]; then
            echo "info:ALB["${1}"]が既に閉塞されているため、閉塞対象がありません"
            echo status:"${status}"
        else
            echo "info:ALB["${1}"]の閉塞処理を行います"
            echo "info:ALB["${1}"]SorryページのPriorityを["${SET_SORRY_PRIORITY_VAL}"]に設定します"

            #設定処理
            /usr/local/bin/aws elbv2 set-rule-priorities --rule-priorities RuleArn="${HTTPS_LISTENER_SORRY_RULE_ARN}",Priority="${SET_SORRY_PRIORITY_VAL}"  | jq '.Rules | map({RuleArn: .RuleArn, Priority: .Priority, Type: .Actions[].Type})'

            #再度、ALBのすべてのHTTPSのリスナーの確認
            ALB_ALL_HTTPS_LISTENER=`/usr/local/bin/aws elbv2 describe-rules --listener-arn "${HTTPS_LISTENER_ARN}" | jq '.Rules | map({RuleArn: .RuleArn, Priority: .Priority, Type: .Actions[].Type, Weight: .Actions[].ForwardConfig.TargetGroups})'`
            echo "info:ALB["${1}"]のすべてのHTTPSのリスナーは:"
            echo "${ALB_ALL_HTTPS_LISTENER}"
            echo status:"${status}"
        fi

    else
        echo "error:ALB["${1}"]のHTTPSのリスナーの数は正しくないため、ALBの閉塞処理を行いません。"
        echo "info:ALB["${1}"]の正しいHTTPSのリスナーの数は:""${OK_HTTPS_LISTENER_NUM}" 
        status=1
        echo status:"${status}"
    fi

    echo -n -e "\n"

fi

#終了処理:戻り値を返却
exit "${status}"

実行結果

sh AlbBlockSorryPage.sh cpi-dev-alb-test01
L_ALB_NAME:cpi-dev-alb-test01
GET_ALB_ARN_CMD:/usr/local/bin/aws elbv2 describe-load-balancers | jq -r '.LoadBalancers[].LoadBalancerArn' | grep -w cpi-dev-alb-test01
ALB_ARN:arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:loadbalancer/app/cpi-dev-alb-test01/802f650de750a132
ALB_ARN_LENGTH:109
###### info:cpi-dev-alb-test01 が存在しているので、後続処理を行います。######
HTTPS_LISTENER_ARN:arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:listener/app/cpi-dev-alb-test01/802f650de750a132/e24df0cbc7afe159
HTTPS_LISTENER_SORRY_RULE_ARN:arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:listener-rule/app/cpi-dev-alb-test01/802f650de750a132/e24df0cbc7afe159/1db7a04576e2b5e3
HTTPS_LISTENER_SORRY_PRIORITY_VAL:900
GET_HTTPS_LISTENER_NUM:3
info:ALB[cpi-dev-alb-test01]の閉塞処理を行います
info:ALB[cpi-dev-alb-test01]SorryページのPriorityを[100]に設定します
[
  {
    "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:listener-rule/app/cpi-dev-alb-test01/802f650de750a132/e24df0cbc7afe159/1db7a04576e2b5e3",
    "Priority": "100",
    "Type": "fixed-response"
  }
]
info:ALB[cpi-dev-alb-test01]のすべてのHTTPSのリスナーは:
[
  {
    "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:listener-rule/app/cpi-dev-alb-test01/802f650de750a132/e24df0cbc7afe159/1db7a04576e2b5e3",
    "Priority": "100",
    "Type": "fixed-response",
    "Weight": null
  },
  {
    "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:listener-rule/app/cpi-dev-alb-test01/802f650de750a132/e24df0cbc7afe159/80e1d5e9b6f8d1ca",
    "Priority": "200",
    "Type": "forward",
    "Weight": [
      {
        "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:targetgroup/cpi-tyo-tg-blue-green/72a168b9b13d6347",
        "Weight": 0
      },
      {
        "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:targetgroup/cpi-tyo-tg-blue/7ad7c69e06f22595",
        "Weight": 100
      }
    ]
  },
  {
    "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:listener-rule/app/cpi-dev-alb-test01/802f650de750a132/e24df0cbc7afe159/bf66598213462d9f",
    "Priority": "default",
    "Type": "forward",
    "Weight": [
      {
        "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:targetgroup/cpi-tyo-tg-blue/7ad7c69e06f22595",
        "Weight": 1
      }
    ]
  }
]
status:0

確認

EC2コンソール上で確認

Sorryページのルールが一番上に表示されます。

テストページをアクセスしてみる

Sorryページの内容が表示されます。

閉塞解除シェル

ファイル名:AlbReleaseSorryPage.sh

ファイル名内容

#!/bin/bash
############################################################################
## 事前準備 
#    実行ユーザ:root
#     引数例:ALBのName
#          cpi-dev-alb-test01
############################################################################
#環境変数
OK_HTTPS_LISTENER_NUM=3
SET_SORRY_PRIORITY_VAL=900

#シェルの引数チェック
if [ $# -ne 1 ]; then
    echo "usage:" "`basename $0` <ALBのNameタグ>"
    exit
fi

#シェルの戻り値
status=0

#処理対象ALBのNameで単語マッチして、結果をファイルに出力
GET_ALB_ARN_CMD="/usr/local/bin/aws elbv2 describe-load-balancers | jq -r '.LoadBalancers[].LoadBalancerArn' | grep -w "${1}""
echo GET_ALB_ARN_CMD:"${GET_ALB_ARN_CMD}"

#GET_ALB_ARN_CMDを実行し、ALB_ARNを取得
ALB_ARN="$(eval "${GET_ALB_ARN_CMD}")"
echo ALB_ARN:"${ALB_ARN}"

#ALB_ARNの文字数を取得(echo -n改行を除く)
ALB_ARN_LENGTH=`echo -n "${ALB_ARN}" | wc -c`
echo ALB_ARN_LENGTH:"${ALB_ARN_LENGTH}"

if [ "${ALB_ARN_LENGTH}" -eq 0 ]; then
    status=1
    echo "###### error:"${1}" が存在しておりません。######"
else
    echo "###### info:"${1}" が存在しているので、後続処理を行います。######"

    #HTTPSのリスナーARNを取得
    HTTPS_LISTENER_ARN=`/usr/local/bin/aws elbv2 describe-listeners --load-balancer-arn "${ALB_ARN}" | jq -r '.Listeners | map({ListenerArn: .ListenerArn, Protocol: .Protocol})' | jq [.[]] | jq 'map(select(.Protocol == "HTTPS"))' | jq -r .[0].ListenerArn`
    echo HTTPS_LISTENER_ARN:"${HTTPS_LISTENER_ARN}"

    #SorryページのRuleArnを取得
    HTTPS_LISTENER_SORRY_RULE_ARN=`/usr/local/bin/aws elbv2 describe-rules --listener-arn "${HTTPS_LISTENER_ARN}" | jq '.Rules | map({RuleArn: .RuleArn, Priority: .Priority, Type: .Actions[].Type})' | jq 'map(select( .Type == "fixed-response" ))' | jq -r .[].RuleArn`
    echo HTTPS_LISTENER_SORRY_RULE_ARN:"${HTTPS_LISTENER_SORRY_RULE_ARN}"

    #SorryページのPriorityを取得
    HTTPS_LISTENER_SORRY_PRIORITY_VAL=`/usr/local/bin/aws elbv2 describe-rules --listener-arn "${HTTPS_LISTENER_ARN}" | jq '.Rules | map({RuleArn: .RuleArn, Priority: .Priority, Type: .Actions[].Type})' | jq 'map(select( .Type == "fixed-response" ))' | jq -r .[].Priority`
    echo HTTPS_LISTENER_SORRY_PRIORITY_VAL:"${HTTPS_LISTENER_SORRY_PRIORITY_VAL}"

    #二つ目のHTTPSのリスナーのPriorityを取得
    HTTPS_LISTENER_SECOND_PRIORITY_VAL=`/usr/local/bin/aws elbv2 describe-rules --listener-arn "${HTTPS_LISTENER_ARN}" | jq '.Rules | map({RuleArn: .RuleArn, Priority: .Priority, Type: .Actions[].Type})' | jq -r .[1].Priority`
    echo HTTPS_LISTENER_SECOND_PRIORITY_VAL:"${HTTPS_LISTENER_SECOND_PRIORITY_VAL}"

    #HTTPSのリスナーの数を取得
    GET_HTTPS_LISTENER_NUM=`/usr/local/bin/aws elbv2 describe-rules --listener-arn "${HTTPS_LISTENER_ARN}" | jq '.Rules | map({RuleArn: .RuleArn, Priority: .Priority, Type: .Actions[].Type})' | jq '[.[]] | length'`
    echo GET_HTTPS_LISTENER_NUM:"${GET_HTTPS_LISTENER_NUM}"

    #HTTPSのリスナーの数が正しい場合、ALBの閉塞処理を行う
    if [ "${GET_HTTPS_LISTENER_NUM}" -eq "${OK_HTTPS_LISTENER_NUM}" ]; then
        #SorryページのPriorityが、二つ目のHTTPSのリスナーのPriorityより小さい場合
        if [ "${HTTPS_LISTENER_SORRY_PRIORITY_VAL}" -lt "${HTTPS_LISTENER_SECOND_PRIORITY_VAL}" ]; then
            echo "info:ALB["${1}"]閉塞解除処理を行います。"
            echo "info:ALB["${1}"]SorryページのPriorityを["${SET_SORRY_PRIORITY_VAL}"]に設定します"

            #設定処理
            /usr/local/bin/aws elbv2 set-rule-priorities --rule-priorities RuleArn="${HTTPS_LISTENER_SORRY_RULE_ARN}",Priority="${SET_SORRY_PRIORITY_VAL}"  | jq '.Rules | map({RuleArn: .RuleArn, Priority: .Priority, Type: .Actions[].Type})'

            #再度、ALBのすべてのHTTPSのリスナーの確認
            ALB_ALL_HTTPS_LISTENER=`/usr/local/bin/aws elbv2 describe-rules --listener-arn "${HTTPS_LISTENER_ARN}" | jq '.Rules | map({RuleArn: .RuleArn, Priority: .Priority, Type: .Actions[].Type, Weight: .Actions[].ForwardConfig.TargetGroups})'`
            echo "info:ALB["${1}"]のすべてのHTTPSのリスナーは:"
            echo "${ALB_ALL_HTTPS_LISTENER}"

            echo status:"${status}"

        else
            echo "info:ALB["${1}"]は既に解除されているため、解除対象がありません。"
            echo status:"${status}"
        fi

    else
        echo "error:ALB["${1}"]のHTTPSのリスナーの数は正しくないため、ALBの閉塞処理を行いません。"
        echo "info:ALB["${1}"]の正しいHTTPSのリスナーの数は:""${OK_HTTPS_LISTENER_NUM}" 
        status=1
        echo status:"${status}"
    fi

    echo -n -e "\n"

fi

#終了処理:戻り値を返却
exit "${status}"

実行結果

sh AlbReleaseSorryPage.sh cpi-dev-alb-test01
GET_ALB_ARN_CMD:/usr/local/bin/aws elbv2 describe-load-balancers | jq -r '.LoadBalancers[].LoadBalancerArn' | grep -w cpi-dev-alb-test01
ALB_ARN:arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:loadbalancer/app/cpi-dev-alb-test01/802f650de750a132
ALB_ARN_LENGTH:109
###### info:cpi-dev-alb-test01 が存在しているので、後続処理を行います。######
HTTPS_LISTENER_ARN:arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:listener/app/cpi-dev-alb-test01/802f650de750a132/e24df0cbc7afe159
HTTPS_LISTENER_SORRY_RULE_ARN:arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:listener-rule/app/cpi-dev-alb-test01/802f650de750a132/e24df0cbc7afe159/1db7a04576e2b5e3
HTTPS_LISTENER_SORRY_PRIORITY_VAL:100
HTTPS_LISTENER_SECOND_PRIORITY_VAL:200
GET_HTTPS_LISTENER_NUM:3
info:ALB[cpi-dev-alb-test01]閉塞解除処理を行います。
info:ALB[cpi-dev-alb-test01]SorryページのPriorityを[900]に設定します
[
  {
    "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:listener-rule/app/cpi-dev-alb-test01/802f650de750a132/e24df0cbc7afe159/1db7a04576e2b5e3",
    "Priority": "900",
    "Type": "fixed-response"
  }
]
info:ALB[cpi-dev-alb-test01]のすべてのHTTPSのリスナーは:
[
  {
    "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:listener-rule/app/cpi-dev-alb-test01/802f650de750a132/e24df0cbc7afe159/80e1d5e9b6f8d1ca",
    "Priority": "200",
    "Type": "forward",
    "Weight": [
      {
        "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:targetgroup/cpi-tyo-tg-blue-green/72a168b9b13d6347",
        "Weight": 0
      },
      {
        "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:targetgroup/cpi-tyo-tg-blue/7ad7c69e06f22595",
        "Weight": 100
      }
    ]
  },
  {
    "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:listener-rule/app/cpi-dev-alb-test01/802f650de750a132/e24df0cbc7afe159/1db7a04576e2b5e3",
    "Priority": "900",
    "Type": "fixed-response",
    "Weight": null
  },
  {
    "RuleArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:listener-rule/app/cpi-dev-alb-test01/802f650de750a132/e24df0cbc7afe159/bf66598213462d9f",
    "Priority": "default",
    "Type": "forward",
    "Weight": [
      {
        "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:268673644828:targetgroup/cpi-tyo-tg-blue/7ad7c69e06f22595",
        "Weight": 1
      }
    ]
  }
]
status:0

確認

EC2コンソール上で確認

Sorryページのルールが一番上に表示されます。

テストページをアクセスしてみる

業務アプリページの内容が表示されます。

めとめ

ALB初期構築時、各HTTPSリスナールールのPriority値を検討しましょう。運用にあたっては優先度を変更フロー作成し、本番化する前のテストして想定の挙動かは確認するのが良いでしょう。
少しでもお役に立てれば幸いです。

+3
Last modified: 2021-05-30

Author