高可用性ガイド


Red Hat build of Keycloak 26.0

Red Hat Customer Content Services

概要

このガイドは、Red Hat build of Keycloak 26.0 を高可用性向けに設定および使用する方法に関する管理者向け情報が記載されています。

第1章 マルチサイトデプロイメント

Red Hat build of Keycloak は、Infinispan キャッシュを使用して相互に接続する複数の Red Hat build of Keycloak インスタンスで構成されるデプロイメントをサポートします。それらのインスタンス間でロードバランサーにより負荷を均等に分散できます。このようなセットアップは、1 つのサイトの透過的なネットワークを想定したものです。

Red Hat build of Keycloak 高可用性ガイドでは、さらに一歩進んで、複数のサイトにわたるセットアップを説明します。このようなセットアップでは複雑さがさらに増し、環境によっては高可用性が必要になる場合があります。

1.1. マルチサイト設定を使用する場合

Red Hat build of Keycloak のマルチサイトデプロイメント機能は、次のようなユースケースを対象としています。

  • 単一の AWS リージョンに制限される。
  • メンテナンスのための計画的な停止を許可する。
  • ユーザーと要求の数が定義された数以内の。
  • 定期的な停止の影響を許容できる。

1.2. サポートされる構成

  • 同じ AWS リージョン内の 2 つの Openshift シングル AZ クラスター

    • ROSA HCP または ROSA classic のいずれかの Red Hat OpenShift Service on AWS (ROSA) を使用してプロビジョニングされます。
    • 各 Openshift クラスターでは、単一のアベイラビリティーゾーンにすべてのワーカーが存在します。
    • OpenShift バージョン 4.16 (またはそれ以降)。
  • Amazon Aurora PostgreSQL データベース

    • 1 つのアベイラビリティーゾーンにプライマリー DB インスタンスを配置し、2 つ目のアベイラビリティーゾーンに同期的にレプリケートされたリーダーを配置することで高可用性を実現
    • バージョン 16.1
  • 両方の ROSA クラスターにトラフィックを送信する AWS Global Accelerator
  • フェイルオーバーを自動化する AWS Lambda

上記の設定からの逸脱はサポートされず、サポートを受けるには問題をその環境で再現する必要があります。

各項目の詳細は、ビルディングブロックのマルチサイトデプロイメント の章を参照してください。

1.3. 最大負荷

  • 100,000 ユーザー
  • 1 秒あたり 300 リクエスト

詳細は、CPU およびメモリーリソースのサイズ設定の概念 の章を参照してください。

1.4. 制限事項

  • Red Hat build of Keycloak または Data Grid をアップグレードする場合、アップグレード中の期間は両方のサイトをオフラインにする必要があります。
  • 特定の障害シナリオでは、最大 5 分のダウンタイムが発生する可能性があります。
  • 特定の障害シナリオが発生した後は、障害が発生したサイトをオンラインに戻して冗長性を回復するために手動介入が必要になる場合があります。
  • 特定の切り替えシナリオでは、最大 5 分のダウンタイムが発生する可能性があります。

制限の詳細は、マルチサイトデプロイメントの概念 の章を参照してください。

1.5. 次のステップ

それぞれの章で、必要な概念とビルディングブロックを紹介します。各ビルディングブロックのブループリントは、完全に機能するサンプルを設定する方法を示しています。ただし、実稼働環境のセットアップを準備する際には、追加のパフォーマンスチューニングとセキュリティーハードニングを実施することを推奨します。

第2章 マルチサイトデプロイメントの概念

このトピックでは、高可用性のマルチサイト設定と想定される動作を説明します。高可用性アーキテクチャーの要件を概説し、その利点と欠点を説明します。

2.1. このセットアップを使用する場合

このセットアップは、サイト障害に耐え、ダウンタイムの可能性を減らすことができる Red Hat build of Keycloak デプロイメントを提供するために使用できます。

2.2. デプロイメント、データストレージ、キャッシュ

異なるサイトで実行されている 2 つの独立した Red Hat build of Keycloak デプロイメントを、低遅延のネットワーク接続で接続します。ユーザー、レルム、クライアント、セッション、およびその他のエンティティーを、2 つのサイト間で同期的にレプリケートされるデータベースに保存します。データは、ローカルキャッシュとして Red Hat build of Keycloak Infinispan キャッシュにもキャッシュされます。一方の Red Hat build of Keycloak インスタンスでデータが変更されると、そのデータがデータベース内で更新され、work キャッシュを使用して無効化メッセージが他方のサイトに送信されます。

以下の段落と図における Data Grid のデプロイへの言及は、外部 Data Grid を対象としています。

2.3. データとサービスの損失の原因

このセットアップは高可用性の実現を目的としたものですが、それでも次の状況ではサービスまたはデータの損失が発生する可能性があります。

  • Red Hat build of Keycloak サイト障害により、障害の発生からロードバランサーによる検出までの間に、障害が発生したサイトにリクエストがルーティングされてリクエストが失敗する可能性があります。
  • サイト間の通信で障害が発生した場合、機能が低下したセットアップを再同期するために手動の手順が必要になります。
  • セットアップの機能が低下すると、別のコンポーネントにさらに障害が発生した場合にサービスまたはデータの損失が発生する可能性があります。セットアップの機能低下を検出するには監視が必要です。

2.4. このセットアップが耐えられる障害

Expand
障害復元RPO1RTO2

データベースノード

ライターインスタンスに障害が発生した場合、データベースは同じサイトまたは別のサイトのリーダーインスタンスを新しいライターにプロモートすることができます。

データ損失なし

数秒から数分 (データベースによって異なる)

Red Hat build of Keycloak ノード

複数の Red Hat build of Keycloak インスタンスが各サイトで実行されます。1 つのインスタンスが失敗すると、一部の受信リクエストがエラーメッセージを受信するか、数秒間遅延する可能性があります。

データ損失なし

30 秒未満

Data Grid ノード

複数の Data Grid インスタンスが各サイトで実行されます。1 つのインスタンスに障害が発生した場合、他のノードが変化を認識するまでに数秒かかります。エンティティーが少なくとも 2 つの Data Grid ノードに保存されるため、1 つのノードの障害によってデータが失われることはありません。

データ損失なし

30 秒未満

Data Grid クラスターの障害

いずれかのサイトで Data Grid クラスターに障害が発生すると、Red Hat build of Keycloak はそのサイト上の外部 Data Grid と通信できなくなり、Red Hat build of Keycloak サービスが使用できなくなります。/lb-check がエラーを返すと、ロードバランサーが状況を検出し、すべてのトラフィックを他のサイトに転送します。

Data Grid クラスターが復元され、データが再同期されるまで、セットアップの機能が低下します。

データ損失なし 3

数秒から数分 (ロードバランサーの設定によって異なる)

接続性 Data Grid

2 つのサイト間の接続が失われると、データを他のサイトに送信できなくなります。受信リクエストがエラーメッセージを受信するか、数秒遅延する場合があります。Data Grid は他のサイトをオフラインとしてマークし、データの送信を停止します。接続が復元され、2 つのサイト間でデータが再同期されるまで、ロードバランサー内でいずれかのサイトをオフラインにする必要があります。ブループリントでは、これの自動化方法を示しています。

データ損失なし 3

数秒から数分 (ロードバランサーの設定によって異なる)

接続性データベース

2 つのサイト間の接続が失われると、同期レプリケーションは失敗します。一部のリクエストがエラーメッセージを受信するか、数秒遅延する場合があります。データベースによっては手動操作が必要な場合があります。

データ損失なし 3

数秒から数分 (データベースによって異なる)

サイトの障害

Red Hat build of Keycloak ノードが利用できない場合、ロードバランサーは停止を検出し、トラフィックを別のサイトにリダイレクトします。ロードバランサーが障害を検出するまで、一部のリクエストがエラーメッセージを受信する可能性があります。

データ損失なし 3

2 分未満

表の脚注:

1 目標復旧時点。この障害が発生した時点でセットアップのすべての部分が健全であると仮定した場合。
2 目標復旧時間。
3 機能が低下したセットアップを復元するには手動操作が必要です。

“データ損失なし” は、以前の障害によってセットアップの機能が低下していないことを条件としています。これには、サイト間の状態を再同期する保留中の手動操作が完了していることも含まれます。

2.5. 既知の制限

サイトの障害
フェイルオーバーを正常に実行するには、以前の障害によってセットアップの機能が低下していない必要があります。データ損失を防ぐために、前回の障害後の再同期などの手動操作をすべて完了する必要があります。モニタリングを使用して、機能低下をタイムリーに検出して処理してください。
同期していないサイト
Data Grid 同期リクエストが失敗すると、サイトの同期が取れなくなることがあります。この状況を監視することは現時点では困難であり、回復するには Data Grid をすべて手動で再同期する必要があります。両方のサイトのキャッシュエントリーの数と Red Hat build of Keycloak ログファイルを監視すると、再同期が必要なタイミングを把握できます。
手動操作
サイト間で Data Grid の状態を再同期する手動操作を行うと、完全な状態の転送が実行され、システムに負荷がかかります。
2 サイト制限
このセットアップは 2 サイトの場合のみテストおよびサポートされています。サイトを追加すると、サイトごとにデータを同期的に書き込む必要があるため、サイトを追加するたびに全体的な遅延が増加します。さらに、ネットワーク障害の可能性が増加し、結果的にダウンタイムも増加します。そのため、3 つ以上のサイトではデプロイメントの安定性とパフォーマンスの低下につながると考え、サポート対象外としています。

2.6. 質問と回答

データベース同期レプリケーションを使用するのはなぜですか?
データベースを同期的にレプリケートすると、サイトに障害が発生しても、一方のサイトに書き込まれたデータをもう一方のサイトで使用でき、データを失うことはありません。また、どのサイトにデータが提供されるかにかかわらず、次のリクエストで古いデータが返されることもありません。
Data Grid 同期レプリケーションを使用するのはなぜですか?
Data Grid を同期的にレプリケートすると、サイト障害が発生しても、一方のサイトでキャッシュされたデータをもう一方のサイトで使用できるため、データを失うことはありません。また、どのサイトにデータが提供されるかにかかわらず、次のリクエストで古いデータが返されることもありません。
サイト間に低遅延ネットワークが必要なのはなぜですか?
同期レプリケーションでは、もう一方のサイトでデータが受信されるまで、呼び出し元へのレスポンスを延期します。データベース同期レプリケーションと Data Grid 同期レプリケーションでは、データの更新時に各リクエストでサイト間のやり取りが複数回発生し、遅延が増大する可能性があるため、低遅延が必要です。
同期クラスターは非同期クラスターよりも安定性に劣りますか?

非同期セットアップでは、サイト間のネットワーク障害が正常に処理されます。一方、同期セットアップでは、非同期セットアップなら別のサイトの Data Grid またはデータベースへの書き込みが延期されるような状況でも、リクエストが遅延し、呼び出し元に対してエラーが出力されます。ただし、2 つのサイトが完全に最新の状態になることはないため、このセットアップでは障害発生時にデータが失われる可能性があります。データ損失には次のものが含まれます。

  • 非同期データベースを使用した場合、データベースの変更が障害発生時にもう一方のサイトにレプリケートされないため、変更が失われ、ユーザーが古いパスワードでログインできます。
  • Data Grid 非同期レプリケーションを使用した場合、無効化されたキャッシュは障害発生時にもう一方のサイトに伝播されないため、無効なキャッシュが原因でユーザーが古いパスワードでログインできます。

したがって、高可用性と整合性の間にはトレードオフが存在します。このトピックの焦点は、Red Hat build of Keycloak の可用性よりも整合性を優先することです。

2.7. 次のステップ

ビルディングブロックのマルチサイトデプロイメント の章を続けて読み、さまざまなビルディングブロックのブループリントを確認してください。

第3章 ビルディングブロックのマルチサイトデプロイメント

同期レプリケーションを使用したマルチサイトデプロイメントをセットアップするには、次のビルディングブロックが必要です。

ビルディングブロックには、設定例を含むブループリントへのリンクがあります。ビルディングブロックはインストールする必要がある順序でリストされています。

注記

以下のブループリントは、機能的に完全な最小限の例を示すためのものであり、通常のインストールに適したベースラインのパフォーマンスを実現します。ただし、お使いの環境、組織の標準、セキュリティーのベストプラクティスに合わせて変更する必要があります。

3.1. 前提条件

3.2. 低遅延接続で接続された 2 つのサイト

同期レプリケーションをデータベースと外部 Data Grid の両方で使用できるようにします。

推奨されるセットアップ: 同じ AWS リージョン内の 2 つの AWS アベイラビリティーゾーン。

考慮対象外: 同じ大陸または異なる大陸の 2 つのリージョン。遅延が増加し、ネットワーク障害が発生する可能性が高くなります。AWS 上の Aurora リージョンデプロイメントを使用した、サービスとしてのデータベースの同期レプリケーションは、同じリージョン内でのみ利用できます。

3.3. Red Hat build of Keycloak と Data Grid の環境

インスタンスが必要に応じてデプロイおよび再起動されるようにします。

推奨されるセットアップ: 各アベイラビリティーゾーンにデプロイされた Red Hat OpenShift Service on AWS (ROSA)。

考慮対象外: 複数のアベイラビリティーゾーンにまたがる拡張された ROSA クラスター。設定を誤ると単一障害点になる可能性があります。

3.4. Database

2 つのサイト間で同期レプリケートされるデータベース。

ブループリント: 複数のアベイラビリティーゾーンへの AWS Aurora のデプロイ

3.5. Data Grid

Data Grid の Cross-DC 機能を活用した Data Grid のデプロイメント。

ブループリント: Data Grid Operator を使用して HA 用の Data Grid をデプロイ し、Data Grid の Gossip Router を使用して 2 つのサイトを接続します。

考慮対象外: ネットワーク層上の Kubernetes クラスター間の直接相互接続。将来的には考慮される可能性があります。

3.6. Red Hat build of Keycloak

外部 Data Grid に接続された、各サイトの Red Hat build of Keycloak のクラスターデプロイメント。

ブループリント: Aurora データベースと Data Grid サーバーへの接続を含む HA 用の Red Hat build of Keycloak を Red Hat build of Keycloak Operator を使用してデプロイ します。

3.7. ロードバランサー

各サイトの Red Hat build of Keycloak の /lb-check URL をチェックするロードバランサーと、2 つのサイト間の Data Grid 接続問題を検出する自動化。

ブループリント: AWS Global Accelerator ロードバランサーをデプロイ し、同時に AWS Lambda をデプロイして応答しないサイトを無効化 します。

第4章 データベース接続プールの概念

このセクションは、Red Hat build of Keycloak 用にデータベース接続プールを設定する方法に関する考慮事項とベストプラクティスを説明することを目的としています。これが適用される設定は、Red Hat build of Keycloak Operator を使用した HA 用の Red Hat build of Keycloak のデプロイ を参照してください。

4.1. 概念

新しいデータベース接続の作成には時間がかかるため、コストがかかります。リクエストが到着したときにデータベース接続を作成すると、レスポンスが遅れるため、リクエストが到着する前に作成しておくことをお勧めします。また、これは スタンピード現象 の原因となる可能性があります。つまり、短期間に大量の接続が作成されると、システムの速度が低下し、スレッドがブロックされるため、さらに状況が悪化する可能性があります。接続を閉じると、その接続のサーバー側ステートメントのキャッシュもすべて無効になります。

最適なパフォーマンスを得るには、データベース接続プールの初期サイズ、最小サイズ、最大サイズの値をすべて等しくする必要があります。これにより、新しいリクエスト受信時の新しいデータベース接続の作成とそのコストが回避されます。

データベース接続をできるだけ長く開いたままにすることで、接続にバインドされたサーバー側のステートメントキャッシュが可能になります。PostgreSQL の場合、サーバー側のプリペアドステートメントを使用するには、クエリーを (デフォルトで) 5 回以上実行する必要があります

詳細は、プリペアドステートメントに関する PostgreSQL ドキュメント を参照してください。

第5章 スレッドプールの設定の概念

このセクションは、Red Hat build of Keycloak 用にスレッドプール接続プールを設定する方法に関する考慮事項とベストプラクティスを説明することを目的としています。これが適用される設定は、Red Hat build of Keycloak Operator を使用した HA 用の Red Hat build of Keycloak のデプロイ を参照してください。

5.1. 概念

5.1.1. Quarkus エグゼキュータープール

Red Hat build of Keycloak のリクエストとブロッキングプローブは、エグゼキュータープールによって処理されます。利用可能な CPU コア数に応じて、プールのサイズは最大 50 スレッド以上になります。スレッドは必要に応じて作成され、不要になると終了するため、システムは自動的にスケールアップおよびスケールダウンします。Red Hat build of Keycloak では、http-pool-max-threads 設定オプションによって最大スレッドプールサイズを設定できます。例は、Red Hat build of Keycloak Operator を使用した HA 用の Red Hat build of Keycloak のデプロイ を参照してください。

Kubernetes で実行する場合は、Pod に許可された CPU 制限を超える負荷が発生しないようにワーカースレッドの数を調整して、輻輳を引き起こすスロットリングを回避します。物理マシンで実行する場合は、ノードが処理できる以上の負荷が発生しないようにワーカースレッドの数を調整して、輻輳を回避します。輻輳が発生すると、応答時間が長くなり、メモリー使用量が増加し、最終的にはシステムが不安定になります。

可能であれば、下限のスレッド数から始めて、目標のスループットと応答時間に応じて数を調整してください。負荷とスレッド数が増加すると、データベース接続もボトルネックになる可能性があります。リクエストが 5 秒以内にデータベース接続を取得できないと、そのリクエストは失敗し、Unable to acquire JDBC Connection のようなメッセージがログに記録されます。呼び出し元は、サーバー側のエラーを示す 5xx HTTP ステータスコードを含む応答を受け取ります。

