構成

この自動フェイルオーバー・ソリューションをデプロイするには、ロード・バランサの構成、アラームと通知の設定、ファンクションの作成、およびOCI APIゲートウェイの構成を行う必要があります。

次のステップを詳しく説明します。

  1. プロセスは、ロード・バランサの準備から始まります。ロード・バランサでは、セカンダリ・リスナーと、リダイレクション動作を制御する特定のルール・セットを設定する必要があります。
  2. これに続いて、アプリケーション・サーバーがすべて異常ステータスで、正常なサーバーが使用可能になるときにアクションをトリガーするアラームおよび通知を構成します。
  3. 次に、OCI関数を使用してオークションをデプロイすることでコア自動化を有効にします。これにより、現在のアラーム状態に基づいてロード・バランサのルール・セットの添付またはデタッチがプログラムによって制御されます。
  4. 最後に、カスタムの静的メンテナンス・ページをホストするようにOCI APIゲートウェイを構成します。

これらの各構成は、フレンドリなメンテナンス・ページへのシームレスで自動化されたフェイルオーバーを実現する上で、特定の統合された役割を果たします。

ロード・バランサの構成

このソリューションの基盤はロード・バランサにあります。ロード・バランサはすでにアプリケーションに向かっており、バックエンド・サーバーにトラフィックを分散しています。これらのステップでは、アプリケーション・リスナー(HTTPまたはHTTPS)、ヘルス・チェックが構成されたバックエンド・セット、ユーザーがサービスにアクセスできるようにインターネット・ゲートウェイを介したルーティングなど、ほとんどのデプロイメント前提条件がすでに整っていることを前提としています。

ロード・バランサのプライマリ・リスナーから開始し、アプリケーションへの通常のトラフィックを処理するように構成します。すべてが正常に動作している場合、このリスナーは受信リクエストをVMインスタンスのバックエンド・セットにルーティングします。標準ポート(HTTP/80またはHTTPS/443)でリスニングし、ヘルス・チェックによって、正常なVMのみがトラフィックを受信することが保証されます。

メンテナンス・ページを表示するには、ロード・バランサに2番目のリスナーを追加します。アプリケーション・リスナーとは異なり、このリスナーはアプリケーション・サーバーにリクエストを転送しません。かわりに、バックエンド・セットは、静的エラー・ページをホストするOCI APIゲートウェイ・インスタンスを指します。この分離により、すべてのアプリケーション・サーバーが停止している場合でも、ロード・バランサは高可用性API Gatewayを介してブランド化された有益なメンテナンス・ページを引き続き表示できます。セカンダリ・リスナーおよびAPIゲートウェイ・ステップの作成はオプションです。メンテナンス・ページはインターネット上の任意の場所にホストできます。

この2つのリスナー間のハンドオフは、ルール・セットを介して管理されます。ルール・セットはアプリケーション・リスナーにアタッチされ、トラフィックをリダイレクトする条件を定義します。通常の状況では、リスナーはトラフィックをアプリケーション・サーバーに直接送信します。ただし、アプリケーション・サーバーがヘルス・チェックに失敗すると、ルール・セットが有効になります。ロード・バランサに、トラフィックをメンテナンス・リスナーにリダイレクトするように指示します。メンテナンス・リスナーは、APIゲートウェイでホストされているカスタム・ページを処理します。

次のステップでは、ユーザーをメンテナンス・ページにリダイレクトするために使用されるルール・セットを作成する方法について説明します。

  1. OCIコンソールで、「ネットワーキング」「ロード・バランサ」の順に選択し、ロード・バランサを選択します。
  2. 「ルール・セット」「ルール・セットの作成」の順に選択します。次の値を使用します。
    • 名前: (ルール・セットに名前を付けます)
    • URLリダイレクト・ルール:
      • 条件: 「パス」PREFIX_MATCHを選択し、値を/に設定します。これは、ロード・バランサに到達するすべてのリクエストと一致します。
      • 処置: URLリダイレクト・ルールで、「リダイレクト」を選択します
    • プロトコル: https (またはhttp)を選択します。
    • ホスト: リダイレクション・ターゲットのURLを入力します
    • パス: /に設定します
    • レスポンス・コード: 307- temporary redirect

