此设置在两个站点中部署两个同步复制的 Infinispan 集群,并具有低延迟网络连接。此场景的一个示例可以是 AWS 区域中的两个可用区。
为简单起见,以下图表中已删除 Keycloak、负载均衡器和数据库。
配置访问 Infinispan 集群的凭据。
Keycloak 需要此凭据才能与 Infinispan 集群进行身份验证。以下 identities.yaml
文件设置了具有管理员权限的用户名和密码
credentials:
- username: developer
password: strong-password
roles:
- admin
identities.yaml
可以设置为 Secret,作为以下选项之一
作为 Kubernetes 资源
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: connect-secret
namespace: keycloak
data:
identities.yaml: Y3JlZGVudGlhbHM6CiAgLSB1c2VybmFtZTogZGV2ZWxvcGVyCiAgICBwYXNzd29yZDogc3Ryb25nLXBhc3N3b3JkCiAgICByb2xlczoKICAgICAgLSBhZG1pbgo= (1)
1 | 来自先前示例的 identities.yaml 经过 base64 编码。 |
使用 CLI
kubectl create secret generic connect-secret --from-file=identities.yaml
有关更多详细信息,请查看 配置身份验证 文档。
这些命令必须在两个 OpenShift 集群上执行。
创建服务帐户。
需要服务帐户才能建立集群之间的连接。Infinispan Operator 使用它来检查远程站点的网络配置,并相应地配置本地 Infinispan 集群。
有关更多详细信息,请参阅 管理跨站点连接 文档。
按如下所示创建 service-account-token
secret 类型。相同的 YAML 文件可以在两个 OpenShift 集群中使用。
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
1 | Secret 名称。 |
2 | 服务帐户名称。 |
在两个 OpenShift 集群中创建服务帐户并生成访问令牌。
Site-A
中创建服务帐户kubectl create sa -n keycloak xsite-sa
oc policy add-role-to-user view -n keycloak -z xsite-sa
kubectl create -f xsite-sa-secret-token.yaml
kubectl get secrets ispn-xsite-sa-token -o jsonpath="{.data.token}" | base64 -d > Site-A-token.txt
Site-B
中创建服务帐户kubectl create sa -n keycloak xsite-sa
oc policy add-role-to-user view -n keycloak -z xsite-sa
kubectl create -f xsite-sa-secret-token.yaml
kubectl get secrets ispn-xsite-sa-token -o jsonpath="{.data.token}" | base64 -d > Site-B-token.txt
下一步是将来自 Site-A
的令牌部署到 Site-B
,反之亦然
Site-B
令牌部署到 Site-A
kubectl create secret generic -n keycloak xsite-token-secret \
--from-literal=token="$(cat Site-B-token.txt)"
Site-A
令牌部署到 Site-B
kubectl create secret generic -n keycloak xsite-token-secret \
--from-literal=token="$(cat Site-A-token.txt)"
创建 TLS secret
在本指南中,Infinispan 使用 OpenShift Route 进行跨站点通信。它使用 TLS 的 SNI 扩展将流量定向到正确的 Pod。为了实现这一点,JGroups 使用 TLS 套接字,这需要具有正确证书的密钥库和信任库。
有关更多信息,请参阅 保护跨站点连接 文档或此 Red Hat 开发者指南。
将密钥库和信任库上传到 OpenShift Secret 中。secret 包含文件内容、访问密码和存储类型。创建证书和存储的说明超出了本指南的范围。
要将密钥库作为 Secret 上传,请使用以下命令
kubectl -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)
1 | 密钥库的文件名和路径。 |
2 | 访问密钥库的密码。 |
3 | 密钥库类型。 |
要将信任库作为 Secret 上传,请使用以下命令
kubectl -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)
1 | 信任库的文件名和路径。 |
2 | 访问信任库的密码。 |
3 | 信任库类型。 |
密钥库和信任库必须在两个 OpenShift 集群中上传。 |
创建启用跨站点的 Infinispan 集群
设置跨站点 文档提供了有关如何创建和配置启用跨站点的 Infinispan 集群的所有信息,包括之前的步骤。
本指南提供了一个基本示例,使用先前步骤中的命令创建的凭据、令牌和 TLS 密钥库/信任库。
Site-A
的 Infinispan
CRapiVersion: 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 (6)
alias: xsite (7)
filename: keystore.p12 (8)
trustStore:
secretName: xsite-truststore-secret (9)
filename: truststore.p12 (10)
locations:
- name: site-b (11)
clusterName: infinispan
namespace: keycloak (12)
url: openshift://api.site-b (13)
secretName: xsite-token-secret (14)
1 | 集群名称 |
2 | 允许 Prometheus 监视集群。 |
3 | 如果使用自定义凭据,请在此处配置 secret 名称。 |
4 | 本地站点的名称,在本例中为 Site-A 。 |
5 | 使用 OpenShift Route 公开跨站点连接。 |
6 | 密钥库存在的 secret 名称,如上一步中所定义。 |
7 | 密钥库内证书的别名。 |
8 | 密钥库的 secret 密钥(文件名),如上一步中所定义。 |
9 | 信任库存在的 secret 名称,如上一步中所定义。 |
10 | 密钥库的信任库密钥(文件名),如上一步中所定义。 |
11 | 远程站点的名称,在本例中为 Site-B 。 |
12 | 来自远程站点的 Infinispan 集群的命名空间。 |
13 | 远程站点的 OpenShift API URL。 |
14 | 具有访问令牌的 secret,用于身份验证到远程站点。 |
对于 Site-B
,Infinispan
CR 看起来与上述类似。请注意第 4、11 和 13 点的差异。
Site-B
的 Infinispan
CRapiVersion: 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 (6)
alias: xsite (7)
filename: keystore.p12 (8)
trustStore:
secretName: xsite-truststore-secret (9)
filename: truststore.p12 (10)
locations:
- name: site-a (11)
clusterName: infinispan
namespace: keycloak (12)
url: openshift://api.site-a (13)
secretName: xsite-token-secret (14)
为 Keycloak 创建缓存。
Keycloak 需要以下缓存存在:actionTokens
、authenticationSessions
、loginFailures
和 work
。
Infinispan Cache CR 允许在 Infinispan 集群中部署缓存。跨站点需要按 跨站点文档 中的文档对每个缓存启用。该文档包含有关本指南使用的选项的更多详细信息。以下示例显示了 Site-A
的 Cache
CR。
在 Site-A
中,为上述每个缓存创建一个 Cache
CR,内容如下。
actionTokens
apiVersion: infinispan.org/v2alpha1
kind: Cache
metadata:
name: actiontokens
namespace: keycloak
spec:
clusterName: infinispan
name: actionTokens
template: |-
distributedCache:
mode: "SYNC"
owners: "2"
statistics: "true"
remoteTimeout: "5000"
encoding:
media-type: "application/x-protostream"
locking:
acquireTimeout: "4000"
transaction:
mode: "NON_DURABLE_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"
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_DURABLE_XA" (1)
locking: "PESSIMISTIC" (2)
stateTransfer:
chunkSize: "16"
indexing:
enabled: true
indexed-entities:
- keycloak.RootAuthenticationSessionEntity
backups:
site-b: (3)
backup:
strategy: "SYNC" (4)
timeout: "4500" (5)
failurePolicy: "FAIL" (6)
stateTransfer:
chunkSize: "16"
loginFailures
apiVersion: infinispan.org/v2alpha1
kind: Cache
metadata:
name: loginfailures
namespace: keycloak
spec:
clusterName: infinispan
name: loginFailures
template: |-
distributedCache:
mode: "SYNC"
owners: "2"
statistics: "true"
remoteTimeout: "5000"
encoding:
media-type: "application/x-protostream"
locking:
acquireTimeout: "4000"
transaction:
mode: "NON_DURABLE_XA" (1)
locking: "PESSIMISTIC" (2)
stateTransfer:
chunkSize: "16"
indexing:
enabled: true
indexed-entities:
- keycloak.LoginFailureEntity
backups:
site-b: (3)
backup:
strategy: "SYNC" (4)
timeout: "4500" (5)
failurePolicy: "FAIL" (6)
stateTransfer:
chunkSize: "16"
work
apiVersion: infinispan.org/v2alpha1
kind: Cache
metadata:
name: work
namespace: keycloak
spec:
clusterName: infinispan
name: work
template: |-
distributedCache:
mode: "SYNC"
owners: "2"
statistics: "true"
remoteTimeout: "5000"
encoding:
media-type: "application/x-protostream"
locking:
acquireTimeout: "4000"
transaction:
mode: "NON_DURABLE_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"
1 | 事务模式。 |
2 | 事务使用的锁定模式。 |
3 | 远程站点名称。 |
4 | 跨站点通信策略,在本例中为 SYNC 。 |
5 | 跨站点复制超时。 |
6 | 跨站点复制失败策略。 |
以上示例是实现最佳数据一致性的推荐配置。
背景信息
在 active-active 设置中,当条目在两个站点中同时修改时,可能会发生死锁。
transaction.mode: NON_DURABLE_XA
确保如果发生这种情况,事务将被回滚,从而保持数据一致性。在这种情况下,需要设置 backup.failurePolicy: FAIL
。它将抛出一个错误,允许安全地回滚事务。当这种情况发生时,Keycloak 将尝试重试。
transaction.locking: PESSIMISTIC
是唯一支持的锁定模式;由于其网络成本,不建议使用 OPTIMISTIC
。相同的设置还可以防止在一个站点更新时另一个站点无法访问。
backup.strategy: SYNC
确保数据在 Keycloak 请求完成时在另一个站点中可见和存储。
locking.acquireTimeout 可以减少以在死锁场景中快速失败。backup.timeout 必须始终高于 locking.acquireTimeout 。 |
对于 Site-B
,Cache
CR 类似,除了上图中第 3 点概述的 backups.<name>
。
Site-B
中 actionTokens
缓存的示例apiVersion: infinispan.org/v2alpha1
kind: Cache
metadata:
name: actiontokens
namespace: keycloak
spec:
clusterName: infinispan
name: actionTokens
template: |-
distributedCache:
mode: "SYNC"
owners: "2"
statistics: "true"
remoteTimeout: "5000"
encoding:
media-type: "application/x-protostream"
locking:
acquireTimeout: "4000"
transaction:
mode: "NON_DURABLE_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"
确认 Infinispan 集群已形成,并且 OpenShift 集群之间已建立跨站点连接。
kubectl wait --for condition=WellFormed --timeout=300s infinispans.infinispan.org -n keycloak infinispan
kubectl wait --for condition=CrossSiteViewFormed --timeout=300s infinispans.infinispan.org -n keycloak infinispan
现在 Infinispan 服务器正在运行,以下是将 Infinispan 连接到 Keycloak 所需的相关 Keycloak CR 更改。这些更改将在 使用 Keycloak Operator 部署用于 HA 的 Keycloak 指南中需要。
创建包含用户名和密码的 Secret 以连接到外部 Infinispan 部署
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'
如下所示,使用 additionalOptions
扩展 Keycloak 自定义资源。
以下 CR 中跳过了所有内存、资源和数据库配置,因为它们已经在 使用 Keycloak Operator 部署用于 HA 的 Keycloak 指南中描述过。管理员应保持这些配置不变。 |
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
1 | 远程 Infinispan 集群的主机名。 |
2 | 远程 Infinispan 集群的端口。这是可选的,默认为 11222 。 |
3 | 包含 Infinispan 用户名凭据的 Secret name 和 key 。 |
4 | 包含 Infinispan 密码凭据的 Secret name 和 key 。 |
5 | spi-connections-infinispan-quarkus-site-name 是一个任意的 Infinispan 站点名称,当使用远程存储时,Keycloak 的 Infinispan 缓存部署需要该名称。此站点名称仅与 Infinispan 缓存相关,不需要与外部 Infinispan 部署中的任何值匹配。如果您在跨 DC 设置中为 Keycloak 使用多个站点,例如 使用 Infinispan Operator 部署用于 HA 的 Infinispan,则每个站点中的站点名称必须不同。 |
在 Aurora AWS 数据库和 Infinispan 部署并运行后,使用 使用 Keycloak Operator 部署用于 HA 的 Keycloak 指南中的步骤部署 Keycloak 并将其连接到所有先前创建的构建块。