データベース接続数とスレッド数を増やしすぎると、高負荷時にリクエストがキューに蓄積されてシステムが輻輳し、パフォーマンスが低下します。データベース接続の数は、それぞれ Database 設定の db-pool-initial-sizedb-pool-min-size、および db-pool-max-size によって設定されます。数値が低いと、負荷が急増したときにリクエストが失敗することがありますが、すべてのクライアントの応答時間が速くなります。

5.1.2. JGroups 接続プール

注記

これは現在、シングルサイトセットアップにのみ適用されます。外部 Data Grid を使用するマルチサイトセットアップの場合、これは制限ではなくなりました。

org.jgroups.util.ThreadPool: thread pool is full エラーを避けるために、クラスター内のすべての Red Hat build of Keycloak ノードのエグゼキュータースレッドの合計数が、JGroups スレッドプールで使用可能なスレッドの数を超えないようにしてください。初めてエラーが発生したときにエラーを確認するには、システムプロパティー jgroups.thread_dumps_threshold1 に設定する必要があります。そうしないと、10000 件のリクエストが拒否されるまで、メッセージが表示されません。

JGroup スレッドの数はデフォルトで 200 です。これは、Java システムプロパティー jgroups.thread_pool.max_threads を使用して設定できますが、この値を維持することを推奨します。実験によると、JGroups の通信のデッドロックを回避するには、クラスター内の Quarkus ワーカースレッドの合計数が、各ノードの JGroup スレッドプール内のスレッド数 (200) 以下である必要があります。4 つの Pod を持つ Red Hat build of Keycloak クラスターの場合、各 Pod の Quarkus ワーカースレッド数が 50 個である必要があります。Quarkus ワーカースレッドの最大数は、Red Hat build of Keycloak 設定オプション http-pool-max-threads を使用して設定します。

メトリクスを使用して、プール内の JGroup スレッドの合計数とプール内でアクティブなスレッドを監視します。JGroups トランスポートプロトコルとして TCP を使用する場合、メトリクス vendor_jgroups_tcp_get_thread_pool_size および vendor_jgroups_tcp_get_thread_pool_size_active を監視に使用できます。UDP を使用する場合、メトリクス vendor_jgroups_udp_get_thread_pool_sizevendor_jgroups_udp_get_thread_pool_size_active を使用できます。これは、Quarkus スレッドプールサイズの制限により、アクティブな JGroup スレッドの数が JGroup スレッドプールの最大サイズ内に収まっていることを確認するのに役立ちます。

5.1.3. 負荷制限

デフォルトでは、Red Hat build of Keycloak は、リクエストの処理が停止した場合でも、すべての受信リクエストを無限にキューに入れます。これにより、Pod でさらにメモリーが使用され、ロードバランサーのリソースが枯渇する可能性があります。最終的には、リクエストが処理されたかどうかをクライアントが認識することなく、リクエストがクライアント側でタイムアウトになります。Red Hat build of Keycloak でキューに入れられるリクエストの数を制限するには、追加の Quarkus 設定オプションを設定します。

http-max-queued-requests を設定して最大キュー長を指定し、このキューサイズを超えた場合に効果的な負荷制限を適用できるようにします。Red Hat build of Keycloak Pod が 1 秒あたり約 200 のリクエストを処理すると仮定すると、キューが 1000 の場合、最大待機時間は約 5 秒になります。

この設定がアクティブな場合、キューに入れられたリクエストの数を超えるリクエストに対して、HTTP 503 エラーが返されます。Red Hat build of Keycloak は、エラーメッセージをログに記録します。

5.1.4. プローブ

Red Hat build of Keycloak の liveness プローブは、高負荷時の Pod の再起動を回避するために、ノンブロッキングです。

全体的なヘルスプローブと readiness プローブは、場合によってはデータベースへの接続を確認するためにブロックすることがあるため、高負荷時に失敗する可能性があります。このため、高負荷時には Pod が準備完了状態にならない可能性があります。

5.1.5. OS リソース

Linux 上で Java を実行する場合、Java がスレッドを作成するには、使用可能なファイルハンドルが必要です。したがって、オープンファイルの数 (Linux で ulimit -n で取得される数) に余裕を確保し、Red Hat build of Keycloak が必要なスレッドの数を増やせるようにする必要があります。各スレッドはメモリーも消費するため、コンテナーのメモリー制限を、これを許容する値に設定する必要があります。そうしないと、Pod が Kubernetes によって強制終了されます。

第6章 CPU およびメモリーリソースのサイジングの概念

この章は、実稼働環境のサイジングの開始点として使用してください。負荷テストに基づいて、必要に応じて環境に合わせて値を調整してください。

6.1. パフォーマンスに関する推奨事項

警告
  • より多くの Pod にスケーリングする場合 (オーバーヘッドの追加のため)、および複数のデータセンターにまたがるセットアップを使用する場合 (トラフィックと運用の拡大のため)、パフォーマンスが低下します。
  • Red Hat build of Keycloak インスタンスを長時間実行する場合、キャッシュサイズを増やすと、パフォーマンスが向上する可能性があります。これにより、応答時間が短縮され、データベースの IOPS が減少します。ただし、このキャッシュはインスタンスの再起動時にいっぱいにする必要があるため、キャッシュがいっぱいになった後に測定した安定状態に基づいてリソースを厳しく設定しないでください。
  • 以下の値は開始点として使用し、実稼働に移行する前に独自の負荷テストを実行してください。

概要:

  • 使用される CPU は、以下のテスト済みの上限まで、リクエストの数に比例して増加します。

推奨事項:

  • Pod の基本メモリー使用量は、レルムデータのキャッシュとキャッシュされた 10,000 セッションを含め、RAM 1250 MB です。
  • コンテナーでは、Keycloak はメモリー制限の 70% をヒープベースのメモリーに割り当てます。また、ヒープベース以外のメモリーも約 300 MB 使用します。要求されるメモリーを計算するには、上記の計算を使用してください。メモリー制限を求めるには、上記の値からヒープ以外のメモリーを減算し、その結果を 0.7 で割ります。
  • 1 秒あたり 15 件のパスワードベースのユーザーログインにつき 1 つの仮想 CPU をクラスターに割り当てます (1 秒あたり最大 300 までテスト済み)。

    Red Hat build of Keycloak は、ユーザーが指定したパスワードのハッシュ化にほとんどの CPU 時間を費やします。CPU 時間はハッシュ化の反復回数に比例します。

  • 1 秒あたり 200 件のクライアントクレデンシャルグラントにつき 1 つの仮想 CPU をクラスターに割り当てます (1 秒あたり 2000 までテスト済み)。

    各クライアントは 1 つのリクエストのみを実行するため、ほとんどの CPU 時間は新しい TLS 接続の作成に費やされます。

  • 1 秒あたり 120 件のリフレッシュトークンリクエストにつき 1 つの仮想 CPU をクラスターに割り当てます (1 秒あたり 435 件のリフレッシュトークンリクエストまでテスト済み)。
  • 負荷の急増に対処するために、CPU 使用率に 150% の余裕を残しておきます。これにより、ノードの高速起動と、フェイルオーバータスクを処理するための十分な容量が確保されます。当社のテストでは、Pod がスロットリングされたときに Red Hat build of Keycloak のパフォーマンスが大幅に低下しました。

Red Hat build of Keycloak は、デフォルトでユーザーセッションをデータベースに保存しますが、Aurora PostgreSQL multi-AZ データベースで最適なパフォーマンスを確保するためには次のリソースが必要です。

1 秒あたり 100 回のログイン/ログアウト/更新リクエストごとに以下が必要です。

  • 1400 Write IOPS のバジェット。
  • 0.35 から 0.7 の範囲での仮想 CPU の割当。

仮想 CPU 要件は範囲として指定されます。データベースホストの CPU 飽和度が増加すると、要求ごとの CPU 使用率は低下しますが、応答時間は長くなります。データベースの CPU クォータが低いと、ピーク負荷時の応答時間が長くなる可能性があります。ピーク負荷時の応答時間を短縮することが重要な場合は、より大きな CPU クォータを選択してください。以下はその例です。

6.1.1. 計算例 (シングルサイト)

ターゲットサイズ:

  • 1 秒あたり 45 回のログインとログアウト
  • 1 秒あたり 600 件のクライアントクレデンシャルグラント
  • 1 秒あたり 360 件のリフレッシュトークンリクエスト (ログイン比率は 1:8)
  • 3 Pod

制限の算定:

  • Pod あたりの CPU リクエスト: 3 仮想 CPU

    (1 秒あたり 45 件のログイン = 3 仮想 CPU、1 秒あたり 600 のクライアントクレデンシャルグラント = 3 仮想 CPU、345 のリフレッシュトークン = 3 仮想 CPU。合計で 9 仮想 CPU。クラスター内で 3 Pod が実行されている場合、各 Pod は 3 仮想 CPU をリクエストします。)

  • Pod あたりの CPU 制限: 7.5 仮想 CPU

    (ピーク、起動、フェイルオーバータスクを処理するために、追加で要求される CPU の 150% を確保)

  • Pod あたりのメモリーリクエスト: 1250 MB

    (1250 MB ベースメモリー)

  • Pod あたりのメモリー制限: 1360 MB

    (1250 MB の予想メモリー使用量から 300 MB (ヒープ以外のメモリー使用量) を引き、0.7 で割った値)

  • Aurora データベースインスタンス: ピーク負荷時に必要な応答時間に応じて、db.t4g.large または db.t4g.xlarge のいずれか。

    (1 秒あたり 45 回のログイン、1 秒あたり 5 回のログアウト、1 秒あたり 360 のリフレッシュトークン。合計すると 1 秒あたり 410 件のリクエストになります。予想される DB 使用量は 1.4 - 2.8 仮想 CPU で、DB アイドル負荷は 0.3 仮想 CPU です。これは、2 仮想 CPU の db.t4g.large インスタンスまたは 4 仮想 CPU の db.t4g.xlarge インスタンスのいずれかを示します。ピーク使用時に応答時間が長くなることが許容される場合、2 仮想 CPU の db.t4g.large の方がコスト効率が高くなります。このシナリオでの当社のテストでは、2 仮想 CPU の db.t4g.large インスタンスで CPU 飽和度が 90% に達すると、ログインとトークン更新の平均応答時間が最大 120 ミリ秒増加しました。このシナリオの場合、ピーク使用時の応答時間を短縮するには 4 仮想 CPU の db.t4g.xlarge インスタンスを検討してください。)

6.1.2. マルチサイトセットアップのサイズ設定

1 つの AWS リージョンに 2 つの AZ を持つアクティブ/アクティブ Keycloak セットアップのサイズ設定を作成するには、次の手順に従います。

  • セカンダリーサイトで、上記と同じメモリーサイズを持つ同数の Pod を作成します。
  • データベースのサイズは変更されません。両方のサイトは同じデータベースライターインスタンスに接続します。

CPU リクエストと制限のサイズ設定に関しては、期待されるフェイルオーバー動作に応じてさまざまなアプローチがあります。

フェイルオーバーが速く、コストが高い
セカンダリーサイトでも、CPU リクエストと制限を上記のままにします。この場合、スケーリングをしなくても他のサイトはプライマリーサイトからのトラフィックをすぐに引き継ぐことができます。
フェイルオーバーが遅く、コスト効率が高い
セカンダリーサイトで、上記の CPU リクエストと制限を 50% 削減します。いずれかのサイトに障害が発生した場合、手動、自動、または Horizontal Pod Autoscaler を使用して、残りのサイトを 3 Pod から 6 Pod にスケーリングします。これには、クラスターに十分な予備容量またはクラスターの自動スケーリング機能が必要です。
一部の環境向けの代替設定
セカンダリーサイトの CPU リクエストを 50% 削減しますが、CPU 制限は上記のままにします。この場合、残りのサイトがトラフィックを処理できますが、ノードの CPU 負荷が高くなり、ピークトラフィック時の応答時間が遅くなります。このセットアップの利点は、フェイルオーバー時に Pod の数を増やす必要がないため、設定が簡単になる点です。

6.2. リファレンスアーキテクチャー

次のセットアップを使用して上記の設定を反映し、さまざまなシナリオで約 10 分間のテストを実行しました。

  • ROSA 経由で AWS にデプロイした OpenShift 4.16.x。
  • m5.2xlarge インスタンスが含まれるマシンプール。
  • Operator と 3 つの Pod を使用して、アクティブ/アクティブモードの 2 サイトを持つ高可用性セットアップでデプロイした Red Hat build of Keycloak。
  • クライアントの TLS 接続が Pod で終了するパススルーモードで実行される OpenShift のリバースプロキシー。
  • マルチ AZ セットアップの Amazon Aurora PostgreSQL データベース。
  • Argon2 による 5 回のハッシュイテレーションと最小メモリーサイズ 7 MiB を使用したデフォルトのユーザーパスワードハッシュ化。これは OWASP により推奨 (デフォルト) されています。
  • クライアントクレデンシャルグラントでリフレッシュトークンを使用しません (デフォルト)。
  • 20,000 のユーザーと 20,000 のクライアントを使用してシードしたデータベース。
  • デフォルトの 10,000 エントリーの Infinispan ローカルキャッシュ。そのため、すべてのクライアントとユーザーがキャッシュに収まるわけではありません。一部のリクエストはデータベースからデータを取得する必要があります。
  • デフォルト設定に従ってすべての認証セッションを分散キャッシュに配置。エントリーごとに 2 人の所有者が存在し、1 つの Pod で障害が発生してもデータ損失が発生しません。
  • すべてのユーザーおよびクライアントセッションはデータベースに保存されます。マルチサイトセットアップでテストされたため、メモリー内にはキャッシュされません。固定数のユーザーおよびクライアントセッションがキャッシュされるため、シングルサイトセットアップではパフォーマンスが若干向上することが予想されます。
  • OpenJDK 21

第7章 Data Grid CLI コマンドを自動化するための概念

Kubernetes で外部 Data Grid と対話する場合、Batch CR を使用すると、標準の oc コマンドを使用して対話を自動化できます。

7.1. 使用するタイミング

Kubernetes での対話を自動化するときに使用します。これにより、ユーザー名とパスワードの入力や、シェルスクリプトの出力とそのステータスの確認が不要になります。

手動操作の場合は、CLI シェルの方が適している場合があります。

7.2. 例

サイトをオフラインにする の操作手順で説明されているとおり、次の Batch CR はサイトをオフラインにします。

apiVersion: infinispan.org/v2alpha1
kind: Batch
metadata:
  name: take-offline
  namespace: keycloak 
1

spec:
  cluster: infinispan 
2

  config: | 
3

    site take-offline --all-caches --site=site-a
    site status --all-caches --site=site-a
Copy to Clipboard Toggle word wrap
1
Batch CR は、Data Grid デプロイメントと同じ namespace に作成する必要があります。
2
Infinispan CR の名前。
3
1 つ以上の Data Grid CLI コマンドを含む複数行の文字列。

CR を作成したら、ステータスに完了と表示されるまで待ちます。

oc -n keycloak wait --for=jsonpath='{.status.phase}'=Succeeded Batch/take-offline
Copy to Clipboard Toggle word wrap
注記

Batch CR インスタンスを変更しても効果はありません。バッチ操作は、Infinispan リソースを変更する “1 回限り” のイベントです。CR の .spec フィールドを更新するには、またはバッチ操作が失敗した場合には、Batch CR の新規インスタンスを作成する必要があります。

7.3. 関連資料

詳細は、Data Grid Operator Batch CR のドキュメント を参照してください。

第8章 複数のアベイラビリティーゾーンへの AWS Aurora のデプロイ

このトピックでは、特定の AWS リージョンにおける 1 つ以上のアベイラビリティーゾーンの障害に対応するために、複数のアベイラビリティーゾーンに PostgreSQL インスタンスの Aurora リージョンデプロイメントをデプロイする方法を説明します。

このデプロイメントは、マルチサイトデプロイメントの概念 の章で説明されているセットアップで使用することを想定しています。このデプロイメントは、マルチサイトデプロイメントのビルディングブロック の章で説明されている他のビルディングブロックとともに使用してください。

注記

以下のブループリントは、機能的に完全な最小限の例を示すためのものであり、通常のインストールに適したベースラインのパフォーマンスを実現します。ただし、お使いの環境、組織の標準、セキュリティーのベストプラクティスに合わせて変更する必要があります。

8.1. アーキテクチャー

Aurora データベースクラスターは、複数の Aurora データベースインスタンスで構成されます。1 つのインスタンスがプライマリーライターとして指定され、他のすべてのインスタンスがバックアップリーダーとして指定されます。アベイラビリティーゾーンに障害が発生した場合に高可用性を確保するために、Aurora では、単一の AWS リージョン内の複数のゾーンにデータベースインスタンスをデプロイできます。プライマリーデータベースインスタンスをホストしているアベイラビリティーゾーンで障害が発生した場合、Aurora は自動的に自己修復し、障害が発生していないアベイラビリティーゾーンのリーダーインスタンスを新しいライターインスタンスにプロモートします。

図8.1 Aurora の複数アベイラビリティーゾーンのデプロイメント

Aurora データベースが提供するセマンティクスの詳細は、AWS Aurora のドキュメント を参照してください。

このドキュメントは AWS のベストプラクティスに従い、インターネットに公開されないプライベート Aurora データベースを作成します。ROSA クラスターからデータベースにアクセスするには、データベースと ROSA クラスターの間にピアリング接続を確立 します。

8.2. 手順

次の手順には 2 つのセクションがあります。

  • eu-west-1 に "keycloak-aurora" という名前の Aurora Multi-AZ データベースクラスターを作成します。
  • ROSA クラスターと Aurora VPC の間にピアリング接続を作成し、ROSA クラスターにデプロイされたアプリケーションがデータベースとの接続を確立できるようにします。

