使用 Infinispan Operator 部署用于 HA 的 Infinispan

Kubernetes 上 Infinispan 部署的构建块

本指南描述了在多集群环境(跨站点)中部署 Infinispan 所需的步骤。为简单起见,本主题使用了允许 Keycloak 与外部 Infinispan 一起使用的最低配置。

本指南假设有两个名为 Site-ASite-B 的 OpenShift 集群。

这是一个构建块,遵循 多站点部署概念 指南中描述的概念。有关概述,请参阅 多站点部署 指南。

外部 Infinispan 部署仅支持 Infinispan 版本 15.0.14.Final 或更高版本的补丁版本。

架构

此设置在两个站点中部署两个同步复制的 Infinispan 集群,并具有低延迟网络连接。此场景的一个示例可以是 AWS 区域中的两个可用区。

为简单起见,以下图表中已删除 Keycloak、负载均衡器和数据库。

infinispan crossdc az.dio

先决条件

步骤

  1. 安装 Infinispan Operator

  2. 配置访问 Infinispan 集群的凭据。

    Keycloak 需要此凭据才能与 Infinispan 集群进行身份验证。以下 identities.yaml 文件设置了具有管理员权限的用户名和密码

    credentials:
      - username: developer
        password: strong-password
        roles:
          - admin

    identities.yaml 可以设置为 Secret,作为以下选项之一

    • 作为 Kubernetes 资源

      凭据 Secret
      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 集群上执行。

  3. 创建服务帐户。

    需要服务帐户才能建立集群之间的连接。Infinispan Operator 使用它来检查远程站点的网络配置,并相应地配置本地 Infinispan 集群。

    有关更多详细信息,请参阅 管理跨站点连接 文档。

    1. 按如下所示创建 service-account-token secret 类型。相同的 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
      1 Secret 名称。
      2 服务帐户名称。
    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
    3. 下一步是将来自 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)"
  4. 创建 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 集群中上传。
  5. 创建启用跨站点的 Infinispan 集群

    设置跨站点 文档提供了有关如何创建和配置启用跨站点的 Infinispan 集群的所有信息,包括之前的步骤。

    本指南提供了一个基本示例,使用先前步骤中的命令创建的凭据、令牌和 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 (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-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 (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)
  6. 为 Keycloak 创建缓存。

    Keycloak 需要以下缓存存在:actionTokensauthenticationSessionsloginFailureswork

    Infinispan Cache CR 允许在 Infinispan 集群中部署缓存。跨站点需要按 跨站点文档 中的文档对每个缓存启用。该文档包含有关本指南使用的选项的更多详细信息。以下示例显示了 Site-ACache CR。

    1. 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-BCache CR 类似,除了上图中第 3 点概述的 backups.<name>

    Site-BactionTokens 缓存的示例
    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 集群之间已建立跨站点连接。

等待直到 Infinispan 集群形成
kubectl wait --for condition=WellFormed --timeout=300s infinispans.infinispan.org -n keycloak infinispan
等待直到 Infinispan 跨站点连接建立
kubectl wait --for condition=CrossSiteViewFormed --timeout=300s infinispans.infinispan.org -n keycloak infinispan

将 Infinispan 连接到 Keycloak

现在 Infinispan 服务器正在运行,以下是将 Infinispan 连接到 Keycloak 所需的相关 Keycloak CR 更改。这些更改将在 使用 Keycloak Operator 部署用于 HA 的 Keycloak 指南中需要。

  1. 创建包含用户名和密码的 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'
  2. 如下所示,使用 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 namekey
    4 包含 Infinispan 密码凭据的 Secret namekey
    5 spi-connections-infinispan-quarkus-site-name 是一个任意的 Infinispan 站点名称,当使用远程存储时,Keycloak 的 Infinispan 缓存部署需要该名称。此站点名称仅与 Infinispan 缓存相关,不需要与外部 Infinispan 部署中的任何值匹配。如果您在跨 DC 设置中为 Keycloak 使用多个站点,例如 使用 Infinispan Operator 部署用于 HA 的 Infinispan,则每个站点中的站点名称必须不同。

架构

这使用 TLS 1.3 保护的 TCP 连接将 Keycloak 连接到 Infinispan。它使用 Keycloak 的信任库来验证 Infinispan 的服务器证书。由于 Keycloak 是使用其 Operator 在下面列出的先决条件中的 OpenShift 上部署的,因此 Operator 已经将 service-ca.crt 添加到用于签名 Infinispan 服务器证书的信任库中。在其他环境中,将必要的证书添加到 Keycloak 的信任库中。

下一步

在 Aurora AWS 数据库和 Infinispan 部署并运行后,使用 使用 Keycloak Operator 部署用于 HA 的 Keycloak 指南中的步骤部署 Keycloak 并将其连接到所有先前创建的构建块。

相关选项

cache-remote-host

外部 Infinispan 集群的主机名。

仅当设置了 multi-siteclusterlesscache-embedded-remote-store 功能时可用。

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

cache-remote-password

用于身份验证到外部 Infinispan 集群的密码。

如果连接到不安全的外部 Infinispan 集群,则它是可选的。如果指定了该选项,则也需要 cache-remote-username

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

仅当设置了远程主机时可用

cache-remote-port

外部 Infinispan 集群的端口。

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

用于身份验证到外部 Infinispan 集群的用户名。

如果连接到不安全的外部 Infinispan 集群,则它是可选的。如果指定了该选项,则也需要 cache-remote-password

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

仅当设置了远程主机时可用

在此页上