Keycloak on K8S HA 部署
本文从 0 到 1 手把手介绍了如何不依赖 Operator 手动部署 Keycloak HA 至 kubernetes 集群。不依赖 helm、operator,纯手撸。
本文将从 0 到 1 手把手教你如何不依赖 Operator、Helm,纯手动部署 Keycloak HA 至 kubernetes 集群
🎩 转发请标明出处
🍄 环境配置
Keycloak: 23.0.7
MySQL: 8.0
域名:test.keycloak.org
命名空间:keycloak
经测试,本文适用于 Keycloak 23.0.3 ~ 24.0.3
的所有版本,将下文中的容器镜像版本进行替换即可。
差异不大的版本,可以自行测试验证。
💫 前置准备
🍕 容器镜像
🗣 仅当需要自定义容器镜像时才需要,否则直接使用官方镜像即可
可以参考如下这个项目:
https://github.com/yangsijie666/keycloak-dingtalk-social-identity-provider
该项目实现了自定义 Keycloak IDP,用于支持钉钉登陆。
看下该项目的容器镜像打包 Dockerfile:
FROM maven:3.8-openjdk-17 AS builder
WORKDIR /app
COPY pom.xml /app
COPY ./settings.xml /usr/share/maven/conf/settings.xml
RUN mvn verify --fail-never -s /usr/share/maven/conf/settings.xml
COPY . /app
RUN mvn clean install -s /usr/share/maven/conf/settings.xml
FROM quay.io/keycloak/keycloak:23.0.7 as kcbuilder
# Enable health and metrics support
ENV KC_HEALTH_ENABLED=true
ENV KC_METRICS_ENABLED=true
WORKDIR /opt/keycloak
COPY --from=builder --chown=keycloak:keycloak /app/target/*.jar /opt/keycloak/providers/
RUN /opt/keycloak/bin/kc.sh build
FROM quay.io/keycloak/keycloak:23.0.7
COPY --from=kcbuilder /opt/keycloak/ /opt/keycloak/
ENTRYPOINT [ "/opt/keycloak/bin/kc.sh" ]
其中 1 ~ 7 行是在构建插件 jar 包,不用管;
12 ~ 13 行开启 HA 环境下需要用到的 /health/ready
、/health/live
、/health/started
和 /metrics
,分别为存活探测和暴露监控指标;
16 行将构建的 jar 包放入 Keycloak 指定目录中;
17 行执行 build 命令;
19 ~ 21 行将 build 后生成的所有文件覆盖至当前目录下,形成运行用的容器。
🤨 19 ~ 21 行为何需要多此一举,没搞懂
后续就是将容器构建,推送至镜像仓库,这里就不赘述了。
🍎 SSL 证书
🗣 有条件的可以申请现成的(腾讯云可以申请免费 SSL 证书)或直接用现有的
没有条件的,可以通过以下命令直接生成即可:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout key.pem -out certificate.pem -subj "/CN=test.keycloak.org/O=test.keycloak.org" -addext "subjectAltName = DNS:test.keycloak.org"
这里生成了 key.pem
和 certificate.pem
文件。
通过以下命令,部署 SSL 证书的 TLS 类型的 Secret:
kubectl create secret -n keycloak tls keycloak-tls-secret --cert certificate.pem --key key.pem
至此,K8S 中的资源视图如下:
🌰 数据库
❗️ 生产环境下请使用独立维护的数据库
这里使用 MySQL 8.0
数据库。
这里直接在 K8S 中创建一个测试用的 MySQL 实例:
apiVersion: v1
kind: Namespace
metadata:
name: mysql
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-db
namespace: mysql
spec:
selector:
matchLabels:
app: mysql-db
replicas: 1
template:
metadata:
labels:
app: mysql-db
spec:
containers:
- name: mysql-db
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
value: testpassword
---
apiVersion: v1
kind: Service
metadata:
name: mysql-db-service
namespace: mysql
spec:
selector:
app: mysql-db
type: ClusterIP
ports:
- port: 3306
targetPort: 3306
通过以下命令,部署数据库访问账号密码至 Secret 中:
kubectl create secret -n keycloak generic keycloak-db-secret \
--from-literal=username=root \
--from-literal=password=testpassword
至此,K8S 中的资源视图如下:
在数据库中创建名为 keycloak
的逻辑库:
mysql> create database keycloak;
Query OK, 1 row affected (0.01 sec)
🧲 域名
🗣 有条件的可以直接用现有的
没条件的,可以通过改本机的 /etc/hosts
来实现,增加如下条目:
x.x.x.x test.keycloak.org
🛠️ 正式部署
☁️ 部署服务发现 Service
在 K8S 环境中,Keycloak 支持通过 Service 使用 7800
接口进行服务发现,因此部署该用途的 Service。
创建的 YAML 如下:
apiVersion: v1
kind: Service
metadata:
labels:
app: keycloak
name: keycloak-discovery
namespace: keycloak
spec:
clusterIP: None
clusterIPs:
- None
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- port: 7800
protocol: TCP
targetPort: 7800
publishNotReadyAddresses: true
selector:
app: keycloak
sessionAffinity: None
type: ClusterIP
至此,K8S 中的资源视图如下:
🌀 部署服务访问 Service
在 K8S 部署用于访问服务的 Service,这里映射 Pod 的 8443
端口。
创建的 YAML 如下:
apiVersion: v1
kind: Service
metadata:
labels:
app: keycloak
name: keycloak-service
namespace: keycloak
spec:
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- name: https
port: 8443
protocol: TCP
targetPort: 8443
selector:
app: keycloak
sessionAffinity: None
type: ClusterIP
至此,K8S 中的资源视图如下:
🎃 部署 Ingress(Optional)
若集群中部署了 Nginx Ingress Controller,则可以创建 Ingress,后端为上一步创建的 Keycloak 的服务访问 Service keycloak-service
,同时绑定 TLS 配置(之前创建的 keycloak-tls-secret
)。
创建的 YAML 如下:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
name: keycloak-ingress
namespace: keycloak
spec:
ingressClassName: nginx
rules:
- host: test.keycloak.org
http:
paths:
- backend:
service:
name: keycloak-service
port:
number: 8443
path: /
pathType: Prefix
tls:
- hosts:
- test.keycloak.org
secretName: keycloak-tls-secret
查看创建结果如下:
至此,K8S 中的资源视图如下:
🌈 部署 Keycloak
开始部署 Keycloak,涉及到的核心的环境变量如下表所示:
环境变量 | 取值 | 说明 |
---|---|---|
KC_HOSTNAME | test.keycloak.org | 访问 Keycloak 时的域名 |
KC_HTTP_PORT | 8080 | HTTP 端口 |
KC_HTTPS_PORT | 8443 | HTTPS 端口 |
KC_HTTPS_CERTIFICATE_FILE | /mnt/certificates/tls.crt | 生产环境需通过 HTTPS 访问,这里是之前部署的 SSL 证书 |
KC_HTTPS_CERTIFICATE_KEY_FILE | /mnt/certificates/tls.key | 生产环境需通过 HTTPS 访问,这里是之前部署的 SSL 证书 |
KC_DB | mysql | 数据库类型,这里用 mysql |
KC_DB_URL | jdbc:mysql://mysql-db-service.mysql:3306/keycloak?characterEncoding=UTF-8 | 数据库连接地址,这里通过之前部署的 mysql 的 Service 进行访问 |
KC_DB_USERNAME | root | mysql账号 |
KC_DB_PASSWORD | testpassword | mysql密码 |
KC_HEALTH_ENABLED | true | 开启健康检查 |
KC_METRICS_ENABLED | true | 开启监控指标 |
KC_CACHE | ispn | |
KC_CACHE_STACK | kubernetes | |
KC_PROXY | passthrough | |
KEYCLOAK_ADMIN | admin | 初始admin账号 |
KEYCLOAK_ADMIN_PASSWORD | changeme | 初始admin密码 |
KC_TRUSTSTORE_PATHS | /var/run/secrets/kubernetes.io/serviceaccount/ca.crt | 用于访问 k8s 集群 |
部署用的 YAML 如下:
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
app: keycloak
name: keycloak
namespace: keycloak
spec:
podManagementPolicy: OrderedReady
replicas: 3
selector:
matchLabels:
app: keycloak
serviceName: ""
template:
metadata:
labels:
app: keycloak
spec:
containers:
- args:
- -Djgroups.dns.query=keycloak-discovery.keycloak
- --verbose
- start
env:
- name: KC_HOSTNAME
value: test.keycloak.org
- name: KC_FEATURES
value: multi-site
- name: KC_TRANSACTION_XA_ENABLED
value: "false"
- name: KC_HTTP_PORT
value: "8080"
- name: KC_HTTPS_PORT
value: "8443"
- name: KC_HTTPS_CERTIFICATE_FILE
value: /mnt/certificates/tls.crt
- name: KC_HTTPS_CERTIFICATE_KEY_FILE
value: /mnt/certificates/tls.key
- name: KC_DB
value: mysql
- name: KC_DB_USERNAME
valueFrom:
secretKeyRef:
key: username
name: keycloak-db-secret
- name: KC_DB_PASSWORD
valueFrom:
secretKeyRef:
key: password
name: keycloak-db-secret
- name: KC_DB_URL
value: jdbc:mysql://mysql-db-service.mysql:3306/keycloak?characterEncoding=UTF-8
- name: KC_DB_POOL_INITIAL_SIZE
value: "30"
- name: KC_DB_POOL_MIN_SIZE
value: "30"
- name: KC_DB_POOL_MAX_SIZE
value: "30"
- name: KC_HEALTH_ENABLED
value: "true"
- name: KC_CACHE
value: ispn
- name: KC_CACHE_STACK
value: kubernetes
- name: KC_PROXY
value: passthrough
- name: KC_HTTP_MAX_QUEUED_REQUESTS
value: "1000"
- name: KC_LOG_CONSOLE_OUTPUT
value: json
- name: KC_METRICS_ENABLED
value: "true"
- name: KC_HTTP_POOL_MAX_THREADS
value: "66"
- name: KEYCLOAK_ADMIN
value: "admin"
- name: KEYCLOAK_ADMIN_PASSWORD
value: "changeme"
- name: KC_TRUSTSTORE_PATHS
value: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
image: quay.io/keycloak/keycloak:23.0.7
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
httpGet:
path: /health/live
port: 8443
scheme: HTTPS
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
name: keycloak
ports:
- containerPort: 8443
name: https
protocol: TCP
- containerPort: 8080
name: http
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /health/ready
port: 8443
scheme: HTTPS
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
limits:
cpu: "6"
memory: 2250M
requests:
cpu: "2"
memory: 1250M
startupProbe:
failureThreshold: 600
httpGet:
path: /health/started
port: 8443
scheme: HTTPS
periodSeconds: 1
successThreshold: 1
timeoutSeconds: 1
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /mnt/certificates
name: keycloak-tls-certificates
restartPolicy: Always
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- name: keycloak-tls-certificates
secret:
defaultMode: 420
optional: false
secretName: keycloak-tls-secret
updateStrategy:
rollingUpdate:
partition: 0
type: RollingUpdate
至此,K8S 中的资源视图如下:
🤖 验证
根据如下步骤进行验证。
😺 映射服务至本地端口
❗️ 若能直接访问(例如使用了 LoadBalancer 或 Ingress 等方式),忽略本步骤
通过如下命令,将 Keycloak 的服务访问 Service 转发至本地:
sudo kubectl port-forward -n keycloak svc/keycloak-service 443:8443
💕 配置 DNS 解析
👀 有合法域名
🗣 注意将上文中测试用的域名
test.keycloak.org
替换为合法域名your.domain.com
在域名服务商处,配置 DNS 解析条目即可,将合法域名 your.domain.com
解析至部署的对外暴露的服务地址(LoadBalancer 或 Ingress 等)。
🦴 无合法域名
🗣 这里用上文中的测试域名
test.keycloak.org
通过修改本机的 hosts 文件,本地解析该域名至部署的对外暴露的服务地址(LoadBalancer 或 Ingress 等)。
通过改本机的 /etc/hosts
,增加如下条目:
x.x.x.x test.keycloak.org
若已将服务映射至本地,则上述的 x.x.x.x
则为 127.0.0.1
。
💯 访问 Keycloak
在浏览器输入 https://域名
即可,若使用的是上文中的,则访问路径为 https://test.keycloak.org
,看到如下页面就成功了:
至此,访问请求链路如下图:
更多推荐
所有评论(0)