Keycloak 集群設定

2019 年 5 月 10 日 作者:张立强 liqiang@fit2cloud.com

這篇文章分享在各種情境下 (例如跨資料中心、Docker 跨主機、Kubernetes) 設定 Keycloak 集群的一些解決方案。

如果您想設定 Keycloak 集群,這篇部落格可能會給您一些參考。

根據 指南,兩個 CLI 腳本檔案已新增至 Keycloak 映像檔

Dockerfile 如下,這兩個檔案是這篇部落格最重要的內容,您可以在 TCPPING.cliJDBC_PING.cli 中找到它們。

FROM jboss/keycloak:latest

ADD cli/TCPPING.cli /opt/jboss/tools/cli/jgroups/discovery/
ADD cli/JDBC_PING.cli /opt/jboss/tools/cli/jgroups/discovery/

首先,我們應該知道,對於 Keycloak 集群,所有 Keycloak 實例都應該使用相同的資料庫,這非常簡單。另一件事是關於快取(一般來說,Keycloak 中有兩種快取,第一種是從資料庫讀取的持久資料快取,旨在提高效能,例如 realm/client/user;第二種是非持久資料快取,例如 sessions/clientSessions,第二種對於集群非常重要),配置起來有點複雜,我們必須確保集群視圖中快取的一致性。

這裡總共有 3 種集群解決方案,所有解決方案都基於 JGroups 的發現協定(Keycloak 使用 Infinispan 快取,而 Infinispan 使用 JGroups 來發現節點)。

1. PING

PING 是 Keycloak 預設啟用的集群解決方案,使用 UDP 協定,您不需要為此進行任何設定。

但是,PING 僅在啟用多播網路且應公開 55200 埠時才可用,例如裸機、虛擬機器、同一主機中的 Docker 容器。

我們在同一主機中的兩個 Keycloak 容器中測試了這個方法。

日誌顯示兩個 Keycloak 實例互相發現並形成集群。

2. TCPPING

TCPPING 使用 TCP 協定和 7600 埠。當多播不可用時可以使用,例如跨資料中心部署、跨主機容器。

我們在跨主機的兩個 Keycloak 容器中測試了這個方法。

在這個解決方案中,我們需要為容器設定以下三個環境變數。

#IP address of this host, please make sure this IP can be accessed by the other Keycloak instances
JGROUPS_DISCOVERY_EXTERNAL_IP=172.21.48.39
#protocol
JGROUPS_DISCOVERY_PROTOCOL=TCPPING
#IP and Port of all host
JGROUPS_DISCOVERY_PROPERTIES=initial_hosts="172.21.48.4[7600],172.21.48.39[7600]"

日誌顯示兩個 Keycloak 實例互相發現並形成集群。

3. JDBC_PING

JDBC_PING 使用 TCP 協定和 7600 埠,這與 TCPPING 類似,但它們之間的區別在於,TCPPING 要求您設定所有實例的 IP 和埠,而對於 JDBC_PING,您只需要設定目前實例的 IP 和埠,這是因為在 JDBC_PING 解決方案中,每個實例都會將自己的資訊插入資料庫,並且實例會透過從資料庫讀取的 ping 資料來發現對等點。

我們在跨主機的兩個 Keycloak 容器中測試了這個方法。

在這個解決方案中,我們需要為容器設定以下兩個環境變數。

#IP address of this host, please make sure this IP can be accessed by the other Keycloak instances
JGROUPS_DISCOVERY_EXTERNAL_IP=172.21.48.39
#protocol
JGROUPS_DISCOVERY_PROTOCOL=JDBC_PING

所有實例的 ping 資料在實例啟動後已儲存在資料庫中。

日誌顯示兩個 Keycloak 實例互相發現並形成集群。

還有一件事

上述解決方案適用於大多數情境,但對於其他一些情境仍然不夠,例如 Kubernetes。

Kubernetes 上典型的部署是一個 Deployment/ReplicateSet/StatefulSet 包含多個 Keycloak Pod,這些 Pod 非常動態,因為它們可以擴展或縮減,或故障轉移到另一個節點,這需要集群發現和移除這些動態成員。

在 Kubernetes 上,我們可以使用 DNS_PINGKUBE_PING,它們在實踐中效果很好。

除了 DNS_PING 和 KUBE_PING,JDBC_PING 是 Kubernetes 的另一個選擇。

在 Kubernetes 上,多播僅適用於同一節點中的容器,並且 Pod 沒有可用於配置 TCPPING 或 JDBC_PING 的靜態 IP。但是,在上面提到的 JDBC_PING.cli 中,我們已經處理了這個問題,如果您沒有設定 JGROUPS_DISCOVERY_EXTERNAL_IP 環境變數,將會使用 Pod IP,這意味著在 Kubernetes 上,您可以簡單地設定 JGROUPS_DISCOVERY_PROTOCOL=JDBC_PING,您的 Keycloak 集群就完成了。

討論

建議和意見可以透過 Keycloak 使用者郵件列表這個 GitHub 儲存庫 進行討論。