【问题标题】:Deploying a Keycloak HA cluster to kubernetes | Pods are not discovering each other将 Keycloak HA 集群部署到 kubernetes | Pod 没有发现彼此
【发布时间】:2022-01-14 02:38:03
【问题描述】:

我正在尝试在 Kubernetes (GKE) 上部署 HA Keycloak 集群(2 个节点)。到目前为止,集群节点(pod)在我从日志中推断出的所有情况下都未能发现彼此。 pod 启动且服务启动但无法看到其他节点的位置。

组件

  • PostgreSQL 数据库部署,默认端口上有 clusterIP 服务。
  • Keycloak 部署 2 个节点,其中包含所需的端口容器端口 8080、8443、相关的 clusterIP 和 LoadBalancer 类型的服务,以将服务公开到 Internet

日志片段:

INFO  [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (MSC service thread 1-4) ISPN000078: Starting JGroups channel ejb
INFO  [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (MSC service thread 1-4) ISPN000094: Received new cluster view for channel ejb: [keycloak-567575d6f8-c5s42|0] (1) [keycloak-567575d6f8-c5s42]
INFO  [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (MSC service thread 1-1) ISPN000094: Received new cluster view for channel ejb: [keycloak-567575d6f8-c5s42|0] (1) [keycloak-567575d6f8-c5s42]
INFO  [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (MSC service thread 1-3) ISPN000094: Received new cluster view for channel ejb: [keycloak-567575d6f8-c5s42|0] (1) [keycloak-567575d6f8-c5s42]
INFO  [org.infinispan.remoting.transport.jgroups.JGroupsTransport] (MSC service thread 1-4) ISPN000079: Channel ejb local address is keycloak-567575d6f8-c5s42, physical addresses are [127.0.0.1:55200]
.
.
.
INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0025: Keycloak 15.0.2 (WildFly Core 15.0.1.Final) started in 67547ms - Started 692 of 978 services (686 services are lazy, passive or on-demand)
INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0060: Http management interface listening on http://127.0.0.1:9990/management
INFO  [org.jboss.as] (Controller Boot Thread) WFLYSRV0051: Admin console listening on http://127.0.0.1:9990

正如我们在上面的日志中看到的那样,节点将自己视为唯一的容器/pod ID

尝试 KUBE_PING 协议

我尝试使用 kubernetes.KUBE_PING 协议进行发现,但它不起作用并且调用了 kubernetes 向下 API。日志中有 403 授权错误(以下是其中的一部分):

Server returned HTTP response code: 403 for URL: https://[SERVER_IP]:443/api/v1/namespaces/default/pods

此时,我能够登录到门户并进行更改,但它还不是 HA 集群,因为更改未复制并且会话未保留,换句话说,如果我删除了我正在使用我被重定向到另一个新会话(好像它是一个单独的节点)

尝试 DNS_PING 协议

当我尝试 DNS_PING 时,情况有所不同,我没有遇到 Kubernetes 向下 API 问题,但我无法登录。

详细地说,我能够正常访问登录页面,但是当我输入我的凭据并尝试登录页面时,尝试加载但让我回到登录页面,但在这方面的 Pod 中没有任何日志。

以下是我过去几天参考的一些参考资料:

我的 Yaml 清单文件

Postgresql 部署

apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres
spec:
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:13
          imagePullPolicy: IfNotPresent
          ports:
          - containerPort: 5432
          env:
            - name: POSTGRES_PASSWORD
              value: "postgres"
            - name: PGDATA
              value: /var/lib/postgresql/data/pgdata
---
apiVersion: v1
kind: Service
metadata:
  name: postgres
spec:
  selector:
    app: postgres
  ports:
  - port: 5432
    targetPort: 5432

Keycloak HA 集群部署

apiVersion: apps/v1
kind: Deployment
metadata:
  name: keycloak
  labels:
    app: keycloak
spec:
  replicas: 2 
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
  selector:
    matchLabels:
      app: keycloak
  template:
    metadata:
      labels:
        app: keycloak
    spec:
      containers:
      - name: keycloak
        image: jboss/keycloak
        env:
            - name: KEYCLOAK_USER 
              value: admin
            - name: KEYCLOAK_PASSWORD 
              value: admin123
            - name: DB_VENDOR
              value: POSTGRES
            - name: DB_ADDR
              value: "postgres" 
            - name: DB_PORT
              value: "5432"
            - name: DB_USER
              value: "postgres"
            - name: DB_PASSWORD
              value: "postgres"
            - name: DB_SCHEMA
              value: "public"
            - name: DB_DATABASE
              value: "keycloak"
#            - name: JGROUPS_DISCOVERY_PROTOCOL
#              value: kubernetes.KUBE_PING
#            - name: JGROUPS_DISCOVERY_PROPERTIES
#              value: dump_requests=true,port_range=0,namespace=default
#              value: port_range=0,dump_requests=true
            - name: JGROUPS_DISCOVERY_PROTOCOL
              value: dns.DNS_PING
            - name: JGROUPS_DISCOVERY_PROPERTIES
              value: "dns_query=keycloak"
            - name: CACHE_OWNERS_COUNT
              value: '2'
            - name: CACHE_OWNERS_AUTH_SESSIONS_COUNT
              value: '2'
            - name: PROXY_ADDRESS_FORWARDING
              value: "true"
        ports:
            - name: http
              containerPort: 8080
            - name: https
              containerPort: 8443

---
apiVersion: v1
kind: Service
metadata:
  name: keycloak
  labels:
    app: keycloak
spec:
  type: ClusterIP
  ports:
    - name: http
      port: 80
      targetPort: 8080
    - name: https
      port: 443
      targetPort: 8443
  selector:
    app: keycloak
---
apiVersion: v1
kind: Service
metadata:
  name: keycloak-np
  labels:
    app: keycloak
spec:
  type: LoadBalancer 
  ports:
    - name: http
      port: 80
      targetPort: 8080
    - name: https
      port: 443
      targetPort: 8443
  selector:
    app: keycloak

重要提示

  • 我尝试了有和没有数据库设置的两种协议。
  • 上面的 yaml 包含了我一次尝试的所有发现协议组合(已注释的那些)

【问题讨论】:

  • 你为什么不用JDBC_PING
  • KUBE_PING 在我看来更像是一种原生解决方案。

标签: kubernetes google-kubernetes-engine keycloak high-availability keycloak-services


【解决方案1】:

kube ping 的工作方式类似于在 keycloak 的 pod 中运行kubectl get pods 以查找其他 pod 的 ip,然后尝试一一连接。除了 keycloak 直接查询 Kubernetes API 而不是运行kubectl

查询 API 需要凭据,基本上是访问令牌。

如果你有令牌,你可以直接传递它,但它不是很安全也不是很方便(你可以在这里查看其他选项和行为:https://github.com/jgroups-extras/jgroups-kubernetes/blob/master/src/main/java/org/jgroups/protocols/kubernetes/KUBE_PING.java)。

Kubernetes 有一种非常方便的方法来注入令牌,以供 pod(或在该 pod 中运行的软件)使用以查询 api。

您只需创建一个服务帐户,授予它使用角色绑定调用 Kubernetes API 的权限,并将 pod 设置为使用该服务帐户。

这样做只是在 Kubernetes API 的每个客户端都知道和期望的标准位置在 pod 内挂载一个带有该帐户令牌的文件。

这样,当 keycloak 尝试调用 Kubernetes API 时,它会在预定义的位置找到令牌文件并使用它来发出请求。

虽然不是很方便,但您可能会遇到更不方便的情况,即缺少创建角色绑定的权限(在更严格的环境中有些常见)。您可以要求某人为您创建服务帐户和角色绑定,或者只是(非常不安全)通过SA_TOKEN_FILE 环境传递您自己用户的令牌(如果您能够在 keycloak 命名空间上执行kubectl get pod,则您有权限)多变的。使用 secret 或 configmap 创建文件,将其挂载到 pod 并将变量设置为该文件位置。

如果您有权在集群中创建服务帐户和角色绑定:

一个例子(未测试):

export TARGET_NAMESPACE=default

# convenient method to create a service account 
kubectl create serviceaccount keycloak-kubeping-service-account -n $TARGET_NAMESPACE

# No convenient method to create Role and RoleBindings
# Needed to explicitly define them.
cat <<EOF | kubectl apply -f -
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: keycloak-kubeping-pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list"]

---

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
  name: keycloak-kubeping-api-access
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: keycloak-kubeping-pod-reader
subjects:
- kind: ServiceAccount
  name: keycloak-kubeping-service-account
  namespace: $TARGET_NAMESPACE

EOF

在部署时,您设置 serviceAccount:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: keycloak
spec:
  template:
    spec:
      serviceAccount: keycloak-kubeping-service-account
      serviceAccountName: keycloak-kubeping-service-account
      containers:
      - name: keycloak
        image: jboss/keycloak
        env:
#          ...
            - name: JGROUPS_DISCOVERY_PROTOCOL
              value: kubernetes.KUBE_PING
            - name: JGROUPS_DISCOVERY_PROPERTIES
              value: dump_requests=true
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.namespace
#          ...

dump_requests=true 将帮助您调试 Kubernetes 请求。最好在生产中使用false。您可以使用 namespace=&lt;yournamespace 而不是 KUBERNETES_NAMESPACE,但这是 pod 必须自动检测其运行所在的命名空间的便捷方式。

请注意,KUBE_PING 会查找命名空间中的所有 pod,而不仅仅是 keycloak pod,并且会尝试连接所有这些 pod。当然,如果您的其他 pod 不关心这一点,也没关系。

【讨论】:

  • 感谢@motobói 的回答,我以与上述方法非常相似的方式解决了这个问题,并且成功了。我非常感谢对 keycloak 和 KUBE_PING 机制的透彻解释。
猜你喜欢
  • 2018-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-26
  • 1970-01-01
相关资源
最近更新 更多