Keycloak 服务

Keycloak 是一个开源的身份和访问管理(IAM)解决方案。

Keycloak 官网链接

Kubernetes 中部署 Keycloak

  • Kubernetes 1.35
  • Kustomize Version: v5.7.1
  • Keycloak 26.x
  • Aurora RDS PostgreSQL

参考官方文档在 Kubernetes 中部署 Keycloak

下载 Keycloak 配置文件: https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/refs/heads/main/kubernetes/keycloak.yaml 并修改数据库相关配置,本示例使用 AWS Aurora PostgreSQL:

keycloak.yaml
## 要连接 RDS PostgreSQL,需要设置这些核心环境变量:
- name: KC_DB
value: postgres
- name: KC_DB_URL_HOST
value: <RDS_ENDPOINT>
- name: KC_DB_URL_DATABASE
value: <DB_NAME>
- name: KC_DB_USERNAME
valueFrom:
secretKeyRef:
name: keycloak-db-secret
key: username
- name: KC_DB_PASSWORD
valueFrom:
secretKeyRef:
name: keycloak-db-secret
key: password

本示例使用 Kustomize 部署,文档结构如下:

$ tree
.
├── base
│ ├── ingresses.yaml
│ ├── kustomization.yaml
│ ├── services.yaml
│ └── statefulset.yaml
└── overlays
├── dev
└── prod
└── kustomization.yaml

