把 Keycloak 放进容器运行,不少团队起步时只执行了一条 docker run 命令,测试登录没问题就认为部署结束。真正出问题往往在第一次重启之后:之前创建的用户、角色、客户端全部消失,或者登录页面样式回到默认主题,甚至从外网登录时浏览器跳转到 172.17.0.2 这样的容器内部地址。容器化 Keycloak 的关键不是启动镜像,而是把状态、配置和入口都处理到容器之外。

下面从启动模式、数据库、反代和自定义资源四个方向拆解生产环境需要落实的细节,配置示例以 Docker Compose 为主,Kubernetes 的改造思路相同。
一、启动模式决定容器的基础行为
Keycloak 从 17 版本开始切换到 Quarkus 发行版,容器镜像的启动参数与旧 WildFly 完全不同。现在官方镜像默认使用 start 命令,要求显式提供数据库、主机名等关键配置;本地快速体验可以用 start-dev 开发模式,它会启用 H2 内存数据库、关闭 HTTPS 强制,并允许热加载主题。开发模式虽然方便,但绝不建议直接发布到生产环境,因为只要容器重建,所有配置都会回到初始状态。
生产启动至少需要设置 KC_BOOTSTRAP_ADMIN_USERNAME 和 KC_BOOTSTRAP_ADMIN_PASSWORD 来创建初始管理员,避免每次进入欢迎页手动填写。环境变量命名统一为 KC_ 前缀,例如 KC_DB、KC_DB_URL、KC_HOSTNAME。这些变量会映射到 keycloak.conf 的配置项,启动时由 Quarkus 读取。一个最小但可重复启动的容器命令如下:
docker run -d --name keycloak \ -p 8080:8080 \ -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \ -e KC_BOOTSTRAP_ADMIN_PASSWORD=change-me \ -e KC_DB=postgres \ -e KC_DB_URL=jdbc:postgresql://192.168.1.20:5432/keycloak \ -e KC_DB_USERNAME=keycloak \ -e KC_DB_PASSWORD=keycloak-pass \ keycloak/keycloak:26.1 start
这里没有使用卷保存 /opt/keycloak/data 目录,因此像导入的 realm 文件、缓存文件等仍然可能随容器销毁而丢失。下一步需要把这些目录挂载出来,并解决数据库自身的持久化。
二、用外置数据库和卷存放真实状态
默认 H2 数据库只适合开发和单机演示,它的数据通常写入容器可写层或临时目录,容器删除后数据很难恢复,也不支持多个 Keycloak 实例同时连接。生产环境最常见的选择是 PostgreSQL,其次是 MySQL 或 MariaDB。使用外置数据库后,realm、用户、角色、客户端等核心数据都保存在数据库表中,Keycloak 容器本身变成无状态计算节点,这为后续水平扩容打下基础。
在 Docker Compose 中,建议把数据库和 Keycloak 放在同一个网络里,通过服务名访问,而不是写死 IP。同时给数据库挂载独立卷,并给 Keycloak 挂载数据卷保存导入文件和本地缓存。下面是一份可直接使用的配置:
services:
postgres:
image: postgres:16-alpine
container_name: keycloak-db
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: keycloak-pass
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak -d keycloak"]
interval: 10s
timeout: 5s
retries: 5
keycloak:
image: keycloak/keycloak:26.1
container_name: keycloak-app
depends_on:
postgres:
condition: service_healthy
environment:
KC_BOOTSTRAP_ADMIN_USERNAME: admin
KC_BOOTSTRAP_ADMIN_PASSWORD: change-me
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak-pass
KC_HOSTNAME: sso.ipipp.com
KC_PROXY_HEADERS: xforwarded
KC_HTTP_ENABLED: "true"
ports:
- "8080:8080"
volumes:
- keycloak-data:/opt/keycloak/data
command: start
volumes:
pgdata:
keycloak-data:
注意 KC_PROXY_HEADERS 设置为 xforwarded 表示信任反向代理传来的 X-Forwarded-For 和 X-Forwarded-Proto 头,否则 Keycloak 无法识别外部 HTTPS,生成的登录地址可能退回 http。数据库健康检查也很重要,depends_on 的 condition: service_healthy 可以避免 Keycloak 在数据库还没准备好时启动导致连接失败。
三、反向代理与 HTTPS 终止必须显式配置
容器内 Keycloak 默认监听 8080 端口且不处理 TLS 证书,生产流量通常先经过 Nginx、Traefik 或云负载均衡器,由它们终止 HTTPS 再转发到容器。如果缺少主机名和代理头配置,用户会在浏览器中看到地址被重写为 http://sso.ipipp.com:8080 或直接跳转到内网 IP,导致登录中断。
Keycloak 提供了 KC_HOSTNAME、KC_HOSTNAME_PORT、KC_HOSTNAME_STRICT 等变量来固定外部访问地址。当反向代理做了 HTTPS 终止时,应设置 KC_PROXY_HEADERS=xforwarded 或 KC_PROXY_HEADERS=forwarded,取决于代理转发头类型。Nginx 的核心配置如下:
server {
listen 443 ssl http2;
server_name sso.ipipp.com;
ssl_certificate /etc/nginx/certs/sso.ipipp.com.crt;
ssl_certificate_key /etc/nginx/certs/sso.ipipp.com.key;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
如果前端还有 CDN 或多层代理,需要确认每一层都正确追加转发头,并且 Keycloak 只信任最外层代理的地址。云环境使用 Kubernetes Ingress 时也可以将 KC_PROXY_HEADERS 设为 forwarded,但前提是 Ingress Controller 会注入标准 Forwarded 头。错误配置往往表现为无限重定向或 403,排查时可以先查看 Keycloak 启动日志中的主机名解析结果。
四、主题、SPI 与 realm 导入的挂载方式
自定义登录页、邮件模板或者第三方用户存储 SPI 在容器化后需要想办法进入镜像内部。有人会选择重新构建镜像,把主题和 JAR 包复制进去,虽然可行但每次升级 Keycloak 版本都要重新打包,维护成本偏高。更轻量的做法是使用卷挂载,把宿主机或配置管理工具管理的目录映射到容器指定路径。
Keycloak 的 Quarkus 发行版默认从 /opt/keycloak/themes 加载主题,从 /opt/keycloak/providers 加载 SPI 提供程序。可以将自定义主题目录挂载到 themes 下的子目录,例如宿主机 /data/keycloak/themes/my-theme 挂载到容器内 /opt/keycloak/themes/my-theme。挂载后需要执行 kc.sh build 让 Quarkus 重新索引提供程序,但不是每次都要构建,主题通常热加载。
realm 配置可以用两种方式导入:启动时通过 --import-realm 参数指定文件,或进入管理控制台手动导入。启动导入适合从 GitOps 或初始化脚本自动创建基础 realm,但要注意只在数据目录为空时执行,否则可能覆盖已有配置。下面命令展示挂载主题和一次性导入 realm:
docker run -d --name keycloak \ -p 8080:8080 \ -v /data/keycloak/themes/my-theme:/opt/keycloak/themes/my-theme \ -v /data/keycloak/import:/opt/keycloak/data/import \ -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \ -e KC_BOOTSTRAP_ADMIN_PASSWORD=change-me \ keycloak/keycloak:26.1 start --import-realm
自定义 SPI 的 JAR 包挂载后,还需要在 keycloak.conf 中声明对应提供者的配置,否则 Keycloak 不会主动加载。容器化部署时更推荐把这些自定义资源纳入版本控制,由 CI 流水线在发布前复制到目标主机,保证每个环境一致。
Keycloak容器化部署Docker Compose修改时间:2026-09-30 10:26:11