如何用 Docker 容器化部署 Keycloak 并完成生产级配置?

来源:程序开发作者:香港程序员头衔:程序员
导读:本期聚焦于香港程序员创作的《如何用 Docker 容器化部署 Keycloak 并完成生产级配置?》,敬请观看详情。只用 docker run 启动 Keycloak 容器,测试环境或许够用,但一旦涉及重启、升级或多人协作,内嵌数据库丢失 realm 配置、管理员账号重置、主题无法定制等问题就会集中爆发。生产级容器化部署的关键不在于能把镜像跑起来,而在于把状态外置、配置显式化、入口统一化。外置 PostgreSQL 或 MySQL 替代默认 H2 数据库,用卷或对象存储保留主题和自定义 SPI,设置正确的 KC_HOSTNAME 与代理头避免登录跳回容器内部地址,再通过 Docker Compose 或 Kubernetes 管理依赖顺序和健康检查。本文从镜像启动模式、数据库持久化、反向代理到主题挂载,给出可以直接落地的配置示例,说明哪些环境变量容易被忽略,以及为什么它们决定 Keycloak 在容器中的稳定性和可维护性。对于已经使用 Docker 的团队,这些配置可以平滑迁移到 Kubernetes,核心思路不变。

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

如何用 Docker 容器化部署 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

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0930/63785.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。