8.2.1. Aurora データベースクラスターの作成

  1. Aurora クラスターの VPC を作成します。

    コマンド:

    aws ec2 create-vpc \
      --cidr-block 192.168.0.0/16 \
      --tag-specifications "ResourceType=vpc, Tags=[{Key=AuroraCluster,Value=keycloak-aurora}]" \
    1
    
      --region eu-west-1
    Copy to Clipboard Toggle word wrap

    1
    VPC を簡単に取得できるように、Aurora クラスターの名前を含むオプションのタグを追加します。

    出力:

    {
        "Vpc": {
            "CidrBlock": "192.168.0.0/16",
            "DhcpOptionsId": "dopt-0bae7798158bc344f",
            "State": "pending",
            "VpcId": "vpc-0b40bd7c59dbe4277",
            "OwnerId": "606671647913",
            "InstanceTenancy": "default",
            "Ipv6CidrBlockAssociationSet": [],
            "CidrBlockAssociationSet": [
                {
                    "AssociationId": "vpc-cidr-assoc-09a02a83059ba5ab6",
                    "CidrBlock": "192.168.0.0/16",
                    "CidrBlockState": {
                        "State": "associated"
                    }
                }
            ],
            "IsDefault": false
        }
    }
    Copy to Clipboard Toggle word wrap

  2. 新しく作成した VPC の VpcId を使用して、Aurora をデプロイする各アベイラビリティーゾーンのサブネットを作成します。

    注記

    各アベイラビリティーゾーンに指定した cidr ブロック範囲が重複しないようにしてください。

    1. ゾーン A

      コマンド:

      aws ec2 create-subnet \
        --availability-zone "eu-west-1a" \
        --vpc-id vpc-0b40bd7c59dbe4277 \
        --cidr-block 192.168.0.0/19 \
        --region eu-west-1
      Copy to Clipboard Toggle word wrap

      出力:

      {
          "Subnet": {
              "AvailabilityZone": "eu-west-1a",
              "AvailabilityZoneId": "euw1-az3",
              "AvailableIpAddressCount": 8187,
              "CidrBlock": "192.168.0.0/19",
              "DefaultForAz": false,
              "MapPublicIpOnLaunch": false,
              "State": "available",
              "SubnetId": "subnet-0d491a1a798aa878d",
              "VpcId": "vpc-0b40bd7c59dbe4277",
              "OwnerId": "606671647913",
              "AssignIpv6AddressOnCreation": false,
              "Ipv6CidrBlockAssociationSet": [],
              "SubnetArn": "arn:aws:ec2:eu-west-1:606671647913:subnet/subnet-0d491a1a798aa878d",
              "EnableDns64": false,
              "Ipv6Native": false,
              "PrivateDnsNameOptionsOnLaunch": {
                  "HostnameType": "ip-name",
                  "EnableResourceNameDnsARecord": false,
                  "EnableResourceNameDnsAAAARecord": false
              }
          }
      }
      Copy to Clipboard Toggle word wrap

    2. ゾーン B

      コマンド:

      aws ec2 create-subnet \
        --availability-zone "eu-west-1b" \
        --vpc-id vpc-0b40bd7c59dbe4277 \
        --cidr-block 192.168.32.0/19 \
        --region eu-west-1
      Copy to Clipboard Toggle word wrap

      出力:

      {
          "Subnet": {
              "AvailabilityZone": "eu-west-1b",
              "AvailabilityZoneId": "euw1-az1",
              "AvailableIpAddressCount": 8187,
              "CidrBlock": "192.168.32.0/19",
              "DefaultForAz": false,
              "MapPublicIpOnLaunch": false,
              "State": "available",
              "SubnetId": "subnet-057181b1e3728530e",
              "VpcId": "vpc-0b40bd7c59dbe4277",
              "OwnerId": "606671647913",
              "AssignIpv6AddressOnCreation": false,
              "Ipv6CidrBlockAssociationSet": [],
              "SubnetArn": "arn:aws:ec2:eu-west-1:606671647913:subnet/subnet-057181b1e3728530e",
              "EnableDns64": false,
              "Ipv6Native": false,
              "PrivateDnsNameOptionsOnLaunch": {
                  "HostnameType": "ip-name",
                  "EnableResourceNameDnsARecord": false,
                  "EnableResourceNameDnsAAAARecord": false
              }
          }
      }
      Copy to Clipboard Toggle word wrap

  3. Aurora VPC ルートテーブルの ID を取得します。

    コマンド:

    aws ec2 describe-route-tables \
      --filters Name=vpc-id,Values=vpc-0b40bd7c59dbe4277 \
      --region eu-west-1
    Copy to Clipboard Toggle word wrap

    出力:

    {
        "RouteTables": [
            {
                "Associations": [
                    {
                        "Main": true,
                        "RouteTableAssociationId": "rtbassoc-02dfa06f4c7b4f99a",
                        "RouteTableId": "rtb-04a644ad3cd7de351",
                        "AssociationState": {
                            "State": "associated"
                        }
                    }
                ],
                "PropagatingVgws": [],
                "RouteTableId": "rtb-04a644ad3cd7de351",
                "Routes": [
                    {
                        "DestinationCidrBlock": "192.168.0.0/16",
                        "GatewayId": "local",
                        "Origin": "CreateRouteTable",
                        "State": "active"
                    }
                ],
                "Tags": [],
                "VpcId": "vpc-0b40bd7c59dbe4277",
                "OwnerId": "606671647913"
            }
        ]
    }
    Copy to Clipboard Toggle word wrap

  4. Aurora VPC ルートテーブルを各アベイラビリティーゾーンのサブネットに関連付けます。

    1. ゾーン A

      コマンド:

      aws ec2 associate-route-table \
        --route-table-id rtb-04a644ad3cd7de351 \
        --subnet-id subnet-0d491a1a798aa878d \
        --region eu-west-1
      Copy to Clipboard Toggle word wrap

    2. ゾーン B

      コマンド:

      aws ec2 associate-route-table \
        --route-table-id rtb-04a644ad3cd7de351 \
        --subnet-id subnet-057181b1e3728530e \
        --region eu-west-1
      Copy to Clipboard Toggle word wrap

  5. Aurora サブネットグループを作成します。

    コマンド:

    aws rds create-db-subnet-group \
      --db-subnet-group-name keycloak-aurora-subnet-group \
      --db-subnet-group-description "Aurora DB Subnet Group" \
      --subnet-ids subnet-0d491a1a798aa878d subnet-057181b1e3728530e \
      --region eu-west-1
    Copy to Clipboard Toggle word wrap

  6. Aurora セキュリティーグループを作成します。

    コマンド:

    aws ec2 create-security-group \
      --group-name keycloak-aurora-security-group \
      --description "Aurora DB Security Group" \
      --vpc-id vpc-0b40bd7c59dbe4277 \
      --region eu-west-1
    Copy to Clipboard Toggle word wrap

    出力:

    {
        "GroupId": "sg-0d746cc8ad8d2e63b"
    }
    Copy to Clipboard Toggle word wrap

  7. Aurora DB クラスターを作成します。

    コマンド:

    aws rds create-db-cluster \
        --db-cluster-identifier keycloak-aurora \
        --database-name keycloak \
        --engine aurora-postgresql \
        --engine-version ${properties["aurora-postgresql.version"]} \
        --master-username keycloak \
        --master-user-password secret99 \
        --vpc-security-group-ids sg-0d746cc8ad8d2e63b \
        --db-subnet-group-name keycloak-aurora-subnet-group \
        --region eu-west-1
    Copy to Clipboard Toggle word wrap

    注記

    --master-username--master-user-password の値は置き換える必要があります。ここで指定した値は、Red Hat build of Keycloak データベース認証情報を設定するときに使用する必要があります。

    出力:

    {
        "DBCluster": {
            "AllocatedStorage": 1,
            "AvailabilityZones": [
                "eu-west-1b",
                "eu-west-1c",
                "eu-west-1a"
            ],
            "BackupRetentionPeriod": 1,
            "DatabaseName": "keycloak",
            "DBClusterIdentifier": "keycloak-aurora",
            "DBClusterParameterGroup": "default.aurora-postgresql15",
            "DBSubnetGroup": "keycloak-aurora-subnet-group",
            "Status": "creating",
            "Endpoint": "keycloak-aurora.cluster-clhthfqe0h8p.eu-west-1.rds.amazonaws.com",
            "ReaderEndpoint": "keycloak-aurora.cluster-ro-clhthfqe0h8p.eu-west-1.rds.amazonaws.com",
            "MultiAZ": false,
            "Engine": "aurora-postgresql",
            "EngineVersion": "15.5",
            "Port": 5432,
            "MasterUsername": "keycloak",
            "PreferredBackupWindow": "02:21-02:51",
            "PreferredMaintenanceWindow": "fri:03:34-fri:04:04",
            "ReadReplicaIdentifiers": [],
            "DBClusterMembers": [],
            "VpcSecurityGroups": [
                {
                    "VpcSecurityGroupId": "sg-0d746cc8ad8d2e63b",
                    "Status": "active"
                }
            ],
            "HostedZoneId": "Z29XKXDKYMONMX",
            "StorageEncrypted": false,
            "DbClusterResourceId": "cluster-IBWXUWQYM3MS5BH557ZJ6ZQU4I",
            "DBClusterArn": "arn:aws:rds:eu-west-1:606671647913:cluster:keycloak-aurora",
            "AssociatedRoles": [],
            "IAMDatabaseAuthenticationEnabled": false,
            "ClusterCreateTime": "2023-11-01T10:40:45.964000+00:00",
            "EngineMode": "provisioned",
            "DeletionProtection": false,
            "HttpEndpointEnabled": false,
            "CopyTagsToSnapshot": false,
            "CrossAccountClone": false,
            "DomainMemberships": [],
            "TagList": [],
            "AutoMinorVersionUpgrade": true,
            "NetworkType": "IPV4"
        }
    }
    Copy to Clipboard Toggle word wrap

  8. Aurora DB インスタンスを作成します。

    1. ゾーン A ライターインスタンスを作成します。

      コマンド:

        aws rds create-db-instance \
          --db-cluster-identifier keycloak-aurora \
          --db-instance-identifier "keycloak-aurora-instance-1" \
          --db-instance-class db.t4g.large \
          --engine aurora-postgresql \
          --region eu-west-1
      Copy to Clipboard Toggle word wrap

    2. ゾーン B リーダーインスタンスを作成します。

      コマンド:

        aws rds create-db-instance \
          --db-cluster-identifier keycloak-aurora \
          --db-instance-identifier "keycloak-aurora-instance-2" \
          --db-instance-class db.t4g.large \
          --engine aurora-postgresql \
          --region eu-west-1
      Copy to Clipboard Toggle word wrap

  9. すべてのライターインスタンスとリーダーインスタンスの準備が完了するまで待ちます。

    コマンド:

    aws rds wait db-instance-available --db-instance-identifier keycloak-aurora-instance-1 --region eu-west-1
    aws rds wait db-instance-available --db-instance-identifier keycloak-aurora-instance-2 --region eu-west-1
    Copy to Clipboard Toggle word wrap

  10. Keycloak で使用するライターエンドポイント URL を取得します。

    コマンド:

    aws rds describe-db-clusters \
      --db-cluster-identifier keycloak-aurora \
      --query 'DBClusters[*].Endpoint' \
      --region eu-west-1 \
      --output text
    Copy to Clipboard Toggle word wrap

    出力:

    [
        "keycloak-aurora.cluster-clhthfqe0h8p.eu-west-1.rds.amazonaws.com"
    ]
    Copy to Clipboard Toggle word wrap

8.2.2. ROSA クラスターとのピアリング接続の確立

Red Hat build of Keycloak デプロイメントを含む ROSA クラスターごとに、以下の手順を 1 回実行します。

  1. Aurora VPC を取得します。

    コマンド:

    aws ec2 describe-vpcs \
      --filters "Name=tag:AuroraCluster,Values=keycloak-aurora" \
      --query 'Vpcs[*].VpcId' \
      --region eu-west-1 \
      --output text
    Copy to Clipboard Toggle word wrap

    出力:

    vpc-0b40bd7c59dbe4277
    Copy to Clipboard Toggle word wrap

  2. ROSA クラスター VPC を取得します。

    1. oc を使用して ROSA クラスターにログインします。
    2. ROSA VPC を取得します。

      コマンド:

      NODE=$(oc get nodes --selector=node-role.kubernetes.io/worker -o jsonpath='{.items[0].metadata.name}')
      aws ec2 describe-instances \
        --filters "Name=private-dns-name,Values=${NODE}" \
        --query 'Reservations[0].Instances[0].VpcId' \
        --region eu-west-1 \
        --output text
      Copy to Clipboard Toggle word wrap

      出力:

      vpc-0b721449398429559
      Copy to Clipboard Toggle word wrap

  3. ピアリング接続を作成します。

    コマンド:

    aws ec2 create-vpc-peering-connection \
      --vpc-id vpc-0b721449398429559 \
    1
    
      --peer-vpc-id vpc-0b40bd7c59dbe4277 \
    2
    
      --peer-region eu-west-1 \
      --region eu-west-1
    Copy to Clipboard Toggle word wrap

    1
    ROSA クラスター VPC
    2
    Aurora VPC

    出力:

    {
        "VpcPeeringConnection": {
            "AccepterVpcInfo": {
                "OwnerId": "606671647913",
                "VpcId": "vpc-0b40bd7c59dbe4277",
                "Region": "eu-west-1"
            },
            "ExpirationTime": "2023-11-08T13:26:30+00:00",
            "RequesterVpcInfo": {
                "CidrBlock": "10.0.17.0/24",
                "CidrBlockSet": [
                    {
                        "CidrBlock": "10.0.17.0/24"
                    }
                ],
                "OwnerId": "606671647913",
                "PeeringOptions": {
                    "AllowDnsResolutionFromRemoteVpc": false,
                    "AllowEgressFromLocalClassicLinkToRemoteVpc": false,
                    "AllowEgressFromLocalVpcToRemoteClassicLink": false
                },
                "VpcId": "vpc-0b721449398429559",
                "Region": "eu-west-1"
            },
            "Status": {
                "Code": "initiating-request",
                "Message": "Initiating Request to 606671647913"
            },
            "Tags": [],
            "VpcPeeringConnectionId": "pcx-0cb23d66dea3dca9f"
        }
    }
    Copy to Clipboard Toggle word wrap

  4. ピアリング接続の存在が確認されるまで待機します。

    コマンド:

    aws ec2 wait vpc-peering-connection-exists --vpc-peering-connection-ids pcx-0cb23d66dea3dca9f
    Copy to Clipboard Toggle word wrap

  5. ピアリング接続を承認します。

    コマンド:

    aws ec2 accept-vpc-peering-connection \
      --vpc-peering-connection-id pcx-0cb23d66dea3dca9f \
      --region eu-west-1
    Copy to Clipboard Toggle word wrap

    出力:

    {
        "VpcPeeringConnection": {
            "AccepterVpcInfo": {
                "CidrBlock": "192.168.0.0/16",
                "CidrBlockSet": [
                    {
                        "CidrBlock": "192.168.0.0/16"
                    }
                ],
                "OwnerId": "606671647913",
                "PeeringOptions": {
                    "AllowDnsResolutionFromRemoteVpc": false,
                    "AllowEgressFromLocalClassicLinkToRemoteVpc": false,
                    "AllowEgressFromLocalVpcToRemoteClassicLink": false
                },
                "VpcId": "vpc-0b40bd7c59dbe4277",
                "Region": "eu-west-1"
            },
            "RequesterVpcInfo": {
                "CidrBlock": "10.0.17.0/24",
                "CidrBlockSet": [
                    {
                        "CidrBlock": "10.0.17.0/24"
                    }
                ],
                "OwnerId": "606671647913",
                "PeeringOptions": {
                    "AllowDnsResolutionFromRemoteVpc": false,
                    "AllowEgressFromLocalClassicLinkToRemoteVpc": false,
                    "AllowEgressFromLocalVpcToRemoteClassicLink": false
                },
                "VpcId": "vpc-0b721449398429559",
                "Region": "eu-west-1"
            },
            "Status": {
                "Code": "provisioning",
                "Message": "Provisioning"
            },
            "Tags": [],
            "VpcPeeringConnectionId": "pcx-0cb23d66dea3dca9f"
        }
    }
    Copy to Clipboard Toggle word wrap

  6. ROSA クラスター VPC ルートテーブルを更新します。

    コマンド:

    ROSA_PUBLIC_ROUTE_TABLE_ID=$(aws ec2 describe-route-tables \
      --filters "Name=vpc-id,Values=vpc-0b721449398429559" "Name=association.main,Values=true" \
    1
    
      --query "RouteTables[*].RouteTableId" \
      --output text \
      --region eu-west-1
    )
    aws ec2 create-route \
      --route-table-id ${ROSA_PUBLIC_ROUTE_TABLE_ID} \
      --destination-cidr-block 192.168.0.0/16 \
    2
    
      --vpc-peering-connection-id pcx-0cb23d66dea3dca9f \
      --region eu-west-1
    Copy to Clipboard Toggle word wrap

    1
    ROSA クラスター VPC
    2
    これは Aurora VPC の作成時に使用した cidr ブロックと同じである必要があります。
  7. Aurora セキュリティーグループを更新します。

    コマンド:

    AURORA_SECURITY_GROUP_ID=$(aws ec2 describe-security-groups \
      --filters "Name=group-name,Values=keycloak-aurora-security-group" \
      --query "SecurityGroups[*].GroupId" \
      --region eu-west-1 \
      --output text
    )
    aws ec2 authorize-security-group-ingress \
      --group-id ${AURORA_SECURITY_GROUP_ID} \
      --protocol tcp \
      --port 5432 \
      --cidr 10.0.17.0/24 \
    1
    
      --region eu-west-1
    Copy to Clipboard Toggle word wrap

    1
    ROSA クラスターの "machine_cidr"

    出力:

    {
        "Return": true,
        "SecurityGroupRules": [
            {
                "SecurityGroupRuleId": "sgr-0785d2f04b9cec3f5",
                "GroupId": "sg-0d746cc8ad8d2e63b",
                "GroupOwnerId": "606671647913",
                "IsEgress": false,
                "IpProtocol": "tcp",
                "FromPort": 5432,
                "ToPort": 5432,
                "CidrIpv4": "10.0.17.0/24"
            }
        ]
    }
    Copy to Clipboard Toggle word wrap

