Keycloak 集群设置

2019 年 5 月 10 日 由 张立强 [email protected]

这篇文章分享了在不同场景下设置 Keycloak 集群的一些解决方案(例如跨数据中心,跨主机 Docker,Kubernetes)。

如果您想设置 Keycloak 集群,这篇博客可以为您提供一些参考。

根据 指南,我们在 Keycloak 镜像 中添加了两个 cli 脚本文件。

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 实例都应该使用相同的数据库,这非常简单。另一件事是关于缓存(通常 Keycloaks 中有两种类型的缓存,第一种是持久性数据缓存,从数据库读取以提高性能,例如 realm/client/user,第二种是非持久性数据缓存,例如 sessions/clientSessions,第二种对于集群来说非常重要),这在配置方面有点复杂,我们必须确保集群视图中缓存的一致性。

总共有三种集群解决方案,所有解决方案都基于 JGroups 的发现协议(Keycloak 使用 Infinispan 缓存,Infinispan 使用 JGroups 来发现节点)。

1. PING

PING 是 Keycloak 使用 UDP 协议的默认启用集群解决方案,您无需为此进行任何配置。

但 PING 仅在启用组播网络且端口 55200 公开的情况下可用,例如裸机,VM,同一主机上的 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 Pods,Pods 非常动态,因为它们可以按比例放大和缩小,或故障转移到另一个节点,这要求集群发现并删除这些动态成员。

在 Kubernetes 上,我们可以使用 DNS_PINGKUBE_PING,它们在 实践 中运行良好。

除了 DNS_PING 和 KUBE_PING,JDBC_PING 也是 Kubernetes 的另一种选择。

在 Kubernetes 上,组播仅适用于同一节点上的容器,并且 Pod 没有静态 IP,可用于配置 TCPPING 或 JDBC_PING。但在上面提到的 JDBC_PING.cli 中,我们已经处理了这个问题,如果您不设置 JGROUPS_DISCOVERY_EXTERNAL_IP 环境变量,将使用 Pod IP,这意味着在 Kubernetes 上,您可以简单地设置 JGROUPS_DISCOVERY_PROTOCOL=JDBC_PING,然后您的 Keycloak 集群就可以了。

讨论

您可以通过 Keycloak 用户邮件列表此 GitHub 存储库 讨论建议和评论。