KeycloakをKubernetes上で動かすとき、詰まるのは大抵Operatorの使い方ではなく、ノード間クラスタリングとキャッシュの挙動です。Operator/CRD、jgroupsによるノード発見、証明書とIngress、スケール時のセッションまで、現行のQuarkus版を基準に実務のポイントを整理します。

KeycloakをKubernetes上で動かす案件は増えていますが、実際に運用フェーズで詰まるのは「Operatorの入れ方」ではありません。ノード間のクラスタリング、キャッシュStackの選び方、そしてスケールやローリング更新時のセッションの挙動です。本記事では現行のQuarkusベースのディストリビューション(WildFly版は非推奨、バージョン依存は公式で要確認)を前提に、Operator/CRDの扱いから、jgroupsによるノード発見、証明書・Ingress、EKSの勘所までを実務目線で整理します。

01Operatorが実際に生成するもの

Keycloak Operatorは、CRD(KeycloakKeycloakRealmImport)をクラスタに登録し、Keycloak カスタムリソース(CR)を1つ書けば必要なワークロード一式を面倒みてくれる仕組みです。インストールはCRDを2本 kubectl apply し、Operator本体をデプロイするか、本番なら Operator Lifecycle Manager(OLM)経由が推奨されています。詳細は公式のOperator Installationガイドを参照してください。

ここで運用上おさえておきたいのは、現行のOperatorが Keycloak カスタムリソースから生成するワークロードは DeploymentではなくStatefulSet だという点です。状態自体はDBと(必要に応じて)分散キャッシュに載るためPodは比較的ステートレスに扱えますが、安定したネットワークIDや順序付きの起動といったクラスタリング要件を満たすために、Operatorは意図的にStatefulSetを採用しています。Podテンプレートを直接いじりたい場合は、CRの unsupported.podTemplate にPodテンプレートの生表現を書き込めます。ラベル・アノテーション・追加ボリューム・マウントを差し込む逃げ道として実務では重宝しますが、名前の通り「unsupported」なので乱用は避けます。

現場のコツ:CRで表現できない専門的な設定は additionalOptions にkey-valueで渡せます。プレーン値だけでなくSecret参照も書けるので、DBパスワードやプロバイダ固有オプションはここでSecret化して流し込むのが定石です。

02キャッシュStackの選択 — jdbc-pingが現行の既定

Keycloakの分散キャッシュはInfinispanで、ノード発見はjgroupsのdiscoveryプロトコルが担います。ここが近年もっとも変わった部分です。かつてKubernetesでは KC_CACHE_STACK=kubernetes(DNS_PING)を使うのが定番でしたが、公式のキャッシュ設定ガイドによれば、分散キャッシュ有効時の 既定Stackは jdbc-ping になり、従来の kubernetes / tcp / udp は非推奨(deprecated)扱いです(バージョン依存のため公式で要確認)。

クラスタ内通信は 7800 番(ユニキャストのデータ転送、cache-embedded-network-bind-port で調整)、障害検知用に 57800 番(既定でオフセット)を使います。NetworkPolicyでPod間を絞っている環境では、この2ポートをノード間で開けておかないとクラスタが組めません。ここはハマりどころなので着任時に必ず確認します。

jdbc-ping によるノード発見(現行の既定) Keycloak Pod A Infinispan Keycloak Pod B Infinispan Keycloak Pod C Infinispan PostgreSQL JGROUPSPING テーブルに自己登録 各ノードがDBを見て相互発見 → 7800/57800でクラスタ形成
図:jdbc-pingは共有DBを介してノードを発見するため、ヘッドレスサービスやマルチキャストに依存しない。

03セッションは「DBが正、キャッシュはL1」という前提

スケールやローリング更新の設計で最初に共有すべき事実は、近年のKeycloakでは 通常のユーザーセッションはDBに永続化され、キャッシュには必要に応じてオンデマンドで載る(persistent user sessions)という点です。つまりキャッシュは真実の源(source of truth)ではなくL1的な位置づけになりました。これによりPodが1つ落ちてもセッションはDBに残り、再スケジュール後もログイン状態が維持されます。

現場のコツ:DBコネクションプールは db.poolMinSize / poolInitialSize / poolMaxSize を同値(例:30)に揃えると、Postgres側のprepared statementキャッシュが効きやすくなります。HAガイドでも同値化が推奨されています。

04Ingressと証明書 — 「どこでTLSを終端するか」を先に決める

KeycloakはOIDC/SAMLのメタデータやリダイレクトURLに自分のホスト名を埋め込むため、外部から見えるURLと内部の通信経路がズレると事故になります。設計の起点は「TLSをどこで終端するか」です。

ビルド時オプションと実行時オプションの区別(proxyやhostname系がどちら扱いか)はバージョンで動くので、ビルド時/実行時設定の分離もあわせて確認してください。

EKSでのIngress終端構成(例) クライアント ALB Ingress TLS終端 / ACM証明書 Keycloak Pod A HTTP + proxy-headers Keycloak Pod B HTTP + proxy-headers RDS Postgres HTTPS
図:ALBでTLS終端する場合、Keycloak側はproxy-headers設定で外部ホスト名とスキームを正しく認識させる。

05スケールとローリング更新の実務

Operatorはデフォルトで scheduling スタンザ(affinity、tolerations、topology spread constraints、priority class)を公開しており、既定でもゾーン・ノードをまたいでPodを分散配置します。HAガイドでは3レプリカを複数AZに分けるのが基本形です。

現場のコツ:リソース既定は要求1250M/上限2250M、CPU要求2/上限6あたりがHAガイドの目安ですが、これはサイジングの出発点にすぎません。realmの数、ユーザー数、トークンの有効期限で実測が必要です。過小なメモリ上限はGC起因のレイテンシとして跳ね返ります。

06EKSでの勘所

EKS特有で着任時に確認するポイントを絞ると次の通りです。

マルチアカウント構成でEKSを運用している場合、認証基盤の配置とアカウント境界の設計はマルチアカウント統制の観点でも整理しておくと後の統制が楽になります。より広いHA設計はAWS上でのKeycloak HA構成にまとめています。

07まとめ — 詰まるのはOperatorではなくクラスタリング

KubernetesでのKeycloak運用は、Operator/CRDのおかげで宣言的なデプロイ自体は素直です。実務で効くのは、(1) キャッシュStackは現行なら jdbc-ping を既定に据える、(2) セッションはDBが正でキャッシュはL1という前提でスケール・更新を設計する、(3) ホスト名とTLS終端位置を最初に固定してproxy-headersを合わせる、(4) 7800/57800とDB接続をネットワーク・SGレベルで通す、という4点です。ここを押さえれば、スケールやローリング更新で「なぜかログアウトされる」「ノードがクラスタに入らない」といった典型的な事故はほぼ回避できます。EMWでも同様の構成でエンタープライズの認証基盤を実構築しており、導入事例もあわせてご覧いただけます。

参考(一次情報)

Kubernetes上でのKeycloak認証基盤の設計・構築でお困りの際は、お問い合わせください。

相談する
← ブログ一覧へ戻る