8.3. 接続の検証

ROSA クラスターと Aurora DB クラスターの間で接続が可能であることを確認する最も簡単な方法は、Openshift クラスターに psql をデプロイし、ライターエンドポイントへの接続を試みることです。

次のコマンドは、デフォルトの namespace に Pod を作成し、可能であれば Aurora クラスターとの psql 接続を確立します。Pod シェルを終了すると、Pod は削除されます。

USER=keycloak 
1

PASSWORD=secret99 
2

DATABASE=keycloak 
3

HOST=$(aws rds describe-db-clusters \
  --db-cluster-identifier keycloak-aurora \
4

  --query 'DBClusters[*].Endpoint' \
  --region eu-west-1 \
  --output text
)
oc run -i --tty --rm debug --image=postgres:15 --restart=Never -- psql postgresql://${USER}:${PASSWORD}@${HOST}/${DATABASE}
Copy to Clipboard Toggle word wrap
1
Aurora DB ユーザー。これは DB の作成時に使用した --master-username と同じものにすることができます。
2
Aurora DB ユーザーパスワード。これは DB の作成時に使用した --master—​user-password と同じものにすることができます。
3
Aurora DB の名前 (--database-name など)。
4
Aurora DB クラスターの名前。

8.4. Aurora データベースを Red Hat build of Keycloak に接続する

この時点で Aurora データベースが確立され、すべての ROSA クラスターにリンクされています。ここでは、Aurora データベースを Red Hat build of Keycloak に接続するために使用できる Red Hat build of Keycloak CR オプションを説明します。これらの変更は、Red Hat build of Keycloak Operator を使用して HA 用に Red Hat build of Keycloak をデプロイする の章で必要になります。JDBC URL は、Aurora データベースライターエンドポイントを使用するように設定されています。

  1. spec.db.urljdbc:aws-wrapper:postgresql://$HOST:5432/keycloak に更新します。$HOSTAurora ライターのエンドポイント URL です。
  2. spec.db.usernameSecret および spec.db.passwordSecret によって参照されるシークレットに、Aurora の作成時に定義したユーザー名とパスワードが含まれていることを確認します。

8.5. 次のステップ

Aurora データベースのデプロイメントが成功したら、Data Grid Operator を使用して HA 用の Data Grid をデプロイする に進みます。

第9章 Data Grid Operator を使用した HA 用の Data Grid のデプロイ

この章では、Data Grid を複数クラスター環境 (クロスサイト) にデプロイするために必要な手順を説明します。わかりやすくするために、このトピックでは、Red Hat build of Keycloak を外部 Data Grid で使用できる最小限の設定を使用します。

この章では、Site-A および Site-B という名前の 2 つの OpenShift クラスターを想定しています。

これは、マルチサイトデプロイメントの概念 の章で説明されている概念に沿うビルディングブロックです。概要は、マルチサイトデプロイメント の章を参照してください。

重要

外部 Data Grid デプロイメントでサポートされているのは、Data Grid バージョン 8.5.2 以降のパッチリリースのみです。

9.1. アーキテクチャー

このセットアップでは、低遅延のネットワーク接続で接続された 2 つのサイトに、同期的にレプリケートする 2 つの Data Grid クラスターがデプロイされています。このようなシナリオの例としては、2 つのアベイラビリティーゾーンがある 1 つの AWS リージョンが考えられます。

わかりやすくするために、Red Hat build of Keycloak、ロードバランサー、およびデータベースは次の図から削除されています。

9.2. 前提条件

  • OpenShift または Kubernetes クラスターが実行中である。
  • Data Grid Operator を理解している。

9.3. 手順

  1. Data Grid Operator をインストールします。
  2. Data Grid クラスターにアクセスするための認証情報を設定します。

    Red Hat build of Keycloak が Data Grid クラスターで認証できるようにするには、この認証情報が必要です。次の identities.yaml ファイルで、管理者権限を持つユーザー名とパスワードを設定します。

    credentials:
      - username: developer
        password: strong-password
        roles:
          - admin
    Copy to Clipboard Toggle word wrap

    identities.yaml は、次のいずれかの方法でシークレットに設定できます。

    • Kubernetes リソースとして:

      認証情報シークレット

      apiVersion: v1
      kind: Secret
      type: Opaque
      metadata:
        name: connect-secret
        namespace: keycloak
      data:
        identities.yaml: Y3JlZGVudGlhbHM6CiAgLSB1c2VybmFtZTogZGV2ZWxvcGVyCiAgICBwYXNzd29yZDogc3Ryb25nLXBhc3N3b3JkCiAgICByb2xlczoKICAgICAgLSBhZG1pbgo= 
      1
      Copy to Clipboard Toggle word wrap

      1
      Base64 でエンコードした上記の例の identities.yaml
    • CLI の使用

      oc create secret generic connect-secret --from-file=identities.yaml
      Copy to Clipboard Toggle word wrap

      詳細は、認証の設定 ドキュメントを参照してください。

      これらのコマンドは両方の OpenShift クラスターで実行する必要があります。

  3. サービスアカウントを作成します。

    クラスター間の接続を確立するには、サービスアカウントが必要です。Data Grid Operator は、これを使用してリモートサイトからネットワーク設定を検査し、それに応じてローカル Data Grid クラスターを設定します。

    詳細は、マネージドのクロスサイトレプリケーション ドキュメントを参照してください。

    1. 次のように service-account-token シークレットタイプを作成します。同じ YAML ファイルを両方の OpenShift クラスターで使用できます。

      xsite-sa-secret-token.yaml

      apiVersion: v1
      kind: Secret
      metadata:
        name: ispn-xsite-sa-token 
      1
      
        annotations:
          kubernetes.io/service-account.name: "xsite-sa" 
      2
      
      type: kubernetes.io/service-account-token
      Copy to Clipboard Toggle word wrap

      1
      シークレットの名前。
      2
      サービスアカウントの名前。
    2. サービスアカウントを作成し、両方の OpenShift クラスターでアクセストークンを生成します。

      Site-A でサービスアカウントを作成する

      oc create sa -n keycloak xsite-sa
      oc policy add-role-to-user view -n keycloak -z xsite-sa
      oc create -f xsite-sa-secret-token.yaml
      oc get secrets ispn-xsite-sa-token -o jsonpath="{.data.token}" | base64 -d > Site-A-token.txt
      Copy to Clipboard Toggle word wrap

      Site-B でサービスアカウントを作成する

      oc create sa -n keycloak xsite-sa
      oc policy add-role-to-user view -n keycloak -z xsite-sa
      oc create -f xsite-sa-secret-token.yaml
      oc get secrets ispn-xsite-sa-token -o jsonpath="{.data.token}" | base64 -d > Site-B-token.txt
      Copy to Clipboard Toggle word wrap

    3. 次に、Site-A から Site-B にトークンをデプロイしてから、その逆を行います。

      Site-B のトークンを Site-A にデプロイする

      oc create secret generic -n keycloak xsite-token-secret \
        --from-literal=token="$(cat Site-B-token.txt)"
      Copy to Clipboard Toggle word wrap

      Site-A のトークンを Site-B にデプロイする

      oc create secret generic -n keycloak xsite-token-secret \
        --from-literal=token="$(cat Site-A-token.txt)"
      Copy to Clipboard Toggle word wrap

  4. TLS シークレットを作成します。

    この章では、Data Grid でクロスサイト通信に OpenShift ルートを使用します。この OpenShift ルートは、TLS の SNI 拡張を使用してトラフィックを正しい Pod に送信します。これを実現するために、JGroups は TLS ソケットを使用します。これには、正しい証明書を備えたキーストアとトラストストアが必要です。

    詳細は、クロスサイト接続のセキュリティー保護 ドキュメントまたはこちらの Red Hat Developer Guide を参照してください。

    キーストアとトラストストアは、OpenShift シークレットでアップロードします。シークレットには、ファイルの内容、ファイルにアクセスするためのパスワード、およびストアのタイプを含めます。証明書とストアを作成する手順は、この章では説明しません。

    キーストアをシークレットとしてアップロードするには、次のコマンドを使用します。

    キーストアのデプロイ

    oc -n keycloak create secret generic xsite-keystore-secret \
      --from-file=keystore.p12="./certs/keystore.p12" \ 
    1
    
      --from-literal=password=secret \ 
    2
    
      --from-literal=type=pkcs12 
    3
    Copy to Clipboard Toggle word wrap

    1
    ファイル名とキーストアへのパス。
    2
    キーストアにアクセスするためのパスワード。
    3
    キーストアのタイプ。

    トラストストアをシークレットとしてアップロードするには、次のコマンドを使用します。

    トラストストアのデプロイ

    oc -n keycloak create secret generic xsite-truststore-secret \
            --from-file=truststore.p12="./certs/truststore.p12" \  
    1
    
            --from-literal=password=caSecret \  
    2
    
            --from-literal=type=pkcs12  
    3
    Copy to Clipboard Toggle word wrap

    1
    ファイル名とトラストストアへのパス。
    2
    トラストストアにアクセスするためのパスワード。
    3
    トラストストアのタイプ。
    注記

    キーストアとトラストストアは、両方の OpenShift クラスターにアップロードする必要があります。

  5. クロスサイトを有効にして Data Grid のクラスターを作成する

    クロスサイトの設定 ドキュメントに、上記の手順を含め、クロスサイトを有効にして Data Grid クラスターを作成および設定する方法に関するすべての情報が記載されています。

    この章では、上記の手順のコマンドによって作成された認証情報、トークン、および TLS キーストア/トラストストアを使用した基本的な例を示します。

    Site-AInfinispan CR

    apiVersion: infinispan.org/v1
    kind: Infinispan
    metadata:
      name: infinispan 
    1
    
      namespace: keycloak
      annotations:
        infinispan.org/monitoring: 'true' 
    2
    
    spec:
      replicas: 3
      jmx:
        enabled: true
      security:
        endpointSecretName: connect-secret 
    3
    
      service:
        type: DataGrid
        sites:
          local:
            name: site-a 
    4
    
            expose:
              type: Route 
    5
    
            maxRelayNodes: 128
            encryption:
              transportKeyStore:
                secretName: xsite-keystore-secret 
    6
    
                alias: xsite 
    7
    
                filename: keystore.p12 
    8
    
              routerKeyStore:
                secretName: xsite-keystore-secret 
    9
    
                alias: xsite 
    10
    
                filename: keystore.p12 
    11
    
              trustStore:
                secretName: xsite-truststore-secret 
    12
    
                filename: truststore.p12 
    13
    
          locations:
            - name: site-b 
    14
    
              clusterName: infinispan
              namespace: keycloak 
    15
    
              url: openshift://api.site-b 
    16
    
              secretName: xsite-token-secret 
    17
    Copy to Clipboard Toggle word wrap

    1
    クラスター名。
    2
    Prometheus によるクラスターの監視を許可します。
    3
    カスタムの認証情報を使用する場合は、ここでシークレット名を設定します。
    4
    ローカルサイトの名前。この場合は Site-A です。
    5
    OpenShift ルートを使用したクロスサイト接続の公開。
    6 9
    前のステップで定義したキーストアが存在するシークレット名。
    7 10
    キーストア内の証明書のエイリアス。
    8 11
    前のステップで定義したキーストアの秘密鍵 (ファイル名)。
    12
    前のステップで定義したトラストストアが存在するシークレット名。
    13
    前のステップで定義したキーストアのトラストストアキー (ファイル名)。
    14
    リモートサイトの名前 (この場合は Site-B)。
    15
    リモートサイトの Data Grid クラスターの namespace。
    16
    リモートサイトの OpenShift API URL。
    17
    リモートサイトで認証するためのアクセストークンを含むシークレット。

    Site-BInfinispan CR も上記と同様です。ポイント 4、11、13 の違いに注意してください。

    Site-BInfinispan CR

    apiVersion: infinispan.org/v1
    kind: Infinispan
    metadata:
      name: infinispan 
    1
    
      namespace: keycloak
      annotations:
        infinispan.org/monitoring: 'true' 
    2
    
    spec:
      replicas: 3
      jmx:
        enabled: true
      security:
        endpointSecretName: connect-secret 
    3
    
      service:
        type: DataGrid
        sites:
          local:
            name: site-b 
    4
    
            expose:
              type: Route 
    5
    
            maxRelayNodes: 128
            encryption:
              transportKeyStore:
                secretName: xsite-keystore-secret 
    6
    
                alias: xsite 
    7
    
                filename: keystore.p12 
    8
    
              routerKeyStore:
                secretName: xsite-keystore-secret 
    9
    
                alias: xsite 
    10
    
                filename: keystore.p12 
    11
    
              trustStore:
                secretName: xsite-truststore-secret 
    12
    
                filename: truststore.p12 
    13
    
          locations:
            - name: site-a 
    14
    
              clusterName: infinispan
              namespace: keycloak 
    15
    
              url: openshift://api.site-a 
    16
    
              secretName: xsite-token-secret 
    17
    Copy to Clipboard Toggle word wrap

  6. Red Hat build of Keycloak 用のキャッシュを作成します。

    Red Hat build of Keycloak では、actionTokensauthenticationSessionsloginFailureswork のキャッシュが存在している必要があります。

    Data Grid Cache CR を使用すると、Data Grid クラスターにキャッシュをデプロイできます。クロスサイトのドキュメント に記載されているように、クロスサイトはキャッシュごとに有効にする必要があります。このドキュメントには、この章で使用するオプションの詳細が記載されています。次の例は、Site-ACache CR を示しています。

    1. Site-A で、上記の各キャッシュに対して次の内容の Cache CR を作成します。これは authenticationSessions キャッシュの例です。
    apiVersion: infinispan.org/v2alpha1
    kind: Cache
    metadata:
      name: authenticationsessions
      namespace: keycloak
    spec:
      clusterName: infinispan
      name: authenticationSessions
      template: |-
        distributedCache:
          mode: "SYNC"
          owners: "2"
          statistics: "true"
          remoteTimeout: "5000"
          encoding:
            media-type: "application/x-protostream"
          locking:
            acquireTimeout: "4000"
          transaction:
            mode: "NON_XA" 
    1
    
            locking: "PESSIMISTIC" 
    2
    
          stateTransfer:
            chunkSize: "16"
          backups:
            site-b: 
    3
    
              backup:
                strategy: "SYNC" 
    4
    
                timeout: "4500" 
    5
    
                failurePolicy: "FAIL" 
    6
    
                stateTransfer:
                  chunkSize: "16"
    Copy to Clipboard Toggle word wrap
    1 1
    トランザクションモード。
    2 2
    トランザクションで使用されるロックモード。
    3 3
    リモートサイト名。
    4 4
    クロスサイト通信ストラテジー。この場合は SYNC
    5 5
    クロスサイトレプリケーションのタイムアウト。
    6 9 6
    クロスサイトレプリケーションの失敗ポリシー。

    上記の例は、最善のデータ整合性を実現するために推奨される設定です。

    背景情報

    アクティブ/アクティブ設定では、両方のサイトでエントリーが同時に変更されるため、デッドロックが発生する可能性があります。

    transaction.mode: NON_XA では、そのようになった場合にデータの整合性を保ちながらトランザクションがロールバックされます。この場合、backup.failurePolicy: FAIL を設定する必要があります。トランザクションを安全にロールバックするためのエラーが出力されます。この状況が発生すると、Red Hat build of Keycloak は再試行を試みます。

    transaction.locking: PESSIMISTIC は唯一サポートされているロックモードです。OPTIMISTIC はネットワークコストが高いため推奨されません。同じ設定により、一方のサイトにアクセスできない間にもう一方のサイトが更新されることも防止されます。

    backup.strategy: SYNC では、Red Hat build of Keycloak のリクエストが完了したときに、データが他のサイトで表示および保存されます。

    注記

    locking.acquireTimeout を短くすると、デッドロックシナリオでフェイルファストを実行できます。backup.timeout は必ず locking.acquireTimeout よりも大きくなければなりません。

    Site-B の場合、上図のポイント 3 に示されている backups.<name> を除き、Cache CR は同じようになります。

    Site-B の authenticationSessions Cache CR

    apiVersion: infinispan.org/v2alpha1
    kind: Cache
    metadata:
      name: authenticationsessions
      namespace: keycloak
    spec:
      clusterName: infinispan
      name: authenticationSessions
      template: |-
        distributedCache:
          mode: "SYNC"
          owners: "2"
          statistics: "true"
          remoteTimeout: "5000"
          encoding:
            media-type: "application/x-protostream"
          locking:
            acquireTimeout: "4000"
          transaction:
            mode: "NON_XA" 
    1
    
            locking: "PESSIMISTIC" 
    2
    
          stateTransfer:
            chunkSize: "16"
          backups:
            site-a: 
    3
    
              backup:
                strategy: "SYNC" 
    4
    
                timeout: "4500" 
    5
    
                failurePolicy: "FAIL" 
    6
    
                stateTransfer:
                  chunkSize: "16"
    Copy to Clipboard Toggle word wrap

9.4. デプロイメントの確認

Data Grid クラスターが形成され、OpenShift クラスター間にクロスサイト接続が確立されていることを確認します。

Data Grid クラスターが形成されるまで待機する