base/statefulset.yaml 内容如下,主要参考官网安装文档(https://raw.githubusercontent.com/keycloak/keycloak-quickstarts/refs/heads/main/kubernetes/keycloak.yaml

base/statefulset.yaml
apiVersion: apps/v1
# Use a stateful setup to ensure that for a rolling update Pods are restarted with a rolling strategy one-by-one.
# This prevents losing in-memory information stored redundantly in two Pods.
kind: StatefulSet
metadata:
name: keycloak
labels:
app: keycloak
spec:
serviceName: keycloak-discovery
# Run with one replica to save resources, or with two replicas to allow for rolling updates for configuration changes
replicas: 2
selector:
matchLabels:
app: keycloak
template:
metadata:
labels:
app: keycloak
spec:
containers:
- name: keycloak
image: quay.io/keycloak/keycloak:26.5.4
args: ["start"]
env:
- name: KC_BOOTSTRAP_ADMIN_USERNAME
value: "admin"
- name: KC_BOOTSTRAP_ADMIN_PASSWORD
value: "admin"
# In a production environment, add a TLS certificate to Keycloak to either end-to-end encrypt the traffic between
# the client or Keycloak, or to encrypt the traffic between your proxy and Keycloak.
# Respect the proxy headers forwarded by the reverse proxy
# In a production environment, verify which proxy type you are using, and restrict access to Keycloak
# from other sources than your proxy if you continue to use proxy headers.
- name: KC_PROXY_HEADERS
value: "xforwarded"
- name: KC_HTTP_ENABLED
value: "true"
# In this explorative setup, no strict hostname is set.
# For production environments, set a hostname for a secure setup.
- name: KC_HOSTNAME_STRICT
value: "false"
- name: KC_HEALTH_ENABLED
value: "true"
- name: 'KC_CACHE'
value: 'ispn'
# Passing the Pod's IP primary address to the JGroups clustering as this is required in IPv6 only setups
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
# Instruct JGroups which DNS hostname to use to discover other Keycloak nodes
# Needs to be unique for each Keycloak cluster
- name: KC_CACHE_EMBEDDED_NETWORK_BIND_ADDRESS
value: '$(POD_IP)'
- name: 'KC_DB_URL_DATABASE'
value: 'keycloak'
- name: 'KC_DB_URL_HOST'
value: '<RDS_endpoint>'
- name: 'KC_DB'
value: 'postgres'
# In a production environment, use a secret to store username and password to the database
- name: 'KC_DB_PASSWORD'
value: '<RDS_PASSWORD>'
- name: 'KC_DB_USERNAME'
value: '<RDS_USERNAME>'
ports:
- name: http
containerPort: 8080
- name: jgroups
containerPort: 7800
- name: jgroups-fd
containerPort: 57800
startupProbe:
httpGet:
path: /health/started
port: 9000
periodSeconds: 1
failureThreshold: 600
readinessProbe:
httpGet:
path: /health/ready
port: 9000
periodSeconds: 10
failureThreshold: 3
livenessProbe:
httpGet:
path: /health/live
port: 9000
periodSeconds: 10
failureThreshold: 3
resources:
limits:
cpu: 2000m
memory: 2000Mi
requests:
cpu: 500m
memory: 1700Mi

base/services.yaml 内容如下:

base/services.yaml
apiVersion: v1
kind: Service
metadata:
name: keycloak
labels:
app: keycloak
spec:
ports:
- protocol: TCP
port: 8080
targetPort: http
name: http
## 主要用于 ALB 健康检查
- name: management
port: 9000
targetPort: 9000
selector:
app: keycloak
type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
labels:
app: keycloak
name: keycloak-discovery
spec:
selector:
app: keycloak
clusterIP: None
type: ClusterIP

base/ingresses.yaml 内容如下:

base/ingresses.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
alb.ingress.kubernetes.io/healthcheck-path: /health/ready
alb.ingress.kubernetes.io/healthcheck-port: "9000" # 健康检查(Health Check)端口和 web 端口(8080)不同
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
name: keycloak-web-ingress
spec:
ingressClassName: alb
rules:
- http:
paths:
- backend:
service:
name: keycloak
port:
number: 8080
path: /
pathType: Prefix

base/kustomization.yaml 内容如下:

base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- statefulset.yaml
- services.yaml
- ingresses.yaml

overlays/prod/kustomization.yaml 内容如下

overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: keycloak

resources:
- ../../base

查看最终生成的配置:

$ kubectl kustomize overlays/prod/
apiVersion: v1
kind: Service
metadata:
labels:
app: keycloak
name: keycloak
namespace: keycloak
spec:
ports:
- name: http
port: 8080
protocol: TCP
targetPort: http
- name: management
port: 9000
targetPort: 9000
selector:
app: keycloak
type: ClusterIP
---
apiVersion: v1
kind: Service
metadata:
labels:
app: keycloak
name: keycloak-discovery
namespace: keycloak
spec:
clusterIP: None
selector:
app: keycloak
type: ClusterIP
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app: keycloak
name: keycloak
namespace: keycloak
spec:
replicas: 2
selector:
matchLabels:
app: keycloak
serviceName: keycloak-discovery
template:
metadata:
labels:
app: keycloak
spec:
containers:
- args:
- start
env:
- name: KC_BOOTSTRAP_ADMIN_USERNAME
value: admin
- name: KC_BOOTSTRAP_ADMIN_PASSWORD
value: admin
- name: KC_PROXY_HEADERS
value: xforwarded
- name: KC_HTTP_ENABLED
value: "true"
- name: KC_HOSTNAME_STRICT
value: "false"
- name: KC_HEALTH_ENABLED
value: "true"
- name: KC_CACHE
value: ispn
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: KC_CACHE_EMBEDDED_NETWORK_BIND_ADDRESS
value: $(POD_IP)
- name: KC_DB_URL_DATABASE
value: keycloak
- name: KC_DB_URL_HOST
value: vp-devops-db-postgresql-instance.cleeqsmauuvg.ap-east-1.rds.amazonaws.com
- name: KC_DB
value: postgres
- name: KC_DB_PASSWORD
value: Q4h9o4joFONtdnvQLnw
- name: KC_DB_USERNAME
value: postgres
image: quay.io/keycloak/keycloak:26.5.4
livenessProbe:
failureThreshold: 3
httpGet:
path: /health/live
port: 9000
periodSeconds: 10
name: keycloak
ports:
- containerPort: 8080
name: http
- containerPort: 7800
name: jgroups
- containerPort: 57800
name: jgroups-fd
readinessProbe:
failureThreshold: 3
httpGet:
path: /health/ready
port: 9000
periodSeconds: 10
resources:
limits:
cpu: 2000m
memory: 2000Mi
requests:
cpu: 500m
memory: 1700Mi
startupProbe:
failureThreshold: 600
httpGet:
path: /health/started
port: 9000
periodSeconds: 1
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
alb.ingress.kubernetes.io/healthcheck-path: /health/ready
alb.ingress.kubernetes.io/healthcheck-port: "9000"
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
name: keycloak-web-ingress
namespace: keycloak
spec:
ingressClassName: alb
rules:
- http:
paths:
- backend:
service:
name: keycloak
port:
number: 8080
path: /
pathType: Prefix