アラームについて

アラームは、検出とアクションの間のブリッジとして機能します。

OCI Monitoringは、ロード・バランサを含むデプロイメントのコンポーネントのヘルス・メトリック(バックエンド・セットのVMのステータスを含む)をリスニングします。OCIアラームで構成したアラーム条件が満たされると(たとえば、監視対象のすべての仮想マシンが1分以上異常になるなど)、ただちに通知がトリガーされます。この通知は、人事部門担当者だけのものではありません。OCI通知を介してルーティングし、OCIファンクションでデプロイされたカスタム・ファンクションを起動できます。この関数は、カスタム・エラー・ページを表示するようにロード・バランサ構成を変更します。

関数に送信される通知メッセージには、ディメンション(メトリック・イベントが属するリソースのバックエンド・セットおよびVMのバックエンド・セットを示すキーと値のペア)が含まれます。

アラーム構成の本文には、次のコードが含まれます。

{{dimensions.resourceId}},{{dimensions.backendSetName}},<name of the ruleset>

次の表では、このアラーム本体のコンポーネントについて説明します。

要素 説明 目 的
{{dimensions.resourceId}} メトリック・イベントを生成したロード・バランサ・リソースのOCID このOCIDを使用して、ルール・セットの更新が必要なロード・バランサを識別します
{{dimensions.backendSetName}} 異常終了したバックエンド・セットの名前 このファンクションは、失敗したバックエンド・セットを検証またはログに記録できます。複数のバックエンド・セットがある動的環境に役立ちます。
<name of the ruleset> 静的値(文字列)— すべてのバックエンドが異常な場合にアタッチされるルール・セットの名前 トリガー時に適用するルール・セットをファンクションに知らせます。

この設計では、同じ機能を再利用して、ロード・バランサを構成してサーバー・メンテナンス・ページを表示したり、サービスのリストア後にトラフィックを実際のアプリケーションにルーティングするなどのタスクを処理できます。このアプローチを適用して、OCIデプロイメント全体のロード・バランサ上のすべてのロード・バランサまたはアプリケーションを管理することもできます。

OCIロード・バランサ・サービスは、ネームスペースoci_lbaasUnhealthybackendserverというメトリックを自動的に公開します。各バックエンド・セット内の異常なバックエンドの数を追跡します。

この解答のために、このメトリックの重要な項目は次のとおりです。

  • 説明
  • サイズ
  • トラルール
  • メッセージのグループ分け

このソリューションでは、すべてのバックエンド・サーバー(VM)が異常になると、アラームがトリガーされます。つまり、異常なサーバー数は、セット内のバックエンド・サーバーの合計数以上である必要があります。

アラーム・トリガー・ルール問合せの例を次に示します。

UnHealthyBackendServers[1m]{lbName = <name of lb>, backendSetName = <name of the backend set>}.max() >= 1

この問合せは、次のように変換されます。

  • 異常なバックエンドの最大数が特定の値以上である場合(この例では1)
  • 定義された1分間の期間。
  • その後、アラームはFIRING状態に遷移します。

ただし、この値の動的移入は、メッセージ・グループ化で「分割通知」が有効になっている場合にのみ機能します。分割通知では、すべてのものをグループ化するのではなく、OCIでディメンション値ごとに1つの通知が送信されます。このため、カスタム関数に到達するアラーム通知には、正確なロード・バランサのOCIDと、障害が発生した正確なバックエンド・セット名が含まれます。その結果、ロード・バランサの詳細をハードコードすることなく、同じ機能が複数のロード・バランサ、バックエンド・セットまたは環境で完全に再利用可能になります。

この構成により、自動化チェーン全体が機能できます。アラームは動的コンテキストを公開し、関数がそれを読み取り、エンド・ユーザーにアプリケーションにサービスを提供している正確なリスナーに対して正しいルールセット・アタッチメントを実行します。

アラームおよび通知の構成