oc wait --for condition=WellFormed --timeout=300s infinispans.infinispan.org -n keycloak infinispan
Copy to Clipboard Toggle word wrap

Data Grid のクロスサイト接続が確立されるまで待機する

oc wait --for condition=CrossSiteViewFormed --timeout=300s infinispans.infinispan.org -n keycloak infinispan
Copy to Clipboard Toggle word wrap

9.5. Red Hat build of Keycloak と Data Grid を接続する

この時点で Data Grid サーバーは実行されています。ここでは、それを Red Hat build of Keycloak に接続するために必要な Red Hat build of Keycloak CR の変更をて説明します。これらの変更は、Red Hat build of Keycloak Operator を使用して HA 用に Red Hat build of Keycloak をデプロイする の章で必要になります。

  1. 外部 Data Grid デプロイメントに接続するためのユーザー名とパスワードを使用してシークレットを作成します。

    apiVersion: v1
    kind: Secret
    metadata:
      name: remote-store-secret
      namespace: keycloak
    type: Opaque
    data:
      username: ZGV2ZWxvcGVy # base64 encoding for 'developer'
      password: c2VjdXJlX3Bhc3N3b3Jk # base64 encoding for 'secure_password'
    Copy to Clipboard Toggle word wrap
  2. 以下に示すように、additionalOptions を使用して Red Hat build of Keycloak カスタムリソースを拡張します。

    注記

    メモリー、リソース、データベース設定は、Red Hat build of Keycloak Operator を使用した HA 用の Red Hat build of Keycloak のデプロイ の章で説明したため、以下の CR では省略されています。管理者はこれらの設定をそのままにしておく必要があります。

    apiVersion: k8s.keycloak.org/v2alpha1
    kind: Keycloak
    metadata:
      labels:
        app: keycloak
      name: keycloak
      namespace: keycloak
    spec:
      additionalOptions:
        - name: cache-remote-host 
    1
    
          value: "infinispan.keycloak.svc"
        - name: cache-remote-port 
    2
    
          value: "11222"
        - name: cache-remote-username 
    3
    
          secret:
            name: remote-store-secret
            key: username
        - name: cache-remote-password 
    4
    
          secret:
            name: remote-store-secret
            key: password
        - name: spi-connections-infinispan-quarkus-site-name 
    5
    
          value: keycloak
    Copy to Clipboard Toggle word wrap
    1 1
    リモート Data Grid クラスターのホスト名。
    2 2
    リモート Data Grid クラスターのポート。これはオプションであり、デフォルトは 11222 です。
    3 3
    Data Grid のユーザー名認証情報を含むシークレットの name および key
    4 4
    Data Grid のパスワード認証情報を含むシークレットの name および key
    5 5
    spi-connections-infinispan-quarkus-site-name は、リモートストアの使用時に Red Hat build of Keycloak が Infinispan キャッシュのデプロイメント用に必要とする任意の Data Grid サイト名です。このサイト名は、Infinispan キャッシュにのみ関連しており、外部 Data Grid デプロイメントの値と一致させる必要はありません。Data Grid Operator を使用した HA 用の Data Grid のデプロイ など、クロス DC セットアップで Red Hat build of Keycloak に複数のサイトを使用している場合、サイト名は各サイトで異なる必要があります。

9.5.1. アーキテクチャー

この設定では、TLS 1.3 で保護された TCP 接続を使用して、Red Hat build of Keycloak を Data Grid に接続します。Red Hat build of Keycloak のトラストストアを使用して、Data Grid のサーバー証明書を検証します。Red Hat build of Keycloak は、下記の前提条件に基づいて OpenShift 上の Operator を使用してデプロイされます。そのため、Data Grid のサーバー証明書への署名に使用されるトラストストアに service-ca.crt が Operator によってすでに追加されています。その他の環境では、Red Hat build of Keycloak のトラストストアに必要な証明書を追加してください。

9.6. 次のステップ

Aurora AWS データベースと Data Grid がデプロイされ、実行されたら、Red Hat build of Keycloak Operator を使用して HA 用の Red Hat build of Keycloak をデプロイする の章で説明されている手順を使用して Red Hat build of Keycloak をデプロイし、作成したすべてのビルディングブロックに接続します。

9.7. 関連するオプション

Expand
 

cache-remote-host

リモートストア設定のリモートサーバーのホスト名。

これは、XML ファイルで指定された設定の remote-server タグの host 属性を置き換えます (cache-config-file オプションを参照)。このオプションを指定する場合、cache-remote-usernamecache-remote-password も必要となり、XML ファイル内に関連する設定を含めることができません。

CLI: --cache-remote-host
Env: KC_CACHE_REMOTE_HOST

 

cache-remote-password

リモートストアのリモートサーバーへの認証に使用するパスワード。

これは、XML ファイルで指定された設定の digest タグの password 属性を置き換えます (cache-config-file オプションを参照)。オプションを指定する場合、cache-remote-username も必要となり、XML ファイル内の関連する設定を含めることはできません。

CLI: --cache-remote-password
Env: KC_CACHE_REMOTE_PASSWORD

リモートホストが設定されている場合にのみ使用可能

 

cache-remote-port

リモートストア設定用のリモートサーバーのポート。

これは、XML ファイルで指定された設定の remote-server タグの port 属性を置き換えます (cache-config-file オプションを参照)。

CLI: --cache-remote-port
Env: KC_CACHE_REMOTE_PORT

リモートホストが設定されている場合にのみ使用可能

11222 (デフォルト)

cache-remote-tls-enabled

TLS サポートを有効にして、保護されたリモート Infinispan サーバーと通信します。

実稼働環境では有効にすることを推奨します。

CLI: --cache-remote-tls-enabled
Env: KC_CACHE_REMOTE_TLS_ENABLED

リモートホストが設定されている場合にのみ使用可能

true (デフォルト)、false

cache-remote-username

リモートストアのリモートサーバーへの認証に使用するユーザー名。

これは、XML ファイルで指定された設定の digest タグの username 属性を置き換えます (cache-config-file オプションを参照)。オプションを指定する場合、cache-remote-password も必要となり、XML ファイル内の関連する設定を含めることはできません。

CLI: --cache-remote-username
Env: KC_CACHE_REMOTE_USERNAME

リモートホストが設定されている場合にのみ使用可能

 

第10章 Red Hat build of Keycloak Operator を使用した HA 用の Red Hat build of Keycloak のデプロイ

ここでは、1 つの Pod の障害から回復する、負荷テスト実施済みの Kubernetes 用の高度な Red Hat build of Keycloak の設定を説明します。

以下の手順は、マルチサイトデプロイメントの概念 の章で説明されているセットアップで使用することを想定しています。これは、マルチサイトデプロイメントのビルディングブロック の章で説明されている他のビルディングブロックとともに使用してください。

10.1. 前提条件

10.2. 手順

  1. CPU およびメモリーリソースのサイジングの概念 の章を使用して、デプロイメントのサイジングを決定します。
  2. Red Hat build of Keycloak Operator のインストール の章の説明に従って、Red Hat build of Keycloak Operator をインストールします。
  3. 以下の設定ファイルには、複数のアベイラビリティーゾーンへの AWS Aurora のデプロイ で説明されている、Aurora データベースへの接続に関連するオプションが含まれています。
  4. 以下の設定ファイルには、Data Grid Operator を使用した HA 用の Data Grid のデプロイ で説明されている、Data Grid サーバーに接続するためのオプションが含まれています。
  5. Amazon Aurora PostgreSQL データベースで使用するために準備 したカスタムの Red Hat build of Keycloak イメージをビルドします。
  6. ステップ 1 で計算したリソース要求および制限を含む次の値を使用して、Red Hat build of Keycloak CR をデプロイします。

    apiVersion: k8s.keycloak.org/v2alpha1
    kind: Keycloak
    metadata:
      labels:
        app: keycloak
      name: keycloak
      namespace: keycloak
    spec:
      hostname:
        hostname: <KEYCLOAK_URL_HERE>
      resources:
        requests:
          cpu: "2"
          memory: "1250M"
        limits:
          cpu: "6"
          memory: "2250M"
      db:
        vendor: postgres
        url: jdbc:aws-wrapper:postgresql://<AWS_AURORA_URL_HERE>:5432/keycloak
        poolMinSize: 30 
    1
    
        poolInitialSize: 30
        poolMaxSize: 30
        usernameSecret:
          name: keycloak-db-secret
          key: username
        passwordSecret:
          name: keycloak-db-secret
          key: password
      image: <KEYCLOAK_IMAGE_HERE> 
    2
    
      startOptimized: false 
    3
    
      features:
        enabled:
          - multi-site 
    4
    
      transaction:
        xaEnabled: false 
    5
    
      additionalOptions:
    
        - name: http-max-queued-requests
          value: "1000"
        - name: log-console-output
          value: json
        - name: metrics-enabled 
    6
    
          value: 'true'
        - name: http-pool-max-threads 
    7
    
          value: "66"
        - name: cache-remote-host
          value: "infinispan.keycloak.svc"
        - name: cache-remote-port
          value: "11222"
        - name: cache-remote-username
          secret:
            name: remote-store-secret
            key: username
        - name: cache-remote-password
          secret:
            name: remote-store-secret
            key: password
        - name: spi-connections-infinispan-quarkus-site-name
          value: keycloak
        - name: db-driver
          value: software.amazon.jdbc.Driver
      http:
        tlsSecret: keycloak-tls-secret
      instances: 3
    Copy to Clipboard Toggle word wrap
    1
    データベースのステートメントキャッシュを許可するには、データベース接続プールの初期サイズ、最大サイズ、最小サイズが同一である必要があります。この数値はシステムのニーズに合わせて調整してください。Red Hat build of Keycloak の組み込みキャッシュにより、ほとんどのリクエストはデータベースに影響を与えないため、このように変更すると、1 秒あたり数百件のリクエストを処理できます。詳細は、データベース接続プールの概念 の章を参照してください。
    2 3
    Red Hat build of Keycloak イメージへの URL を指定します。イメージが最適化されている場合は、startOptimized フラグを true に設定します。
    4
    ロードバランサープローブ /lb-check などのマルチサイトサポートの追加機能を有効にします。
    5
    XA トランザクションは、Amazon Web Services JDBC Driver ではサポートされていません。
    6
    負荷がかかっているシステムを分析できるように、メトリクスエンドポイントを有効にします。この設定の欠点は、外部の Red Hat build of Keycloak エンドポイントでメトリクスが利用可能になるため、エンドポイントが外部から利用できないようにフィルターを追加する必要があることです。Red Hat build of Keycloak の前にリバースプロキシーを使用して、これらの URL をフィルタリングして除外します。
    7
    Red Hat build of Keycloak スレッドの数をさらに制限することを検討してもよいでしょう。要求された CPU 制限に達すると、複数の同時実行スレッドが原因で Kubernetes によるスロットリングが発生するためです。詳細は、スレッドプールの設定の概念 の章を参照してください。

10.3. デプロイメントの確認

Red Hat build of Keycloak デプロイメントの準備ができていることを確認します。

oc wait --for=condition=Ready keycloaks.k8s.keycloak.org/keycloak
oc wait --for=condition=RollingUpdate=False keycloaks.k8s.keycloak.org/keycloak
Copy to Clipboard Toggle word wrap

10.4. オプション: 負荷制限

負荷制限を有効にするには、キューに入れられるリクエストの数を制限します。

キューに入れられる HTTP リクエストの最大数による負荷制限

spec:
  additionalOptions:
    - name: http-max-queued-requests
      value: "1000"
Copy to Clipboard Toggle word wrap

超過したリクエストはすべて HTTP 503 で処理されます。詳細は、負荷制限に関する スレッドプールの設定の概念 の章を参照してください。

10.5. オプション: スティッキーセッションの無効化

HAProxy によって実行される負荷分散は、OpenShift および Red Hat build of Keycloak Operator が提供するデフォルトのパススルー Ingress セットアップで実行される場合、ソースの IP アドレスに基づくスティッキーセッションを使用して実行されます。負荷テストを実行するとき、または HAProxy の前にリバースプロキシーがあるときは、1 つの Red Hat build of Keycloak Pod ですべてのリクエストを受信しないように、この設定を無効にすることができます。

Red Hat build of Keycloak カスタムリソースの spec に次の補足設定を追加して、スティッキーセッションを無効にします。

spec:
  ingress:
    enabled: true
    annotations:
      # When running load tests, disable sticky sessions on the OpenShift HAProxy router
      # to avoid receiving all requests on a single Red Hat build of Keycloak Pod.
      haproxy.router.openshift.io/balance: roundrobin
      haproxy.router.openshift.io/disable_cookies: 'true'
Copy to Clipboard Toggle word wrap

第11章 AWS Global Accelerator ロードバランサーをデプロイする

このトピックでは、マルチサイト Red Hat build of Keycloak デプロイメント間でトラフィックをルーティングするために使用する AWS Global Accelerator のデプロイ手順を説明します。

このデプロイメントは、マルチサイトデプロイメントの概念 の章で説明されているセットアップで使用することを想定しています。このデプロイメントは、マルチサイトデプロイメントのビルディングブロック の章で説明されている他のビルディングブロックとともに使用してください。

注記

以下のブループリントは、機能的に完全な最小限の例を示すためのものであり、通常のインストールに適したベースラインのパフォーマンスを実現します。ただし、お使いの環境、組織の標準、セキュリティーのベストプラクティスに合わせて変更する必要があります。

11.1. 対象者

この章では、複数のアベイラビリティーゾーンの Red Hat build of Keycloak デプロイメントで Red Hat build of Keycloak クライアント接続フェイルオーバーを処理するために AWS Global Accelerator インスタンスをデプロイする方法を説明します。

11.2. アーキテクチャー

ユーザーリクエストが Red Hat build of Keycloak にルーティングされるようにするには、ロードバランサーを利用する必要があります。クライアント側での DNS キャッシュの問題を防ぐには、クライアントを両方のアベイラビリティーゾーンにルーティングするときに変更されない静的 IP アドレスを実装で使用する必要があります。

この章では、すべての Red Hat build of Keycloak クライアントリクエストを AWS Global Accelerator ロードバランサー経由でルーティングする方法を説明します。Red Hat build of Keycloak サイトに障害が発生した場合、Accelerator はすべてのクライアントリクエストが他の正常なサイトにルーティングされるようにします。両方のサイトが異常とマークされている場合、Accelerator は “fail-open” を実行し、ランダムに選択されたサイトにリクエストを転送します。

図11.1 AWS Global Accelerator のフェイルオーバー

Keycloak Pod を AWS Global Accelerator インスタンスへのエンドポイントとして使用できるようにするために、両方の ROSA クラスターに AWSNetwork Load Balancer (NLB) が作成されます。各クラスターエンドポイントには 128 の重み (最大重み 255 の半分) が割り当てられ、両方のクラスターが正常な場合にアクセラレータートラフィックが両方のアベイラビリティーゾーンに均等にルーティングされます。

11.3. 前提条件

  • ROSA ベースの Multi-AZ Red Hat build of Keycloak デプロイメント

