Links#
https://www.keycloak.org/server/containers
https://www.keycloak.org/server/configuration-production
https://www.keycloak.org/server/db
https://www.keycloak.org/server/hostname
https://www.keycloak.org/server/reverseproxy
https://www.keycloak.org/operator/installation
https://www.keycloak.org/operator/basic-deployment1. Linux VM With systemd#
VM 部署适合小规模、传统网络、没有 Kubernetes 的环境。生产上仍然要使用 external PostgreSQL、HTTPS、反向代理和系统级监控。
layout:
/opt/keycloak
/etc/keycloak/keycloak.conf
/var/log/keycloak
/etc/keycloak/tlsExample config:
hostname=sso.example.com
http-enabled=false
https-certificate-file=/etc/keycloak/tls/tls.crt
https-certificate-key-file=/etc/keycloak/tls/tls.key
db=postgres
db-url=jdbc:postgresql://postgres.example.com:5432/keycloak
db-username=keycloak
db-password=${KC_DB_PASSWORD}
health-enabled=true
metrics-enabled=true
proxy-headers=xforwardedsystemd unit:
[Unit]
Description=Keycloak
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=keycloak
Group=keycloak
EnvironmentFile=/etc/keycloak/keycloak.env
WorkingDirectory=/opt/keycloak
ExecStart=/opt/keycloak/bin/kc.sh start --config-file=/etc/keycloak/keycloak.conf
Restart=on-failure
RestartSec=10
LimitNOFILE=65535
[Install]
WantedBy=multi-user.targetoperations:
sudo systemctl daemon-reload
sudo systemctl enable --now keycloak
sudo systemctl status keycloak
journalctl -u keycloak -f2. Docker#
Docker local dev:
docker run --name keycloak-demo --rm \
-p 8080:8080 \
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
-e KC_BOOTSTRAP_ADMIN_PASSWORD=change_me_now \
quay.io/keycloak/keycloak:latest \
start-devProduction-like compose:
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: change_me_db
volumes:
- postgres-data:/var/lib/postgresql/data
keycloak:
image: quay.io/keycloak/keycloak:latest
command:
- start
environment:
KC_HOSTNAME: sso.example.com
KC_PROXY_HEADERS: xforwarded
KC_HTTP_ENABLED: "true"
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: change_me_db
KC_HEALTH_ENABLED: "true"
KC_METRICS_ENABLED: "true"
KC_BOOTSTRAP_ADMIN_USERNAME: admin
KC_BOOTSTRAP_ADMIN_PASSWORD: change_me_now
depends_on:
- postgres
ports:
- "8080:8080"
volumes:
postgres-data:notes:
for production:
do not use start-dev
use managed PostgreSQL or HA PostgreSQL
put TLS at load balancer or Keycloak
use secrets instead of plaintext compose env
pin image version, do not blindly use latest3. K8S With Operator#
Keycloak has an official Operator. For production Kubernetes, prefer OLM with manual approval, or a carefully governed GitOps manifest. Community Helm charts can be useful, but treat them as third-party packaging and review upgrade behavior.
OLM baseline:
recommended:
install Keycloak Operator through OLM
use manual approval for Operator upgrades
test Keycloak and Operator upgrades in staging first
backup database before approving production upgradeOperator install without OLM:
kubectl create namespace keycloak
kubectl apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/26.6.3/kubernetes/keycloaks.k8s.keycloak.org-v1.yml
kubectl apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/26.6.3/kubernetes/keycloakrealmimports.k8s.keycloak.org-v1.yml
kubectl -n keycloak apply -f https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/26.6.3/kubernetes/kubernetes.ymlMinimal Keycloak CR:
apiVersion: k8s.keycloak.org/v2alpha1
kind: Keycloak
metadata:
name: keycloak
namespace: keycloak
spec:
instances: 3
db:
vendor: postgres
host: postgres.example.com
database: keycloak
usernameSecret:
name: keycloak-db
key: username
passwordSecret:
name: keycloak-db
key: password
hostname:
hostname: sso.example.com
http:
tlsSecret: keycloak-tls
additionalOptions:
- name: health-enabled
value: "true"
- name: metrics-enabled
value: "true"Verify:
kubectl -n keycloak get pods
kubectl -n keycloak get keycloak
kubectl -n keycloak logs deploy/keycloak -f
kubectl -n keycloak describe keycloak keycloakNetwork policy baseline:
allow ingress:
from ingress controller namespace to Keycloak HTTP/HTTPS port
allow egress:
to PostgreSQL
to external LDAP / AD if User Federation is used
to upstream IdP metadata / JWKS endpoints
to SMTP if email is used
deny:
random namespace to admin endpoint4. High Availability#
HA requirements:
at least 2-3 Keycloak replicas
external HA PostgreSQL
shared hostname behind load balancer
sticky sessions can help, but do not rely on a single pod
readiness probe and rolling update configured
DB connection pool sized for replicasCapacity starting point:
estimate:
peak login requests per minute
token refresh rate
admin/API automation rate
number of apps / clients
external LDAP / AD lookup latency if User Federation is used
scale:
increase replicas for stateless HTTP pressure
increase DB capacity for session/event/write pressure
tune cache and DB pool only after metrics show bottleneckBackup:
must backup:
PostgreSQL database
Keycloak signing keys
custom themes
realm config export
secret manager entries
restore test:
restore DB snapshot into isolated environment
start Keycloak with same version
verify admin login
verify OIDC discovery
verify one OIDC app and one SAML app5. Operations#
Rolling restart:
kubectl -n keycloak rollout restart deployment/keycloak
kubectl -n keycloak rollout status deployment/keycloakUseful checks:
curl -fsS https://sso.example.com/health/ready
curl -fsS https://sso.example.com/metrics
curl -fsS https://sso.example.com/realms/master/.well-known/openid-configurationUpgrade checklist:
before:
read Keycloak release notes
backup database
export realm config
test upgrade in staging
during:
upgrade one environment at a time
watch logs, HTTP 5xx, DB pool, login errors
verify OIDC, SAML, LDAP federation, admin console
rollback:
rollback container/version only if DB schema is compatible
otherwise restore DB snapshot into previous version
keep version-specific runbook for major upgradesCommon diagnostics:
kubectl -n keycloak get pods -o wide
kubectl -n keycloak describe pod <pod>
kubectl -n keycloak logs <pod> --previous
kubectl -n keycloak top pod
kubectl -n keycloak get events --sort-by=.lastTimestamp