Apache Syncope 4.1.3 Docker Compose 部署指南

使用官方镜像与 Docker Compose 部署 Apache Syncope 4.1.3 的完整指南,覆盖环境变量清单、编排文件编写、栈启动验证、安全密钥强制配置、数据持久化与常见故障排查,全部步骤与回显均来自真实环境实测。

Apache SyncopeApache Syncope2026/10/12

Apache Syncope 4.1.3 Docker Compose 部署指南

一、架构说明

使用官方容器镜像编排部署 Apache Syncope 4.1.3,包含四个服务:

服务镜像实测镜像大小容器内端口宿主映射(实测)
dbpostgres:16-alpine420 MB5432不对外
syncope(Core)apache/syncope:4.1.31.64 GB808018080
syncope-console(管理控制台)apache/syncope-console:4.1.3936 MB808028080
syncope-enduser(用户自助界面)apache/syncope-enduser:4.1.3839 MB808038080

组件协作方式(实测确认):数据库使用外部 PostgreSQL(数据持久化,容器重启不丢数据,这是与 standalone 发行版内嵌临时库的关键差异);各组件通过 Keymaster 机制互相发现,本方案中 Keymaster 由 Core 自身的 REST 端点(/syncope/rest/keymaster)提供,无需额外组件。

官方容器镜像运行环境为 Java 25(实测容器内 Java 25.0.4),无需宿主机安装 JDK。

二、前置条件

宿主机需安装 Docker(实测 Docker 29.8.0)与 Compose 插件(实测 Compose v5.5.1):

docker version --format 'Client {{.Client.Version}} / Server {{.Server.Version}}'
docker compose version
Client 29.8.0 / Server 29.8.0
Docker Compose version v5.5.1

确认端口未被占用:18080、28080、38080。

ss -ltnp | grep -E ':18080|:28080|:38080'

无输出即端口可用。

三、获取官方镜像

逐一拉取(实测回显为镜像 ID 行):

docker pull apache/syncope:4.1.3
4.1.3: Pulling from apache/syncope
Digest: sha256:e6a5326d5e3a4a2b93d76c52a334797d3fa0ba4d22e6d18b16d68a5b54a1e0db
Status: Downloaded newer image for apache/syncope:4.1.3
docker.io/apache/syncope:4.1.3
docker pull apache/syncope-console:4.1.3
docker pull apache/syncope-enduser:4.1.3
docker pull postgres:16-alpine

官方还提供 apache/syncope-wa:4.1.3(认证中心)与 apache/syncope-sra:4.1.3(反向代理网关),本指南的基础架构不涉及;需要 SSO 认证中心时可按同一模式加入编排。

四、部署步骤

4.1 创建部署目录与环境变量文件

mkdir -p /opt/syncope
cd /opt/syncope

创建 .env 文件(Compose 变量来源,实测必须给 KEYMASTER_USERNAME/KEYMASTER_PASSWORD 非空值,否则 Core 启动崩溃,见 7.1):

cat > .env <<'EOF'
SYNCOPE_VERSION=4.1.3
KEYMASTER_USERNAME=anonymous
KEYMASTER_PASSWORD=anonymousKey
ANONYMOUS_USER=anonymous
ANONYMOUS_KEY=anonymousKey
EOF

4.2 编写 docker-compose.yml

创建 docker-compose.yml(基于官方 docker-compose-postgresql.yml 模板,加入实测必需的安全密钥环境变量与堆限制):