11.4. 手順

  1. ネットワークロードバランサーを作成します。

    Red Hat build of Keycloak クラスターごとに次の操作を実行します。

    1. ROSA クラスターにログインします。
    2. Kubernetes ロードバランサーサービスを作成します。

      コマンド:

      cat <<EOF | oc apply -n $NAMESPACE -f - 
      1
      
        apiVersion: v1
        kind: Service
        metadata:
          name: accelerator-loadbalancer
          annotations:
            service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: accelerator=${ACCELERATOR_NAME},site=${CLUSTER_NAME},namespace=${NAMESPACE} 
      2
      
            service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
            service.beta.kubernetes.io/aws-load-balancer-healthcheck-path: "/lb-check"
            service.beta.kubernetes.io/aws-load-balancer-healthcheck-protocol: "https"
            service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: "10" 
      3
      
            service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: "3" 
      4
      
            service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: "3" 
      5
      
        spec:
          ports:
          - name: https
            port: 443
            protocol: TCP
            targetPort: 8443
          selector:
            app: keycloak
            app.kubernetes.io/instance: keycloak
            app.kubernetes.io/managed-by: keycloak-operator
          sessionAffinity: None
          type: LoadBalancer
      EOF
      Copy to Clipboard Toggle word wrap

      1
      $NAMESPACE は Red Hat build of Keycloak デプロイメントの namespace に置き換えてください。
      2
      AWS によって作成されたリソースにタグを追加して、後で取得できるようにします。ACCELERATOR_NAME は後続の手順で作成される Global Accelerator の名前、CLUSTER_NAME は現在のサイトの名前でなければなりません。
      3
      ヘルスチェックプローブの実行頻度 (秒単位)
      4
      NLB を正常とみなすために必要なヘルスチェックの合格回数
      5
      NLB を正常ではないとみなすために必要なヘルスチェックの不合格回数
    3. 後で必要になるため、DNS ホスト名をメモしておいてください。

      コマンド:

      oc -n $NAMESPACE get svc accelerator-loadbalancer --template="{{range .status.loadBalancer.ingress}}{{.hostname}}{{end}}"
      Copy to Clipboard Toggle word wrap

      出力:

      abab80a363ce8479ea9c4349d116bce2-6b65e8b4272fa4b5.elb.eu-west-1.amazonaws.com
      Copy to Clipboard Toggle word wrap

  2. Global Accelerator インスタンスを作成します。

    コマンド:

    aws globalaccelerator create-accelerator \
      --name example-accelerator \ 
    1
    
      --ip-address-type DUAL_STACK \ 
    2
    
      --region us-west-2 
    3
    Copy to Clipboard Toggle word wrap

    1
    作成するアクセラレーターの名前。必要に応じて更新します。
    2
    'DUAL_STACK' または 'IPV4' を使用できます。
    3
    すべての globalaccelerator コマンドで、必ず 'us-west-2' リージョンを使用する必要があります

    出力:

    {
        "Accelerator": {
            "AcceleratorArn": "arn:aws:globalaccelerator::606671647913:accelerator/e35a94dd-391f-4e3e-9a3d-d5ad22a78c71", 
    1
    
            "Name": "example-accelerator",
            "IpAddressType": "DUAL_STACK",
            "Enabled": true,
            "IpSets": [
                {
                    "IpFamily": "IPv4",
                    "IpAddresses": [
                        "75.2.42.125",
                        "99.83.132.135"
                    ],
                    "IpAddressFamily": "IPv4"
                },
                {
                    "IpFamily": "IPv6",
                    "IpAddresses": [
                        "2600:9000:a400:4092:88f3:82e2:e5b2:e686",
                        "2600:9000:a516:b4ef:157e:4cbd:7b48:20f1"
                    ],
                    "IpAddressFamily": "IPv6"
                }
            ],
            "DnsName": "a099f799900e5b10d.awsglobalaccelerator.com", 
    2
    
            "Status": "IN_PROGRESS",
            "CreatedTime": "2023-11-13T15:46:40+00:00",
            "LastModifiedTime": "2023-11-13T15:46:42+00:00",
            "DualStackDnsName": "ac86191ca5121e885.dualstack.awsglobalaccelerator.com" 
    3
    
        }
    }
    Copy to Clipboard Toggle word wrap

    1
    作成されたアクセラレーターインスタンスに関連付けられた ARN。後続のコマンドで使用します。
    2
    IPv4 Red Hat build of Keycloak クライアントが接続する DNS 名
    3
    IPv6 Red Hat build of Keycloak クライアントが接続する DNS 名
  3. アクセラレーターのリスナーを作成します。

    コマンド:

    aws globalaccelerator create-listener \
      --accelerator-arn 'arn:aws:globalaccelerator::606671647913:accelerator/e35a94dd-391f-4e3e-9a3d-d5ad22a78c71' \
      --port-ranges '[{"FromPort":443,"ToPort":443}]' \
      --protocol TCP \
      --region us-west-2
    Copy to Clipboard Toggle word wrap

    出力:

    {
        "Listener": {
            "ListenerArn": "arn:aws:globalaccelerator::606671647913:accelerator/e35a94dd-391f-4e3e-9a3d-d5ad22a78c71/listener/1f396d40",
            "PortRanges": [
                {
                    "FromPort": 443,
                    "ToPort": 443
                }
            ],
            "Protocol": "TCP",
            "ClientAffinity": "NONE"
        }
    }
    Copy to Clipboard Toggle word wrap

  4. リスナーのエンドポイントグループを作成します。

    コマンド:

    CLUSTER_1_ENDPOINT_ARN=$(aws elbv2 describe-load-balancers \
        --query "LoadBalancers[?DNSName=='abab80a363ce8479ea9c4349d116bce2-6b65e8b4272fa4b5.elb.eu-west-1.amazonaws.com'].LoadBalancerArn" \ 
    1
    
        --region eu-west-1 \ 
    2
    
        --output text
    )
    CLUSTER_2_ENDPOINT_ARN=$(aws elbv2 describe-load-balancers \
        --query "LoadBalancers[?DNSName=='a1c76566e3c334e4ab7b762d9f8dcbcf-985941f9c8d108d4.elb.eu-west-1.amazonaws.com'].LoadBalancerArn" \ 
    3
    
        --region eu-west-1 \ 
    4
    
        --output text
    )
    ENDPOINTS='[
      {
        "EndpointId": "'${CLUSTER_1_ENDPOINT_ARN}'",
        "Weight": 128,
        "ClientIPPreservationEnabled": false
      },
      {
        "EndpointId": "'${CLUSTER_2_ENDPOINT_ARN}'",
        "Weight": 128,
        "ClientIPPreservationEnabled": false
      }
    ]'
    aws globalaccelerator create-endpoint-group \
      --listener-arn 'arn:aws:globalaccelerator::606671647913:accelerator/e35a94dd-391f-4e3e-9a3d-d5ad22a78c71/listener/1f396d40' \ 
    5
    
      --traffic-dial-percentage 100 \
      --endpoint-configurations ${ENDPOINTS} \
      --endpoint-group-region eu-west-1 \ 
    6
    
      --region us-west-2
    Copy to Clipboard Toggle word wrap

    1 3
    クラスターの NLB の DNS ホスト名
    2 4 5
    前のステップで作成したリスナーの ARN
    6
    これはクラスターをホストする AWS リージョンである必要があります。

    出力:

    {
        "EndpointGroup": {
            "EndpointGroupArn": "arn:aws:globalaccelerator::606671647913:accelerator/e35a94dd-391f-4e3e-9a3d-d5ad22a78c71/listener/1f396d40/endpoint-group/2581af0dc700",
            "EndpointGroupRegion": "eu-west-1",
            "EndpointDescriptions": [
                {
                    "EndpointId": "arn:aws:elasticloadbalancing:eu-west-1:606671647913:loadbalancer/net/abab80a363ce8479ea9c4349d116bce2/6b65e8b4272fa4b5",
                    "Weight": 128,
                    "HealthState": "HEALTHY",
                    "ClientIPPreservationEnabled": false
                },
                {
                    "EndpointId": "arn:aws:elasticloadbalancing:eu-west-1:606671647913:loadbalancer/net/a1c76566e3c334e4ab7b762d9f8dcbcf/985941f9c8d108d4",
                    "Weight": 128,
                    "HealthState": "HEALTHY",
                    "ClientIPPreservationEnabled": false
                }
            ],
            "TrafficDialPercentage": 100.0,
            "HealthCheckPort": 443,
            "HealthCheckProtocol": "TCP",
            "HealthCheckPath": "undefined",
            "HealthCheckIntervalSeconds": 30,
            "ThresholdCount": 3
        }
    }
    Copy to Clipboard Toggle word wrap

  5. オプション: カスタムドメインを設定します。

    カスタムドメインを使用している場合は、カスタムドメインでエイリアスまたは CNAME を設定して、カスタムドメインを AWS グローバルロードバランサーにポイントします。

  6. Red Hat build of Keycloak デプロイメントを更新または作成します。

    Red Hat build of Keycloak クラスターごとに次の操作を実行します。

    1. ROSA クラスターにログインします。
    2. Keycloak CR が次の設定になっていることを確認します。

      apiVersion: k8s.keycloak.org/v2alpha1
      kind: Keycloak
      metadata:
        name: keycloak
      spec:
        hostname:
          hostname: $HOSTNAME 
      1
      
        ingress:
          enabled: false 
      2
      Copy to Clipboard Toggle word wrap
      1
      Keycloak に接続するためにクライアントが使用するホスト名
      2
      すべての Red Hat build of Keycloak アクセスはプロビジョニングされた NLB 経由で行われるため、デフォルトの Ingress を無効にします。

      リクエスト転送が確実に期待通り機能するためには、Keycloak CR で、クライアントが Red Hat build of Keycloak インスタンスにアクセスするためのホスト名を指定する必要があります。これは、Global Accelerator に関連付けられた DualStackDnsName または DnsName ホスト名のいずれかになります。カスタムドメインを使用している場合は、カスタムドメインを AWS Globa Accelerator にポイントし、ここでカスタムドメインを使用します。

11.5. 検証

Global Accelerator がクラスターに接続するように正しく設定されていることを確認するには、上記で設定されたホスト名に移動して Red Hat build of Keycloak 管理コンソールを表示します。

11.6. 関連資料

第12章 AWS Lambda をデプロイしてレスポンスのないサイトを無効にする

この章では、マルチサイトデプロイメントの 2 つのサイト間におけるスプリットブレインシナリオを解決する方法を説明します。1 つのサイトに障害が発生するとレプリケーションが無効になるため、他のサイトは引き続きリクエストを処理できます。

このデプロイメントは、マルチサイトデプロイメントの概念 の章で説明されているセットアップで使用することを想定しています。このデプロイメントは、マルチサイトデプロイメントのビルディングブロック の章で説明されている他のビルディングブロックとともに使用してください。

注記

以下のブループリントは、機能的に完全な最小限の例を示すためのものであり、通常のインストールに適したベースラインのパフォーマンスを実現します。ただし、お使いの環境、組織の標準、セキュリティーのベストプラクティスに合わせて変更する必要があります。

12.1. アーキテクチャー

マルチサイトデプロイメントのサイト間でネットワーク通信障害が発生すると、2 つのサイト間でデータのレプリケーションを継続できなくなります。Data Grid には FAIL 障害ポリシーが設定されており、可用性よりも整合性が優先されます。したがって、ネットワーク接続を復元するかクロスサイトレプリケーションを無効にすることで障害が解決されるまで、すべてのユーザーリクエストにエラーメッセージが表示されます。

このようなシナリオでは、オンラインまたはオフラインとしてマークするサイトを判断するためにクォーラムが一般的に使用されます。ただし、マルチサイトデプロイメントは 2 サイトのみで構成されるため、これは不可能です。代わりに “フェンシング” を使用して、サイトの 1 つが他のサイトに接続できない場合はロードバランサー設定に 1 つのサイトのみ残るようにし、そのサイトだけが後続のユーザーリクエストを処理できるようにします。

フェンシングの手順では、ロードバランサーの設定に加え、2 つの Data Grid クラスター間のレプリケーションを無効にして、ロードバランサー設定に残っているサイトからのユーザーリクエストに対応できるようにします。その結果、レプリケーションが無効になるとサイトは同期されなくなります。

非同期状態から回復するには、サイトの同期 で説明されているとおり手動で再同期する必要があります。このような理由から、フェンシングによって削除されたサイトは、ネットワーク通信障害が解決されても自動的に再追加されません。削除したサイトは、サイトをオンラインにする で説明されている手順で 2 つのサイトを同期した後でなければ再度追加するべきではありません。

この章では、Prometheus アラート と AWS Lambda 関数を組み合わせてフェンシングを実装する方法を説明します。Data Grid サーバーのメトリクスによってスプリットブレインが検出されると、Prometheus アラートがトリガーされ、Prometheus AlertManager が AWS Lambda ベースの Webhook を呼び出します。トリガーされた Lambda 関数は、現在の Global Accelerator 設定を検査し、オフラインであると報告されたサイトを削除します。

両方のサイトがまだ稼働しているがネットワーク通信がダウンしている真のスプリットブレインシナリオでは、両方のサイトが同時に Webhook をトリガーする可能性があります。これを防止するために、一度に 1 つの Lambda インスタンスのみを実行できるようにします。AWS Lambda のロジックにより、ロードバランサー設定には必ず 1 つのサイトエントリーが残ります。

12.2. 前提条件

  • ROSA HCP ベースのマルチサイト Keycloak デプロイメント
  • AWS CLI がインストールされている
  • AWS Global Accelerator ロードバランサー
  • jq ツールがインストールされている