このソリューションのアラームおよび通知を構成するには、次のステップを実行します。

  1. OCIコンソールで、「監視および管理」に移動し、「監視」を選択して、「アラーム・ステータス」を選択します。
  2. 「アラームの作成」を選択します。「アラーム名」フィールドで、アラームの名前を作成します。
  3. 「メトリック」に値を入力します。
    • コンパートメント: <ロード・バランサが存在するコンパートメントを選択します>
    • メトリック・ネームスペース: oci_lbaas
    • メトリック名: <UnhealthyBackendServers>を選択します。
    • 間隔: <ポーリング間隔の頻度>
    • 統計: Max
    • メトリック・ディメンション:
      • ディメンション名: <ロード・バランサ名を選択します>
      • ディメンション値: <バックエンド・セットの名前を選択します>
  4. 次の値を使用してトリガー・ルールを作成します:
    • 演算子: ≥(大きい方または等しい記号)
    • : <バックエンド・セットのバックエンド・サーバーの合計数>
    • トリガー遅延分数: <アラームをトリガーするまでの時間遅延分数>
  5. 「Set Severity」をアラートの目的の重大度に設定します。
  6. 「アラーム本体」{{dimensions.resourceId}},{{dimensions.backendSetName}},<ruleset name>を設定します。
  7. 次の値を使用してアラーム通知を定義します。
    • 宛先サービス: notification
    • コンパートメント: サービスを含むコンパートメントを選択します
    • トピック: <通知のトピックの名前>
    • メッセージのグループ化: Split notifications per metric stream
    • メッセージ形式: Send formatted messages
新しいアラームを作成したら、コンソールでアラームを有効にします。

ファンクションの作成

自動化の中心には、すべてのアプリケーション・バックエンドが異常であることがアラームによって検出されるたびにトリガーされる機能があります。

ファンクションのロールはシンプルですが強力です。トラフィック・リダイレクションを処理するルール・セットをアタッチまたはデタッチすることで、ロード・バランサ構成を動的に更新します。

関数内の Pythonコードは、次の3つの論理ステップに従います。

  • OCIによる認証: このファンクションは、リソース・プリンシパルを使用してOCIとのセキュアなセッションを確立することから始まります(このようにして、OCIのファンクションは、キーを手動で管理せずに他のOCIサービスをコールできます)。これにより、コードがロード・バランサ・サービスと安全に対話できるようになります。認証の詳細は、「詳細」のリンクを参照してください。
  • ロード・バランサ・リスナーを変更するAPIコール: 認証されると、コードによってロード・バランサAPIがコールされます。
    • バックエンドが失敗した場合、この関数はリダイレクト・ルール・セットをアプリケーション・リスナーにアタッチし、ユーザーをカスタム・エラー・ページにリダイレクトします。
    • バックエンドがリカバリされると、関数はルール・セットをデタッチし、通常のトラフィック・フローをアプリケーション・サーバーにリストアします。
  • ロギングおよび検証: このコードには単純なロギングも含まれているため、管理者は実行されたアクション(たとえば、「listener-1に設定されたアタッチされたメンテナンス・ページ・ルール」)を追跡できます。これは、トラブルシューティングまたは監査時に非常に役立ちます。

次のPythonコードの例を使用して、Oracle Functionsでファンクションを作成し、必要に応じて変更します。

Function.py

import io
import json
import os
import oci
from fdk import response
import logging