services:
  db:
    image: postgres:16-alpine
    restart: always
    environment:
      POSTGRES_DB: syncope
      POSTGRES_USER: syncope
      POSTGRES_PASSWORD: syncope

  syncope:
    depends_on:
      - db
    image: apache/syncope:4.1.3
    ports:
      - "18080:8080"
    restart: always
    environment:
      SPRING_PROFILES_ACTIVE: docker,postgresql,saml2
      DB_URL: jdbc:postgresql://db:5432/syncope?stringtype=unspecified
      DB_USER: syncope
      DB_PASSWORD: syncope
      DB_POOL_MAX: 20
      DB_POOL_MIN: 5
      OPENJPA_REMOTE_COMMIT: sjvm
      KEYMASTER_ADDRESS: http://localhost:8080/syncope/rest/keymaster
      KEYMASTER_USERNAME: ${KEYMASTER_USERNAME:-}
      KEYMASTER_PASSWORD: ${KEYMASTER_PASSWORD:-}
      SERVICE_DISCOVERY_ADDRESS: http://syncope:8080/syncope/rest/
      ANONYMOUS_USER: ${ANONYMOUS_USER}
      ANONYMOUS_KEY: ${ANONYMOUS_KEY}
      SECURITY_ADMINPASSWORD: e553465e3d1ad816a8a8c33176a2ff00fb58f6f55502c89e7593242accc1b0d3c2a2b5fc300a085b5051ecbdd2195b05a53a198ec98d9f75d323cc3c563592f9
      SECURITY_ADMINPASSWORDALGORITHM: SHA512
      SECURITY_AESSECRETKEY: Qf7kP2mX9vLw4nR8tY6uJ3hB5dC1aZ0e
      SECURITY_JWSKEY: Xk4tP8wR2mY6uL3vJ9qF5hD1aZ7cN0bS4gE8iK2oT6yUQzA5rW7eM1nV9xC3fG8Hd
      JAVA_OPTS: "-Xms256m -Xmx512m"

  syncope-console:
    depends_on:
      - syncope
    image: apache/syncope-console:4.1.3
    ports:
      - "28080:8080"
    restart: always
    environment:
      SPRING_PROFILES_ACTIVE: docker
      KEYMASTER_ADDRESS: http://syncope:8080/syncope/rest/keymaster
      KEYMASTER_USERNAME: ${KEYMASTER_USERNAME:-}
      KEYMASTER_PASSWORD: ${KEYMASTER_PASSWORD:-}
      SERVICE_DISCOVERY_ADDRESS: http://syncope-console:8080/syncope-console/
      ANONYMOUS_USER: ${ANONYMOUS_USER}
      ANONYMOUS_KEY: ${ANONYMOUS_KEY}

  syncope-enduser:
    depends_on:
      - syncope
    image: apache/syncope-enduser:4.1.3
    ports:
      - "38080:8080"
    restart: always
    environment:
      SPRING_PROFILES_ACTIVE: docker
      KEYMASTER_ADDRESS: http://syncope:8080/syncope/rest/keymaster
      KEYMASTER_USERNAME: ${KEYMASTER_USERNAME:-}
      KEYMASTER_PASSWORD: ${KEYMASTER_PASSWORD:-}
      SERVICE_DISCOVERY_ADDRESS: http://syncope-enduser:8080/syncope-enduser/
      ANONYMOUS_USER: ${ANONYMOUS_USER}
      ANONYMOUS_KEY: ${ANONYMOUS_KEY}

说明:

  1. SECURITY_ADMINPASSWORD 的值为 q1w2e3r4 的 SHA512 十六进制摘要(生成方法见 7.2),容器默认密码为 password 且被强制检测,不修改则 REST 全部返回 500。
  2. SECURITY_AESSECRETKEY 固定 32 字符(AES-256);SECURITY_JWSKEY 在 HS512 算法下必须不少于 64 字符,否则启动失败(见 7.3、7.4)。生产环境请替换为自己生成的随机值。
  3. JAVA_OPTS 限制 Core 的 JVM 堆在 512 MB 内;四个服务相互独立,Console/Enduser 如需限制可各自添加。

4.3 校验并启动

校验编排文件语法:

docker compose config --quiet && echo CONFIG_OK
CONFIG_OK

启动全部服务:

docker compose up -d
[+] Running 5/5
 ✔ Network syncope_default     Created
 ✔ Container syncope-db-1      Started
 ✔ Container syncope-syncope-1 Started
 ✔ Container syncope-syncope-console-1 Started
 ✔ Container syncope-syncope-enduser-1 Started

查看运行状态:

docker compose ps --format 'table {{.Name}}\t{{.Image}}\t{{.Status}}'
NAME                        IMAGE                          STATUS
syncope-db-1                postgres:16-alpine             Up 20 seconds
syncope-syncope-1           apache/syncope:4.1.3           Up 20 seconds
syncope-syncope-console-1   apache/syncope-console:4.1.3   Up 20 seconds
syncope-syncope-enduser-1   apache/syncope-enduser:4.1.3   Up 20 seconds

4.4 等待 Core 就绪

Core 完全启动需 30-90 秒(首次启动含建表与数据初始化)。观察日志直到出现 Started:

docker compose logs syncope 2>&1 | grep 'Started SyncopeCoreApplication'
syncope-1  | 2026-10-12 02:26:08.364  INFO [       main] org.apache.syncope.core.starter.SyncopeCoreApplication       : Started SyncopeCoreApplication in 26.605 seconds (process running for 28.527)

注意:Console 在 Core 完全启动(服务注册完成)前访问会短暂返回 500(No registered services for type CORE),Core 就绪后自愈,属启动时序现象(见 7.5)。

五、部署验证

5.1 REST 接口验证

使用 admin 与新密码调用自助接口(实测回显):

curl -s -u admin:q1w2e3r4 http://localhost:18080/syncope/rest/users/self | grep -o '"username":"[^"]*"'
"username":"admin"

5.2 界面可达性验证

curl -s -o /dev/null -w 'console=%{http_code}\n' http://localhost:28080/syncope-console/
curl -s -o /dev/null -w 'enduser=%{http_code}\n' http://localhost:38080/syncope-enduser/
console=302
enduser=302

302 为跳转登录页,表示服务正常。浏览器访问 http://<服务器IP>:28080/syncope-console/,以 admin/q1w2e3r4 登录管理控制台。

5.3 数据持久化验证(与 standalone 的关键差异)

创建测试用户(实测返回 201):

curl -s -X POST -u admin:q1w2e3r4 -H 'Content-Type: application/json' \
  -d '{"_class":"org.apache.syncope.common.lib.request.UserCR","username":"appuser01","password":"Q1w2E3r4!@#5","realm":"/","plainAttrs":[{"schema":"fullname","values":["App User 01"]},{"schema":"surname","values":["User"]},{"schema":"userId","values":["appuser01@syncope.apache.org"]}]}' \
  'http://localhost:18080/syncope/rest/users?storePasswordOnSyncope=true' -w '\ncode=%{http_code}\n' -o /dev/null
code=201

重启 Core 容器后再查询(实测用户仍在):

docker compose restart syncope
curl -s -u admin:q1w2e3r4 'http://localhost:18080/syncope/rest/users?fiql=username%3D%3Dappuser01' | grep -o '"username":"appuser01"'
"username":"appuser01"

数据保存在独立 PostgreSQL 服务中,Core 容器重启不丢失,适合承载长期数据。

六、环境变量与镜像内配置详解

6.1 Core(apache/syncope)环境变量

环境变量示例值说明
SPRING_PROFILES_ACTIVEdocker,postgresql,saml2必须包含 docker 与对应数据库 profile,saml2 可选
DB_URLjdbc:postgresql://db:5432/syncope?stringtype=unspecified数据库连接串;stringtype=unspecified 为 PostgreSQL 必备
DB_USER / DB_PASSWORDsyncope / syncope数据库账号,对应 db 服务的初始化值
DB_POOL_MAX / DB_POOL_MIN20 / 5连接池上下限
OPENJPA_REMOTE_COMMITsjvmOpenJPA 远程提交提供者,单实例用 sjvm
KEYMASTER_ADDRESShttp://localhost:8080/syncope/rest/keymasterCore 用自身内置 Keymaster(localhost 为容器内自身);也可指向 zookeeper:2181
KEYMASTER_USERNAME / KEYMASTER_PASSWORDanonymous / anonymousKey访问 Keymaster 的凭据,必须非空
SERVICE_DISCOVERY_ADDRESShttp://syncope:8080/syncope/rest/对外登记的服务地址(服务名:8080)
ANONYMOUS_USER / ANONYMOUS_KEYanonymous / anonymousKey匿名内部调用账号,生产环境必须修改
SECURITY_ADMINPASSWORD(SHA512 摘要)覆盖默认 admin 密码摘要,强制要求
SECURITY_ADMINPASSWORDALGORITHMSHA512与上一项配套的算法
SECURITY_AESSECRETKEY32 字符随机串AES 密钥,16/24/32 字符对应 AES-128/192/256
SECURITY_JWSKEY不少于 64 字符随机串JWT 签名密钥(HS512 算法要求 ≥64 字符)
JAVA_OPTS"-Xms256m -Xmx512m"JVM 参数,容器入口脚本原样传给 java