12.3. 手順

  1. Openshift ユーザーアラートルーティングを有効にします。

    コマンド:

    oc apply -f - << EOF
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: user-workload-monitoring-config
      namespace: openshift-user-workload-monitoring
    data:
      config.yaml: |
        alertmanager:
          enabled: true
          enableAlertmanagerConfig: true
    EOF
    oc -n openshift-user-workload-monitoring rollout status --watch statefulset.apps/alertmanager-user-workload
    Copy to Clipboard Toggle word wrap

  2. Lambda ウェブフックの認証に使用するユーザー名とパスワードの組み合わせを決定し、そのパスワードを保存する AWS シークレットを作成します。

    コマンド:

    aws secretsmanager create-secret \
      --name webhook-password \ 
    1
    
      --secret-string changeme \ 
    2
    
      --region eu-west-1 
    3
    Copy to Clipboard Toggle word wrap

    1
    シークレットの名前
    2
    認証に使用するパスワード
    3
    シークレットをホストする AWS リージョン
  3. Lambda の実行に使用するロールを作成します。

    コマンド:

    FUNCTION_NAME= 
    1
    
    ROLE_ARN=$(aws iam create-role \
      --role-name ${FUNCTION_NAME} \
      --assume-role-policy-document \
      '{
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Principal": {
              "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
          }
        ]
      }' \
      --query 'Role.Arn' \
      --region eu-west-1 \ 
    2
    
      --output text
    )
    Copy to Clipboard Toggle word wrap

    1
    Lambda および関連リソースに関連付ける任意の名前
    2
    Kubernetes クラスターをホストする AWS リージョン
  4. Lambda が AWS Secrets にアクセスできるように、'LambdaSecretManager' ポリシーを作成してアタッチします。

    コマンド:

    POLICY_ARN=$(aws iam create-policy \
      --policy-name LambdaSecretManager \
      --policy-document \
      '{
          "Version": "2012-10-17",
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": [
                      "secretsmanager:GetSecretValue"
                  ],
                  "Resource": "*"
              }
          ]
      }' \
      --query 'Policy.Arn' \
      --output text
    )
    aws iam attach-role-policy \
      --role-name ${FUNCTION_NAME} \
      --policy-arn ${POLICY_ARN}
    Copy to Clipboard Toggle word wrap

  5. ElasticLoadBalancingReadOnly ポリシーをアタッチして、Lambda がプロビジョニングされたネットワークロードバランサーに対してクエリーを実行できるようにします。

    コマンド:

    aws iam attach-role-policy \
      --role-name ${FUNCTION_NAME} \
      --policy-arn arn:aws:iam::aws:policy/ElasticLoadBalancingReadOnly
    Copy to Clipboard Toggle word wrap

  6. GlobalAcceleratorFullAccess ポリシーをアタッチして、Lambda が Global Accelerator EndpointGroup を更新できるようにします。

    コマンド:

    aws iam attach-role-policy \
      --role-name ${FUNCTION_NAME} \
      --policy-arn arn:aws:iam::aws:policy/GlobalAcceleratorFullAccess
    Copy to Clipboard Toggle word wrap

  7. 必要なフェンシングロジックを含む Lambda ZIP ファイルを作成します。

    コマンド:

    LAMBDA_ZIP=/tmp/lambda.zip
    cat << EOF > /tmp/lambda.py
    
    from urllib.error import HTTPError
    
    import boto3
    import jmespath
    import json
    import os
    import urllib3
    
    from base64 import b64decode
    from urllib.parse import unquote
    
    # Prevent unverified HTTPS connection warning
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    
    
    class MissingEnvironmentVariable(Exception):
        pass
    
    
    class MissingSiteUrl(Exception):
        pass
    
    
    def env(name):
        if name in os.environ:
            return os.environ[name]
        raise MissingEnvironmentVariable(f"Environment Variable '{name}' must be set")
    
    
    def handle_site_offline(labels):
        a_client = boto3.client('globalaccelerator', region_name='us-west-2')
    
        acceleratorDNS = labels['accelerator']
        accelerator = jmespath.search(f"Accelerators[?(DnsName=='{acceleratorDNS}'|| DualStackDnsName=='{acceleratorDNS}')]", a_client.list_accelerators())
        if not accelerator:
            print(f"Ignoring SiteOffline alert as accelerator with DnsName '{acceleratorDNS}' not found")
            return
    
        accelerator_arn = accelerator[0]['AcceleratorArn']
        listener_arn = a_client.list_listeners(AcceleratorArn=accelerator_arn)['Listeners'][0]['ListenerArn']
    
        endpoint_group = a_client.list_endpoint_groups(ListenerArn=listener_arn)['EndpointGroups'][0]
        endpoints = endpoint_group['EndpointDescriptions']
    
        # Only update accelerator endpoints if two entries exist
        if len(endpoints) > 1:
            # If the reporter endpoint is not healthy then do nothing for now
            # A Lambda will eventually be triggered by the other offline site for this reporter
            reporter = labels['reporter']
            reporter_endpoint = [e for e in endpoints if endpoint_belongs_to_site(e, reporter)][0]
            if reporter_endpoint['HealthState'] == 'UNHEALTHY':
                print(f"Ignoring SiteOffline alert as reporter '{reporter}' endpoint is marked UNHEALTHY")
                return
    
            offline_site = labels['site']
            endpoints = [e for e in endpoints if not endpoint_belongs_to_site(e, offline_site)]
            del reporter_endpoint['HealthState']
            a_client.update_endpoint_group(
                EndpointGroupArn=endpoint_group['EndpointGroupArn'],
                EndpointConfigurations=endpoints
            )
            print(f"Removed site={offline_site} from Accelerator EndpointGroup")
    
            take_infinispan_site_offline(reporter, offline_site)
            print(f"Backup site={offline_site} caches taken offline")
        else:
            print("Ignoring SiteOffline alert only one Endpoint defined in the EndpointGroup")
    
    
    def endpoint_belongs_to_site(endpoint, site):
        lb_arn = endpoint['EndpointId']
        region = lb_arn.split(':')[3]
        client = boto3.client('elbv2', region_name=region)
        tags = client.describe_tags(ResourceArns=[lb_arn])['TagDescriptions'][0]['Tags']
        for tag in tags:
            if tag['Key'] == 'site':
                return tag['Value'] == site
        return false
    
    
    def take_infinispan_site_offline(reporter, offlinesite):
        endpoints = json.loads(INFINISPAN_SITE_ENDPOINTS)
        if reporter not in endpoints:
            raise MissingSiteUrl(f"Missing URL for site '{reporter}' in 'INFINISPAN_SITE_ENDPOINTS' json")
    
        endpoint = endpoints[reporter]
        password = get_secret(INFINISPAN_USER_SECRET)
        url = f"https://{endpoint}/rest/v2/container/x-site/backups/{offlinesite}?action=take-offline"
        http = urllib3.PoolManager(cert_reqs='CERT_NONE')
        headers = urllib3.make_headers(basic_auth=f"{INFINISPAN_USER}:{password}")
        try:
            rsp = http.request("POST", url, headers=headers)
            if rsp.status >= 400:
                raise HTTPError(f"Unexpected response status '%d' when taking site offline", rsp.status)
            rsp.release_conn()
        except HTTPError as e:
            print(f"HTTP error encountered: {e}")
    
    
    def get_secret(secret_name):
        session = boto3.session.Session()
        client = session.client(
            service_name='secretsmanager',
            region_name=SECRETS_REGION
        )
        return client.get_secret_value(SecretId=secret_name)['SecretString']
    
    
    def decode_basic_auth_header(encoded_str):
        split = encoded_str.strip().split(' ')
        if len(split) == 2:
            if split[0].strip().lower() == 'basic':
                try:
                    username, password = b64decode(split[1]).decode().split(':', 1)
                except:
                    raise DecodeError
            else:
                raise DecodeError
        else:
            raise DecodeError
    
        return unquote(username), unquote(password)
    
    
    def handler(event, context):
        print(json.dumps(event))
    
        authorization = event['headers'].get('authorization')
        if authorization is None:
            print("'Authorization' header missing from request")
            return {
                "statusCode": 401
            }
    
        expectedPass = get_secret(WEBHOOK_USER_SECRET)
        username, password = decode_basic_auth_header(authorization)
        if username != WEBHOOK_USER and password != expectedPass:
            print('Invalid username/password combination')
            return {
                "statusCode": 403
            }
    
        body = event.get('body')
        if body is None:
            raise Exception('Empty request body')
    
        body = json.loads(body)
        print(json.dumps(body))
    
        if body['status'] != 'firing':
            print("Ignoring alert as status is not 'firing', status was: '%s'" % body['status'])
            return {
                "statusCode": 204
            }
    
        for alert in body['alerts']:
            labels = alert['labels']
            if labels['alertname'] == 'SiteOffline':
                handle_site_offline(labels)
    
        return {
            "statusCode": 204
        }
    
    
    INFINISPAN_USER = env('INFINISPAN_USER')
    INFINISPAN_USER_SECRET = env('INFINISPAN_USER_SECRET')
    INFINISPAN_SITE_ENDPOINTS = env('INFINISPAN_SITE_ENDPOINTS')
    SECRETS_REGION = env('SECRETS_REGION')
    WEBHOOK_USER = env('WEBHOOK_USER')
    WEBHOOK_USER_SECRET = env('WEBHOOK_USER_SECRET')
    
    EOF
    zip -FS --junk-paths ${LAMBDA_ZIP} /tmp/lambda.py
    Copy to Clipboard Toggle word wrap

  8. Lambda 関数を作成します。

    コマンド:

    aws lambda create-function \
      --function-name ${FUNCTION_NAME} \
      --zip-file fileb://${LAMBDA_ZIP} \
      --handler lambda.handler \
      --runtime python3.12 \
      --role ${ROLE_ARN} \
      --region eu-west-1 
    1
    Copy to Clipboard Toggle word wrap

    1
    Kubernetes クラスターをホストする AWS リージョン
  9. 関数 URL を公開して、Lambda を Webhook としてトリガーできるようにします。

    コマンド:

    aws lambda create-function-url-config \
      --function-name ${FUNCTION_NAME} \
      --auth-type NONE \
      --region eu-west-1 
    1
    Copy to Clipboard Toggle word wrap

    1
    Kubernetes クラスターをホストする AWS リージョン
  10. 関数 URL のパブリック呼び出しを許可します。

    コマンド:

    aws lambda add-permission \
      --action "lambda:InvokeFunctionUrl" \
      --function-name ${FUNCTION_NAME} \
      --principal "*" \
      --statement-id FunctionURLAllowPublicAccess \
      --function-url-auth-type NONE \
      --region eu-west-1 
    1
    Copy to Clipboard Toggle word wrap

    1
    Kubernetes クラスターをホストする AWS リージョン
  11. Lambda の環境変数を設定します。

    1. 各 Kubernetes クラスターで、公開された Data Grid URL エンドポイントを取得します。

      oc -n ${NAMESPACE} get route infinispan-external -o jsonpath='{.status.ingress[].host}' 
      1
      Copy to Clipboard Toggle word wrap
      1
      ${NAMESPACE} を、Data Grid サーバーが含まれる namespace に置き換えます。
    2. 必要な環境変数をアップロードします。

      ACCELERATOR_NAME= 
      1
      
      LAMBDA_REGION= 
      2
      
      CLUSTER_1_NAME= 
      3
      
      CLUSTER_1_ISPN_ENDPOINT= 
      4
      
      CLUSTER_2_NAME= 
      5
      
      CLUSTER_2_ISPN_ENDPOINT= 
      6
      
      INFINISPAN_USER= 
      7
      
      INFINISPAN_USER_SECRET= 
      8
      
      WEBHOOK_USER= 
      9
      
      WEBHOOK_USER_SECRET= 
      10
      
      
      INFINISPAN_SITE_ENDPOINTS=$(echo "{\"${CLUSTER_NAME_1}\":\"${CLUSTER_1_ISPN_ENDPOINT}\",\"${CLUSTER_2_NAME}\":\"${CLUSTER_2_ISPN_ENDPOINT\"}" | jq tostring)
      aws lambda update-function-configuration \
          --function-name ${ACCELERATOR_NAME} \
          --region ${LAMBDA_REGION} \
          --environment "{
            \"Variables\": {
              \"INFINISPAN_USER\" : \"${INFINISPAN_USER}\",
              \"INFINISPAN_USER_SECRET\" : \"${INFINISPAN_USER_SECRET}\",
              \"INFINISPAN_SITE_ENDPOINTS\" : ${INFINISPAN_SITE_ENDPOINTS},
              \"WEBHOOK_USER\" : \"${WEBHOOK_USER}\",
              \"WEBHOOK_USER_SECRET\" : \"${WEBHOOK_USER_SECERT}\",
              \"SECRETS_REGION\" : \"eu-central-1\"
            }
          }"
      Copy to Clipboard Toggle word wrap
      1
      デプロイメントで使用される AWS Global Accelerator の名前
      2
      Kubernetes クラスターと Lambda 関数をホストしている AWS リージョン
      3
      Data Grid Operator を使用した HA 用の Data Grid のデプロイ で定義されている 1 つの Data Grid サイトの名前
      4
      CLUSER_1_NAME サイトに関連付けられた Data Grid エンドポイント URL
      5
      2 番目の Data Grid サイトの名前
      6
      CLUSER_2_NAME サイトに関連付けられた Data Grid エンドポイント URL
      7
      サーバー上で REST リクエストを実行するのに十分な権限を持つ Data Grid ユーザーのユーザー名
      8
      Data Grid ユーザーに関連付けられたパスワードが含まれる AWS シークレットの名前
      9
      Lambda 関数へのリクエストの認証に使用されるユーザー名
      10
      Lambda 関数へのリクエストの認証に使用されるパスワードが含まれる AWS シークレットの名前
  12. Lambda 関数 URL を取得します。

    コマンド:

    aws lambda get-function-url-config \
      --function-name ${FUNCTION_NAME} \
      --query "FunctionUrl" \
      --region eu-west-1 \
    1
    
      --output text
    Copy to Clipboard Toggle word wrap

    1
    Lambda が作成された AWS リージョン

    出力:

    https://tjqr2vgc664b6noj6vugprakoq0oausj.lambda-url.eu-west-1.on.aws
    Copy to Clipboard Toggle word wrap

  13. 各 Kubernetes クラスターで、スプリットブレイン発生時に Lambda をトリガーする Prometheus アラートルーティングを設定します。

    コマンド:

    NAMESPACE= # The namespace containing your deployments
    oc apply -n ${NAMESPACE} -f - << EOF
    apiVersion: v1
    kind: Secret
    type: kubernetes.io/basic-auth
    metadata:
      name: webhook-credentials
    stringData:
      username: 'keycloak' 
    1
    
      password: 'changme' 
    2
    
    ---
    apiVersion: monitoring.coreos.com/v1beta1
    kind: AlertmanagerConfig
    metadata:
      name: example-routing
    spec:
      route:
        receiver: default
        groupBy:
          - accelerator
        groupInterval: 90s
        groupWait: 60s
        matchers:
          - matchType: =
            name: alertname
            value: SiteOffline
      receivers:
        - name: default
          webhookConfigs:
            - url: 'https://tjqr2vgc664b6noj6vugprakoq0oausj.lambda-url.eu-west-1.on.aws/' 
    3
    
              httpConfig:
                basicAuth:
                  username:
                    key: username
                    name: webhook-credentials
                  password:
                    key: password
                    name: webhook-credentials
                tlsConfig:
                  insecureSkipVerify: true
    ---
    apiVersion: monitoring.coreos.com/v1
    kind: PrometheusRule
    metadata:
      name: xsite-status
    spec:
      groups:
        - name: xsite-status
          rules:
            - alert: SiteOffline
              expr: 'min by (namespace, site) (vendor_jgroups_site_view_status{namespace="default",site="site-b"}) == 0' 
    4
    
              labels:
                severity: critical
                reporter: site-a 
    5
    
                accelerator: a3da6a6cbd4e27b02.awsglobalaccelerator.com 
    6
    Copy to Clipboard Toggle word wrap

    1
    Lambda リクエストの認証に必要なユーザー名
    2
    Lambda リクエストの認証に必要なパスワード
    3
    Lambda 関数 URL
    4
    namespace の値は Infinispan CR をホストする namespace、サイトは Infinispan CR の spec.service.sites.locations[0].name で定義されたリモートサイトでなければなりません。
    5
    Infinispan CR の spec.service.sites.local.name で定義されたローカルサイトの名前
    6
    Global Accelerator の DNS

12.4. 検証

Prometheus アラートが期待どおりに Webhook をトリガーすることをテストするには、次の手順を実行してスプリットブレインをシミュレートします。

  1. 各クラスターで以下を実行します。

    コマンド:

    oc -n openshift-operators scale --replicas=0 deployment/infinispan-operator-controller-manager 
    1
    
    oc -n openshift-operators rollout status -w deployment/infinispan-operator-controller-manager
    oc -n ${NAMESPACE} scale --replicas=0 deployment/infinispan-router 
    2
    
    oc -n ${NAMESPACE} rollout status -w deployment/infinispan-router
    Copy to Clipboard Toggle word wrap

    1
    次のステップで Operator がデプロイメントが再作成しないように、Data Grid Operator をスケールダウンします。
    2
    Gossip Router のデプロイメントをスケールダウンします。${NAMESPACE} は、Data Grid サーバーが含まれる namespace に置き換えます。
  2. Openshift コンソールの ObserveAlerting メニューを調べて、クラスターで SiteOffline イベントが発生したことを確認します。
  3. AWS コンソールで Global Accelerator EndpointGroup を調べます。エンドポイントが 1 つだけ存在するはずです。
  4. サイト間の接続を再確立するために、Data Grid Operator と Gossip Router をスケールアップします。

    コマンド:

    oc -n openshift-operators scale --replicas=1 deployment/infinispan-operator-controller-manager
    oc -n openshift-operators rollout status -w deployment/infinispan-operator-controller-manager
    oc -n ${NAMESPACE} scale --replicas=1 deployment/infinispan-router 
    1
    
    oc -n ${NAMESPACE} rollout status -w deployment/infinispan-router
    Copy to Clipboard Toggle word wrap

    1
    ${NAMESPACE} を、Data Grid サーバーが含まれる namespace に置き換えます。
  5. 各サイトの vendor_jgroups_site_view_status メトリクスを調べます。値が 1 の場合、サイトがアクセス可能であることを示します。
  6. 両方のエンドポイントが含まれるように Accelerator EndpointGroup を更新します。詳細は、サイトをオンラインにする の章を参照してください。

12.5. 関連資料

第13章 サイトをオフラインにする

13.1. この手順を使用する状況

デプロイメントライフサイクル中に、メンテナンスやソフトウェアのアップグレードのために、サイトの 1 つを一時的にオフラインにしなければならないことがあります。メンテナンスが必要なサイトにユーザーリクエストがルーティングされないようにするには、ロードバランサー設定からサイトを削除する必要があります。

13.2. 手順

トラフィックがルーティングされないようにロードバランサーからサイトを削除するには、次の手順に従います。

13.2.1. Global Accelerator

  1. オンライン状態のまま維持するサイトに関連付けられた Network Load Balancer (NLB) の ARN を決定します。

    コマンド:

    NAMESPACE= 
    1
    
    REGION= 
    2
    
    HOSTNAME=$(oc -n $NAMESPACE get svc accelerator-loadbalancer --template="{{range .status.loadBalancer.ingress}}{{.hostname}}{{end}}")
    aws elbv2 describe-load-balancers \
      --query "LoadBalancers[?DNSName=='${HOSTNAME}'].LoadBalancerArn" \
      --region ${REGION} \
      --output text
    Copy to Clipboard Toggle word wrap

    1
    Keycloak デプロイメントを格納する Kubernetes namespace
    2
    Kubernetes クラスターをホストしている AWS リージョン

    出力:

    arn:aws:elasticloadbalancing:eu-west-1:606671647913:loadbalancer/net/a49e56e51e16843b9a3bc686327c907b/9b786f80ed4eba3d
    Copy to Clipboard Toggle word wrap

  2. 1 つのサイトのみ含まれるように Accelerator EndpointGroup を更新します。

    1. Global Accelerator の EndpointGroup 内の現在のエンドポイントをリスト表示します。

      コマンド:

      ACCELERATOR_NAME= 
      1
      
      ACCELERATOR_ARN=$(aws globalaccelerator list-accelerators \
        --query "Accelerators[?Name=='${ACCELERATOR_NAME}'].AcceleratorArn" \
        --region us-west-2 \ 
      2
      
        --output text
      )
      LISTENER_ARN=$(aws globalaccelerator list-listeners \
        --accelerator-arn ${ACCELERATOR_ARN} \
        --query "Listeners[*].ListenerArn" \
        --region us-west-2 \
        --output text
      )
      aws globalaccelerator list-endpoint-groups \
        --listener-arn ${LISTENER_ARN} \
        --region us-west-2
      Copy to Clipboard Toggle word wrap

      1
      更新するアクセラレーターの名前
      2
      AWS Global Accelerators を紹介する場合、必ずリージョンを us-west-2 に設定する必要があります。

      出力:

      {
          "EndpointGroups": [
              {
                  "EndpointGroupArn": "arn:aws:globalaccelerator::606671647913:accelerator/d280fc09-3057-4ab6-9330-6cbf1f450748/listener/8769072f/endpoint-group/a30b64ec1700",
                  "EndpointGroupRegion": "eu-west-1",
                  "EndpointDescriptions": [
                      {
                          "EndpointId": "arn:aws:elasticloadbalancing:eu-west-1:606671647913:loadbalancer/net/a49e56e51e16843b9a3bc686327c907b/9b786f80ed4eba3d",
                          "Weight": 128,
                          "HealthState": "HEALTHY",
                          "ClientIPPreservationEnabled": false
                      },
                      {
                          "EndpointId": "arn:aws:elasticloadbalancing:eu-west-1:606671647913:loadbalancer/net/a3c75f239541c4a6e9c48cf8d48d602f/5ba333e87019ccf0",
                          "Weight": 128,
                          "HealthState": "HEALTHY",
                          "ClientIPPreservationEnabled": false
                      }
                  ],
                  "TrafficDialPercentage": 100.0,
                  "HealthCheckPort": 443,
                  "HealthCheckProtocol": "TCP",
                  "HealthCheckIntervalSeconds": 30,
                  "ThresholdCount": 3
              }
          ]
      }
      Copy to Clipboard Toggle word wrap

    2. 手順 1 で取得した NLB のみが含まれるように EndpointGroup を更新します。

      コマンド:

      aws globalaccelerator update-endpoint-group \
        --endpoint-group-arn arn:aws:globalaccelerator::606671647913:accelerator/d280fc09-3057-4ab6-9330-6cbf1f450748/listener/8769072f/endpoint-group/a30b64ec1700 \
        --region us-west-2 \
        --endpoint-configurations '
        [
          {
              "EndpointId": "arn:aws:elasticloadbalancing:eu-west-1:606671647913:loadbalancer/net/a49e56e51e16843b9a3bc686327c907b/9b786f80ed4eba3d",
              "Weight": 128,
              "ClientIPPreservationEnabled": false
          }
        ]
      '
      Copy to Clipboard Toggle word wrap

第14章 サイトをオンラインにする

14.1. この手順を使用する状況

この手順では、オフラインにされている Keycloak サイトを Global Accelerator に再度追加して、クライアントリクエストを処理できるようにする方法を説明します。

14.2. 手順

Keycloak サイトを AWS Global Accelerator に再度追加してクライアントリクエストを処理できるようにするには、次の手順を実行します。

