CloudWatch Events で Sorry ページを切り替える

こんにちは、米須です。
このブログを開設して1年になりました。ちょっと忙しくて投稿が止まっていましたが、今後も色々なネタをお届けできたらと思っていますので、引き続きよろしくお願いします(^0^)ノ

さて、前回は ALB の「固定レスポンスアクション」を利用した Sorry ページの表示方法について説明しました。このままだとずっと Sorry ページが表示されてしまうので、CloudWatch Events を利用して特定の時間だけ Sorry ページが表示されるような仕組みを作ってみたいと思います。

今回の構成

下記の構成図にある赤い矢印の流れが今回構築するところです。
CloudWatch Events を利用して Lambda 関数を実行し、ALB に設定されているルールの優先度を変更することで、特定の時間だけ Sorry ページが表示されるようになります。

構成図

Lambda の設定

まずは Lambda から見ていきましょう。

ソース

主な流れは下記のとおりです。
  ① 環境変数からリスナーの ARN を取得
  ② リスナーの情報を取得
  ③ 変更対象のルールを判別
  ④ 優先度(Priority)を設定

import json
import boto3
import os

def lambda_handler(event, context):
    listener = os.environ['LISTENER_ARN'] 
    client = boto3.client('elbv2') 

    # 現在のルールのプロパティを確認 
    result = client.describe_rules(ListenerArn=listener, )

    for rule in result['Rules']:
        rule_arn = rule['RuleArn']
        priority = rule['Priority']
        type = rule['Actions'][0]['Type']

        #fixed-response タイプのルールが存在したら、優先度を変更する
        if type == "fixed-response": 
            if priority == "1": 
                set_priority = 99 
            else: 
                set_priority = 1

            client.set_rule_priorities(
                RulePriorities=[{'RuleArn': rule_arn, 'Priority': set_priority},]
            )

① 環境変数からリスナーの ARN を取得

リスナーの ARN はロードバランサーのリスナータブで取得できます。下記の赤枠にある▼を押すと表示されるので、丸ごとコピーします。

ALBリスナー

コピーした内容は Lambda の設定タブにある環境変数に設定します。今回はキー名を「LISTENER_ARN」としており、プログラムの中で
   listener = os.environ['LISTENER_ARN’]
とすることで取得できます。

Lambda環境変数

② リスナーの情報を取得

① でリスナーの ARN が取得できたので、下記のようにしてリスナーの情報を取得します。
   result = client.describe_rules(ListenerArn=listener, )

[boto3 ドキュメント]
describe_rules
https://boto3.amazonaws.com/v1/documentation/api/1.9.42/reference/services/elbv2.html#ElasticLoadBalancingv2.Client.describe_rules

このメソッドにより取得できるデータは、上記ドキュメントの Returns を見ると分かります。

③ 変更対象のルールを判別

今回の仕組みのポイントは、「どうやって Sorry ページを設定しているルールを判別するか」という点にあると思います。② で取得した情報の中から判別に使えそうな項目を探すのですが、「固定レスポンスアクション」を設定しているルールは1つしかなかったので、type が 「fixed-response」かどうかで判別することにしました。
(今考えると、ルールの ARN もあるので、それを利用するという手もあると思います)

④ 優先度(Priority)を設定

対象のルールが判別できたら、set_rule_priorities メソッドを使用してルールの優先度を設定します。

[boto3 ドキュメント]
set_rule_priorities
https://boto3.amazonaws.com/v1/documentation/api/1.9.42/reference/services/elbv2.html#ElasticLoadBalancingv2.Client.set_rule_priorities

ここで注意点が2つあります。

【 注意点1 】
ALB のルール設定画面において赤枠部分に数字が表示されていますが、これは優先度ではありません。ただの順番です。実際の優先度は ② で取得したデータの「Priority」の項目から取得できます。(画面上では確認できないっぽいです)

ALBルール

マネコンからルールを作成したり削除したりしていると各ルールの優先度に何が設定されているか分からなくなるので、プログラム内で設定する優先度は 1 or 99 にしました。(ルールを全部舐めて優先度を設定するのがちょっと面倒だったので、1 or 99 なら一番前か一番後ろになるだろうという安易な考えです(^^;)

【 注意点2 】
下記画像で説明したいのですが、1つ目のルール(ARN の末尾が b3a45)の優先度が2、2つ目のルール(ARN の末尾が 06006)の優先度が 99 になっていたとします。この状態でマネコンから1つ目のルールを2つ目のルールの下に来るよう順番を入れ替えると、2つめのルールの優先度である 99 より大きい値(100)が設定されます。

ALBルール

プログラムの中では 1 or 99 として設定しているので、こうなってしまうと何度 Lambda を実行しても通常のサイトを表示するルールと「固定レスポンスアクション」を設定しているルールは入れ替わらなくなってしまいます。優先度を 1 or 99 と決め打ちで設定するようなプログラムにする場合は、マネコンでルールを変更しないようにしましょう(^^;

IAM ロールの設定

プログラムができたら、Lambda が実行できるよう IAM ロールを設定します。
describe_rules メソッドと set_rule_priorities メソッドを使っているので、忘れずに下記の権限を追加しておきましょう。

  elasticloadbalancing:DescribeRules
  elasticloadbalancing:SetRulePriorities

ここまで出来たら Lambda のテスト機能を使って動作確認してみてください。

CloudWatch Events の設定

動作確認ができたら、CloudWatch Events でルールを作成します。
  スケジュールの Cron式:通常のページから Sorry ページへ切り替える時間を設定
  Lambda 関数:今回作成した Lambda を指定

CloudWatch Events

同様に、Sorry ページから通常のページへ切り替える時間を設定したルールをもう一つ作ると、Sorry ページを切り替えられる仕組みが完成します。

さいごに

若干決め打ちな所はありますが、夜間 EC2 を止めても Sorry ページが表示できるなんて、クラウドならではの構成ですよね。
ではまた。