SECURITY_* 环境变量生效机制:镜像内配置文件使用 Spring Boot 宽松绑定,security.adminPassword 等属性可直接由对应大写环境变量覆盖(实测验证有效)。

Console 与 Enduser 的环境变量结构相同(KEYMASTER_、SERVICE_DISCOVERY_ADDRESS、ANONYMOUS_),无数据库相关项。

6.2 镜像内部结构(排障用)

Core 镜像内目录(实测):

/opt/syncope/bin/startup.sh    # 入口脚本:exec java $JAVA_OPTS -jar /opt/syncope/lib/syncope.jar
/opt/syncope/lib/syncope.jar   # Spring Boot 可执行包
/opt/syncope/conf/core-docker.properties      # 环境变量映射(keymaster.*、security.anonymous* 等)
/opt/syncope/conf/core-postgresql.properties  # 数据库参数映射(persistence.domain[0].* ← DB_*)
/opt/syncope/conf/log4j2.xml
/opt/syncope/bundles/           # ConnId 连接器包
/opt/syncope/log/               # 容器内日志目录

进入容器核对 JVM 参数的实测方法:

docker exec syncope-syncope-1 sh -c 'tr "\0" " " < /proc/1/cmdline'
java -Xms256m -Xmx512m -jar /opt/syncope/lib/syncope.jar

七、常见启动失败与解决方法(全部实测复现)

7.1 Keymaster 凭据为空导致崩溃

日志特征:

WARN org.springframework.boot.SpringApplication : Exception encountered during context initialization - cancelling refresh attempt: java.lang.IllegalArgumentException: Cannot pass null or empty values to constructor
ERROR org.springframework.boot.SpringApplication : Application run failed

原因:官方 postgresql 模板的 KEYMASTER_USERNAME/KEYMASTER_PASSWORD 引用环境变量但无默认值,.env 缺失时为空。解决:在 .env 中写入 anonymous/anonymousKey(或自定义强凭据并同步修改 ANONYMOUS_*)。

7.2 默认管理员密码被强制拒绝

日志特征:

ERROR org.apache.catalina.core.StandardWrapperValve : Servlet.service() for servlet [cxfServletRegistration] threw exception
java.lang.IllegalStateException: The default adminPassword property is being used. This must be changed to avoid a security breach!

原因:容器内 security.adminPassword 仍为官方默认值。解决:生成新密码摘要并通过 SECURITY_ADMINPASSWORD/SECURITY_ADMINPASSWORDALGORITHM 环境变量传入。摘要生成方法(在任意装有 JDK 的机器上,将下述内容保存为 Sha512.java 并编译执行):

import java.security.MessageDigest;
import java.util.HexFormat;
public class Sha512 {
  public static void main(String[] a) throws Exception {
    System.out.println(HexFormat.of().formatHex(
        MessageDigest.getInstance("SHA-512").digest(a[0].getBytes())));
  }
}
java Sha512.java q1w2e3r4
e553465e3d1ad816a8a8c33176a2ff00fb58f6f55502c89e7593242accc1b0d3c2a2b5fc300a085b5051ecbdd2195b05a53a198ec98d9f75d323cc3c563592f9

7.3 默认 AES 密钥被强制拒绝

日志特征:

java.lang.IllegalStateException: The default AES key property is being used. This must be changed to avoid a security breach!

解决:设置 SECURITY_AESSECRETKEY 环境变量,长度 16/24/32 字符。

7.4 JWS 密钥长度不足导致启动失败

日志特征:

Failed to instantiate [org.apache.syncope.core.spring.security.DefaultCredentialChecker]:
Factory method 'credentialChecker' threw exception with message: The configured key for HS512 must be at least 64 characters

解决:SECURITY_JWSKEY 使用 64 字符以上的随机串(实测 66 字符通过)。

7.5 Console 短暂 500(No registered services for type CORE)

日志特征(Console 容器):

Caused by: org.apache.syncope.common.keymaster.client.api.KeymasterException:
jakarta.ws.rs.NotFoundException: {"status":404,"type":"NotFound","elements":["NotFoundException: No registered services for type CORE"]}

原因:Console 启动早于 Core 完成向 Keymaster 注册(Core 的注册发生在 Started SyncopeCoreApplication 之后)。解决:等待 Core 日志出现 Started 且再过数秒后访问即可,无需处理;编排层面可增大 depends_on 之外的重试容忍(Compose 的 depends_on 不等待应用就绪,属正常现象)。

八、日常运维命令

查看实时日志:

docker compose logs -f syncope

重启单个服务:

docker compose restart syncope

修改 docker-compose.yml 或 .env 后应用变更(自动重建受影响容器):

docker compose up -d

查看各服务状态:

docker compose ps --format 'table {{.Name}}\t{{.Image}}\t{{.Status}}'

升级版本流程:修改 .env 中 SYNCOPE_VERSION 与各 image 标签为新的 4.1.x 补丁版本,执行 docker pull 拉取新镜像后 docker compose up -d 重建;数据库结构由 Core 启动时自动校验,跨大版本升级需按官方迁移文档另行处理。

九、卸载方式

停止并移除全部容器与网络(实测回显):

docker compose down
 Container syncope-syncope-enduser-1 Stopped
 Container syncope-db-1 Stopping
 Container syncope-db-1 Stopped
 Container syncope-db-1 Removing
 Container syncope-db-1 Removed
 Network syncope_default Removing
 Network syncope_default Removed

如需连同数据一并清除,在 down 时加 -v 参数移除数据卷;再删除部署目录与本地镜像:

rm -rf /opt/syncope
docker rmi apache/syncope:4.1.3 apache/syncope-console:4.1.3 apache/syncope-enduser:4.1.3 postgres:16-alpine

十、常见问题

Q1:与 standalone 发行版部署怎么选?

standalone 解压即用、内置嵌入式数据库,适合快速验证,但数据重启即重置;Compose 部署使用外部 PostgreSQL,数据持久,适合长期运行与生产起步。生产环境还建议为 db 服务配置卷挂载持久化数据(本指南模板默认卷由 Compose 管理)。

Q2:REST 访问返回 500 且日志提示 default adminPassword property is being used?

容器安全策略强制修改三类默认凭据:adminPassword、AES 密钥、(部分场景)JWS 密钥。按第七节 7.2/7.3/7.4 的方法通过环境变量覆盖后重建容器。

Q3:修改了 SECURITY_ 环境变量后不生效?*

docker compose up -d 检测到环境变量变化会自动重建容器;若使用 docker compose restart 则不会重建,需执行 up -d。确认容器为重建而非重启:docker compose ps 查看 Created/Up 时间。

Q4:端口可以改成 80/443 吗?

可以。ports 映射左侧宿主端口可自由调整(如 "80:8080"),组件间发现地址 SERVICE_DISCOVERY_ADDRESS 使用容器网络内部端口,不受宿主映射影响。

Q5:如何确认 Core 使用的 JVM 堆限制?

执行 docker exec syncope-syncope-1 sh -c 'tr "\0" " " < /proc/1/cmdline',实测回显 java -Xms256m -Xmx512m -jar /opt/syncope/lib/syncope.jar 即生效值。

十一、参考链接

  1. Apache Syncope Getting Started(Docker 章节):https://syncope.apache.org/docs/getting-started.html
  2. 官方 compose 模板(随源码包发布):https://downloads.apache.org/syncope/
  3. Docker Hub 官方镜像页:https://hub.docker.com/r/apache/syncope
  4. Apache Syncope Reference Guide:https://syncope.apache.org/docs/reference-guide.html