14.2.1. Global Accelerator

  1. オンラインにするサイトに関連付けられた Network Load Balancer (NLB) の ARN を決定します。

    コマンド:

    NAMESPACE= 
    1
    
    REGION= 
    2
    
    HOSTNAME=$(oc -n $NAMESPACE get svc accelerator-loadbalancer --template="{{range .status.loadBalancer.ingress}}{{.hostname}}{{end}}")
    aws elbv2 describe-load-balancers \
      --query "LoadBalancers[?DNSName=='${HOSTNAME}'].LoadBalancerArn" \
      --region ${REGION} \
      --output text
    Copy to Clipboard Toggle word wrap

    1
    Keycloak デプロイメントを格納する Kubernetes namespace
    2
    Kubernetes クラスターをホストしている AWS リージョン

    出力:

    arn:aws:elasticloadbalancing:eu-west-1:606671647913:loadbalancer/net/a49e56e51e16843b9a3bc686327c907b/9b786f80ed4eba3d
    Copy to Clipboard Toggle word wrap

  2. 両方のサイトを含むように Accelerator EndpointGroup を更新します。

    1. Global Accelerator の EndpointGroup 内の現在のエンドポイントをリスト表示します。

      コマンド:

      ACCELERATOR_NAME= 
      1
      
      ACCELERATOR_ARN=$(aws globalaccelerator list-accelerators \
        --query "Accelerators[?Name=='${ACCELERATOR_NAME}'].AcceleratorArn" \
        --region us-west-2 \ 
      2
      
        --output text
      )
      LISTENER_ARN=$(aws globalaccelerator list-listeners \
        --accelerator-arn ${ACCELERATOR_ARN} \
        --query "Listeners[*].ListenerArn" \
        --region us-west-2 \
        --output text
      )
      aws globalaccelerator list-endpoint-groups \
        --listener-arn ${LISTENER_ARN} \
        --region us-west-2
      Copy to Clipboard Toggle word wrap

      1
      更新するアクセラレーターの名前
      2
      AWS Global Accelerators を紹介する場合、必ずリージョンを us-west-2 に設定する必要があります。

      出力:

      {
          "EndpointGroups": [
              {
                  "EndpointGroupArn": "arn:aws:globalaccelerator::606671647913:accelerator/d280fc09-3057-4ab6-9330-6cbf1f450748/listener/8769072f/endpoint-group/a30b64ec1700",
                  "EndpointGroupRegion": "eu-west-1",
                  "EndpointDescriptions": [
                      {
                          "EndpointId": "arn:aws:elasticloadbalancing:eu-west-1:606671647913:loadbalancer/net/a3c75f239541c4a6e9c48cf8d48d602f/5ba333e87019ccf0",
                          "Weight": 128,
                          "HealthState": "HEALTHY",
                          "ClientIPPreservationEnabled": false
                      }
                  ],
                  "TrafficDialPercentage": 100.0,
                  "HealthCheckPort": 443,
                  "HealthCheckProtocol": "TCP",
                  "HealthCheckIntervalSeconds": 30,
                  "ThresholdCount": 3
              }
          ]
      }
      Copy to Clipboard Toggle word wrap

    2. 既存のエンドポイントと手順 1 で取得した NLB を含むように EndpointGroup を更新します。

      コマンド:

      aws globalaccelerator update-endpoint-group \
        --endpoint-group-arn arn:aws:globalaccelerator::606671647913:accelerator/d280fc09-3057-4ab6-9330-6cbf1f450748/listener/8769072f/endpoint-group/a30b64ec1700 \
        --region us-west-2 \
        --endpoint-configurations '
        [
          {
              "EndpointId": "arn:aws:elasticloadbalancing:eu-west-1:606671647913:loadbalancer/net/a3c75f239541c4a6e9c48cf8d48d602f/5ba333e87019ccf0",
              "Weight": 128,
              "ClientIPPreservationEnabled": false
          },
          {
              "EndpointId": "arn:aws:elasticloadbalancing:eu-west-1:606671647913:loadbalancer/net/a49e56e51e16843b9a3bc686327c907b/9b786f80ed4eba3d",
              "Weight": 128,
              "ClientIPPreservationEnabled": false
          }
        ]
      '
      Copy to Clipboard Toggle word wrap

第15章 サイトの同期

15.1. この手順を使用する状況

2 つのサイトの Data Grid クラスターが切断状態で、キャッシュ内容が同期されていない場合に使用してください。たとえばスプリットブレインが発生した後や、メンテナンスのために 1 つのサイトをオフラインにした場合に実行します。

手順の最後に、セカンダリーサイトのデータは破棄され、アクティブサイトのデータに置き換えられます。無効なキャッシュコンテンツを回避するために、オフラインサイトのすべてのキャッシュがクリアされます。

15.2. 手順

15.2.1. Data Grid クラスター

この章のコンテキストでは、site-a が現在アクティブなサイトです。site-b は AWS Global Accelerator EndpointGroup の一部ではないため、ユーザーリクエストを受信しないオフラインサイトです。

警告

状態転送を実行すると、応答時間やリソースの使用量が増加し、Data Grid クラスターのパフォーマンスに影響が及ぶ可能性があります。

最初の手順として、オフラインサイトから古いデータを削除します。

  1. オフラインサイトにログインします。
  2. Red Hat build of Keycloak をシャットダウンします。これにより、Red Hat build of Keycloak のキャッシュがすべてクリアされ、Red Hat build of Keycloak の状態と Data Grid との同期ずれが防止されます。

    Red Hat build of Keycloak Operator を使用して Red Hat build of Keycloak をデプロイした場合、Red Hat build of Keycloak カスタムリソース内の Red Hat build of Keycloak インスタンスの数を 0 に変更します。

  3. Data Grid CLI ツールを使用して Data Grid クラスターに接続します。

    コマンド:

    oc -n keycloak exec -it pods/infinispan-0 -- ./bin/cli.sh --trustall --connect https://127.0.0.1:11222
    Copy to Clipboard Toggle word wrap

    Data Grid クラスターのユーザー名とパスワードが要求されます。これらの認証情報は、Data Grid Operator を使用した HA 用の Data Grid のデプロイ の章にある認証情報の設定セクションで設定したものです。

    出力:

    Username: developer
    Password:
    [infinispan-0-29897@ISPN//containers/default]>
    Copy to Clipboard Toggle word wrap

    注記

    Pod 名は、Data Grid CR で定義したクラスター名によって異なります。接続は、Data Grid クラスター内の任意の Pod で行うことができます。

  4. 次のコマンドを実行して、オフラインサイトからアクティブサイトへのレプリケーションを無効にします。これにより、クリアリクエストがアクティブサイトに到達してキャッシュされた正しいデータがすべて削除されるのを防ぎます。

    コマンド:

    site take-offline --all-caches --site=site-a
    Copy to Clipboard Toggle word wrap

    出力:

    {
      "authenticationSessions" : "ok",
      "work" : "ok",
      "loginFailures" : "ok",
      "actionTokens" : "ok"
    }
    Copy to Clipboard Toggle word wrap

  5. レプリケーションのステータスが offline であることを確認します。

    コマンド:

    site status --all-caches --site=site-a
    Copy to Clipboard Toggle word wrap

    出力:

    {
      "status" : "offline"
    }
    Copy to Clipboard Toggle word wrap

    ステータスが offline でない場合は、前のステップを繰り返します。

    警告

    レプリケーションが offline あることを確認してください。そうでない場合、クリアデータによって両方のサイトがクリアされます。

  6. 次のコマンドを使用して、オフラインサイトのキャッシュデータをすべてクリアします。

    コマンド:

    clearcache actionTokens
    clearcache authenticationSessions
    clearcache loginFailures
    clearcache work
    Copy to Clipboard Toggle word wrap

    これらのコマンドは何も出力しません。

  7. オフラインサイトからアクティブサイトへのクロスサイトレプリケーションを再度有効にします。

    コマンド:

    site bring-online --all-caches --site=site-a
    Copy to Clipboard Toggle word wrap

    出力:

    {
      "authenticationSessions" : "ok",
      "work" : "ok",
      "loginFailures" : "ok",
      "actionTokens" : "ok"
    }
    Copy to Clipboard Toggle word wrap

  8. レプリケーションのステータスが online であることを確認します。

    コマンド:

    site status --all-caches --site=site-a
    Copy to Clipboard Toggle word wrap

    出力:

    {
      "status" : "online"
    }
    Copy to Clipboard Toggle word wrap

これで、アクティブサイトからオフラインサイトに状態を転送する準備が整いました。

  1. アクティブサイトにログインします。
  2. Data Grid CLI ツールを使用して Data Grid クラスターに接続します。

    コマンド:

    oc -n keycloak exec -it pods/infinispan-0 -- ./bin/cli.sh --trustall --connect https://127.0.0.1:11222
    Copy to Clipboard Toggle word wrap

    Data Grid クラスターのユーザー名とパスワードが要求されます。これらの認証情報は、Data Grid Operator を使用した HA 用の Data Grid のデプロイ の章にある認証情報の設定セクションで設定したものです。

    出力:

    Username: developer
    Password:
    [infinispan-0-29897@ISPN//containers/default]>
    Copy to Clipboard Toggle word wrap

    注記

    Pod 名は、Data Grid CR で定義したクラスター名によって異なります。接続は、Data Grid クラスター内の任意の Pod で行うことができます。

  3. アクティブサイトからオフラインサイトへの状態転送をトリガーします。

    コマンド:

    site push-site-state --all-caches --site=site-b
    Copy to Clipboard Toggle word wrap

    出力:

    {
      "authenticationSessions" : "ok",
      "work" : "ok",
      "loginFailures" : "ok",
      "actionTokens" : "ok"
    }
    Copy to Clipboard Toggle word wrap

  4. すべてのキャッシュのレプリケーションステータスが online であることを確認します。

    コマンド:

    site status --all-caches --site=site-b
    Copy to Clipboard Toggle word wrap

    出力:

    {
      "status" : "online"
    }
    Copy to Clipboard Toggle word wrap

  5. すべてのキャッシュに対する push-site-status コマンドの出力を確認して、状態転送が完了するまで待ちます。

    コマンド:

    site push-site-status --cache=actionTokens
    site push-site-status --cache=authenticationSessions
    site push-site-status --cache=loginFailures
    site push-site-status --cache=work
    Copy to Clipboard Toggle word wrap

    出力:

    {
      "site-b" : "OK"
    }
    {
      "site-b" : "OK"
    }
    {
      "site-b" : "OK"
    }
    {
      "site-b" : "OK"
    }
    Copy to Clipboard Toggle word wrap

    考えられるステータス値は、クロスサイトドキュメントのこのセクション にある表を参照してください。

    エラーが報告された場合は、その特定のキャッシュに対して状態転送を再度実行します。

    コマンド:

    site push-site-state --cache=<cache-name> --site=site-b
    Copy to Clipboard Toggle word wrap

  6. 以下のコマンドで状態転送ステータスをクリア/リセットします。

    コマンド:

    site clear-push-site-status --cache=actionTokens
    site clear-push-site-status --cache=authenticationSessions
    site clear-push-site-status --cache=loginFailures
    site clear-push-site-status --cache=work
    Copy to Clipboard Toggle word wrap

    出力:

    "ok"
    "ok"
    "ok"
    "ok"
    Copy to Clipboard Toggle word wrap

これで、オフラインサイトで状態が使用できるようになりました。Red Hat build of Keycloak を再度起動できます。

  1. セカンダリーサイトにログインします。
  2. Red Hat build of Keycloak を起動します。

    Red Hat build of Keycloak Operator を使用して Red Hat build of Keycloak をデプロイした場合、Red Hat build of Keycloak カスタムリソース内の Red Hat build of Keycloak インスタンスの数を元の値に変更します。

15.2.2. AWS Aurora データベース

アクションは不要です。

15.2.3. AWS Global Accelerator

2 つのサイトが同期されると、サイトをオンラインにする の章で説明されている手順を実行して、オフラインだったサイトを Global Accelerator EndpointGroup に安全に追加できます。

15.3. 関連資料

Data Grid CLI コマンドを自動化するための概念 を参照してください。

第16章 マルチサイトデプロイメントのヘルスチェック

Kubernetes 環境で マルチサイトデプロイメント を実行する場合は、すべてが期待どおりに稼働しているか確認するチェックを自動化する必要があります。

このページでは、Red Hat build of Keycloak のマルチサイト設定を検証するために使用できる URL、Kubernetes リソース、Healthcheck エンドポイントを概説します。

16.1. 概要

プロアクティブなモニタリングストラテジーは、問題がユーザーに影響を与える前に検出して警告することを目的としています。このストラテジーは、Red Hat build of Keycloak の回復力と可用性を高める鍵となります。

さまざまなアーキテクチャーコンポーネント (アプリケーションの健全性、負荷分散、キャッシュ、全体的なシステムの状態など) を対象とするヘルスチェックは、次の点で重要です。

高可用性の確保
すべてのサイトとロードバランサーが動作していることを確認することは、1 つのサイトがダウンした場合でもシステムがリクエストを処理できることを保証するための鍵となります。
パフォーマンスの維持
Red Hat build of Keycloak は、Data Grid キャッシュの健全性と分散をチェックすることで、セッションやその他の一時データを効率的に処理し、最適なパフォーマンスを維持できます。
オペレーションの回復力
Red Hat build of Keycloak と、Kubernetes 環境内の依存関係の両方の健全性を継続的に監視することで、システムは問題を迅速に特定し、場合によっては自動的に修復して、ダウンタイムを短縮できます。

16.2. 前提条件

  1. Kubectl CLI のインストールと設定 が完了している。
  2. オペレーティングシステムにインストールされていない場合、jq をインストールする。

16.3. 特定のヘルスチェック

16.3.1. Red Hat build of Keycloak のロードバランサーとサイト

ロードバランサーと、プライマリーサイトおよびバックアップサイトの両方を通じて、Red Hat build of Keycloak の健全性を確認します。これにより、Red Hat build of Keycloak にアクセスでき、さまざまな地理的またはネットワーク上の場所をまたいで負荷分散メカニズムが正しく機能することが確保されます。

このコマンドは、Red Hat build of Keycloak アプリケーションの設定済みデータベースへの接続のヘルスステータスを返すため、データベース接続の信頼性を確認できます。このコマンドは管理ポートでのみ使用でき、外部 URL からは使用できません。Kubernetes セットアップでは、Pod の準備を完了するために health/ready サブステータスが定期的にチェックされます。

curl -s https://keycloak:managementport/health
Copy to Clipboard Toggle word wrap

このコマンドは、ロードバランサーの lb-check エンドポイントを検証し、Red Hat build of Keycloak アプリケーションクラスターが稼働していることを確認します。

curl -s https://keycloak-load-balancer-url/lb-check
Copy to Clipboard Toggle word wrap

これらのコマンドは、マルチサイトセットアップにおける Red Hat build of Keycloak の Site A および Site B の実行ステータスを返します。

curl -s https://keycloak_site_a_url/lb-check
curl -s https://keycloak_site_b_url/lb-check
Copy to Clipboard Toggle word wrap

16.3.2. Data Grid キャッシュの健全性

外部 Data Grid クラスター内のデフォルトのキャッシュマネージャーと個々のキャッシュの健全性を確認します。Data Grid は、Red Hat build of Keycloak のデプロイメントで分散キャッシュやセッションクラスタリングに使用されることが多いため、このチェックは Red Hat build of Keycloak のパフォーマンスと信頼性において重要です。

このコマンドは、Data Grid キャッシュマネージャーの総合的な健全性を返します。つまり、管理者ユーザーが健全性ステータスを取得するためにユーザー認証情報を提供する必要がないため便利です。

curl -s https://infinispan_rest_url/rest/v2/cache-managers/default/health/status
Copy to Clipboard Toggle word wrap

上記のヘルスチェックとは異なり、以下のヘルスチェックでは、外部 Data Grid クラスターキャッシュの全体的な健全性を確認するためのリクエストの一部として、管理者ユーザーは Data Grid ユーザーの認証情報を提供する必要があります。

curl -u <infinispan_user>:<infinispan_pwd> -s https://infinispan_rest_url/rest/v2/cache-managers/default/health \
 | jq 'if .cluster_health.health_status == "HEALTHY" and (all(.cache_health[].status; . == "HEALTHY")) then "HEALTHY" else "UNHEALTHY" end'
Copy to Clipboard Toggle word wrap

jq フィルターは、個々のキャッシュの健全性に基づいて全体的な健全性を計算するのに便利です。jq フィルターなしで上記のコマンドを実行すると、すべての詳細を確認できます。

16.3.3. Data Grid クラスターの分散

Data Grid クラスターの分散の健全性を評価し、クラスターのノードがデータを正しく分散していることを確認します。このステップは、キャッシュレイヤーのスケーラビリティーとフォールトトレランスにとって不可欠です。

expectedCount 3 引数を、クラスター内の合計ノード数と一致するように変更し、その健全性を検証できます。

curl <infinispan_user>:<infinispan_pwd> -s https://infinispan_rest_url/rest/v2/cluster\?action\=distribution \
 | jq --argjson expectedCount 3 'if map(select(.node_addresses | length > 0)) | length == $expectedCount then "HEALTHY" else "UNHEALTHY" end'
Copy to Clipboard Toggle word wrap

16.3.4. 全体的な Data Grid システムの健全性

oc CLI ツールを使用して、指定された namespace 内の Data Grid クラスターと Red Hat build of Keycloak サービスのヘルスステータスを照会します。この包括的なチェックにより、Red Hat build of Keycloak デプロイメントのすべてのコンポーネントが Kubernetes 環境内で動作し、正しく設定されていることを確認できます。

oc get infinispan -n <NAMESPACE> -o json  \
| jq '.items[].status.conditions' \
| jq 'map({(.type): .status})' \
| jq 'reduce .[] as $item ([]; . + [keys[] | select($item[.] != "True")]) | if length == 0 then "HEALTHY" else "UNHEALTHY: " + (join(", ")) end'
Copy to Clipboard Toggle word wrap

16.3.5. Kubernetes における Red Hat build of Keycloak の準備状態

具体的には、Kubernetes での Red Hat build of Keycloak デプロイメントの準備状態とローリング更新条件をチェックし、Red Hat build of Keycloak インスタンスが完全に動作しており、可用性に影響を与える可能性のある更新が行われていないことを確認します。

oc wait --for=condition=Ready --timeout=10s keycloaks.k8s.keycloak.org/keycloak -n <NAMESPACE>
oc wait --for=condition=RollingUpdate=False --timeout=10s keycloaks.k8s.keycloak.org/keycloak -n <NAMESPACE>
Copy to Clipboard Toggle word wrap

法律上の通知

Copyright © 2025 Red Hat, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.See the License for the specific language governing permissions and limitations under the License.
トップに戻る
Red Hat logoGithubredditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。 最新の更新を見る.

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

Theme

© 2026 Red Hat