def handler(ctx, data: io.BytesIO=None):
    message = "start of function"
    logging.getLogger().info("HTTP function start")
    try:
        payload_bytes = data.getvalue()
        if payload_bytes == b'':
            raise KeyError('No keys in payload')
        body1 = json.loads(payload_bytes)
        type1 = body1["type"]
        query = body1["body"]
        load_balancer_ocid = query.split(",")[0]
        maintenance = query.split(",")[2]
        signer = oci.auth.signers.get_resource_principals_signer()
        load_balancer_client = oci.load_balancer.LoadBalancerClient(config={}, signer=signer)
        load_balancer_client_composite_ops = oci.load_balancer.LoadBalancerClientCompositeOperations(load_balancer_client)
        load_balancer_data = json.loads(str(load_balancer_client.get_load_balancer(load_balancer_ocid).data))
        lb_config = load_balancer_data['listeners']
        list1 = json.dumps(lb_config)
        for key,value in json.loads(list1).items():
            if value['default_backend_set_name'] == query.split(",")[1]:
                f_list = key
                rulesets = value['rule_set_names']
                if type1=="OK_TO_FIRING":
                    message = "FIRE"
                    if maintenance in rulesets:
                        message = "Already in Maintenance Mode"
                        logging.getLogger().info("Already in Manintenance mode")
                    else:
                        rulesets.insert(0, maintenance)
                        message = "Entering Maintenance Mode"
                        logging.getLogger().info("Entering Main mode")
                        load_balancer_client_composite_ops.update_listener_and_wait_for_state(
                            oci.load_balancer.models.UpdateListenerDetails(
                                default_backend_set_name=value["default_backend_set_name"],
                                rule_set_names=rulesets,
                                port=value["port"],
                                protocol=value["protocol"],
                                ssl_configuration=value["ssl_configuration"]
                            ),
                            load_balancer_ocid,
                            key,
                            wait_for_states=[oci.load_balancer.models.WorkRequest.LIFECYCLE_STATE_SUCCEEDED]
                        )
                elif type1=="FIRING_TO_OK":
                    message = "OK"
                    if maintenance in rulesets:
                        message = "Entering Operation Mode"
                        logging.getLogger().info("Entering Operation Mode")
                        rulesets.remove(maintenance)
                        load_balancer_client_composite_ops.update_listener_and_wait_for_state(
                            oci.load_balancer.models.UpdateListenerDetails(
                                default_backend_set_name=value["default_backend_set_name"],
                                rule_set_names=rulesets,
                                port=value["port"],
                                protocol=value["protocol"],
                                ssl_configuration=value["ssl_configuration"]
                            ),
                            load_balancer_ocid,
                            key,
                            wait_for_states=[oci.load_balancer.models.WorkRequest.LIFECYCLE_STATE_SUCCEEDED]
                        )   

                    else:
                        message = "Already in operation Mode"
                        logging.getLogger().info("Already in Operation mode")


    except (Exception) as ex:
       message = "Error:" + str(ex)

    return message

OCI APIゲートウェイの構成

このソリューションでは、OCI APIゲートウェイが静的Webページに直接対応するように構成されています。

ノート:

OCI API Gatewayの使用はオプションです。OCIの外部でメンテナンス/エラー・ページをホストすることもできます。

リクエストが関数やコンピュート・インスタンスなどの動的バックエンドにルーティングされるOCI APIゲートウェイの一般的な使用とは異なり、このアプローチでは、OCI APIゲートウェイの静的レスポンスをホストする機能を利用します。この静的ページはわかりやすいメンテナンス・メッセージとして機能し、スケジュールされたメンテナンスまたはその他の問題のためにサービスが一時的に使用できないことをユーザーに通知します。静的ページは、OCI API Gatewayによって完全に管理されるため、Webサーバーやオブジェクト・ストレージなどの追加のインフラストラクチャが不要になります。

すべてのバックエンド・サーバーが異常であることが検出されると、アラームによってトリガーされる関数は、OCI APIゲートウェイ・インスタンスのフロントエンドでトラフィックをセカンダリ・リスナーにリダイレクトするようにロード・バランサを構成することで応答し、デフォルトのエラー・ページを公開せずにシームレスで使いやすいエクスペリエンスを実現します。

この例では、OCI APIゲートウェイを使用して静的レスポンスを構成するために必要なステップのみに焦点を当てています。詳細は、Explore Moreのリソースを参照してください。

  1. OCIコンソールで、ゲートウェイに移動し、ゲートウェイを開いて「デプロイメント」を選択し、「デプロイメントの作成」を選択します。
  2. 「新規APIの作成」を選択します。
  3. 基本情報を構成します:
    • 名前: webpage
    • パス接頭辞: /
    • コンパートメント: ゲートウェイと同じコンパートメントを使用します

    残りのオプションはデフォルト値のままにします。

  4. 「認証」を構成します。
    デフォルトの構成を使用できます。
  5. ルートを構成します:
    • パス: /{req*} (ワイルドカード一致)
    • メソッド: GET
    • 「編集」をクリックして、単一のバックエンドを追加します。
    • バックエンド・タイプ: Stock response
    • ステータス・コード: 200
    • 本文: <メンテナンス・ページのHTMLコンテンツ>
    • ヘッダー名: content-type
    • ヘッダー値: text/html