Apache ShenYu Docker Compose 部署指南
基于真实构建实测的 Apache ShenYu 2.7.1 Docker Compose 部署指南,覆盖自建镜像 Dockerfile、admin 初始化脚本覆盖、三服务编排与健康检查、服务间 websocket 同步地址修改、divide 上游注册与网关代理验证及常见故障
Apache ShenYu Docker Compose 部署指南
目标:基于真实构建实测的 Apache ShenYu 2.7.1 Docker Compose 部署指南,覆盖自建镜像 Dockerfile、admin 初始化脚本覆盖、三服务编排与健康检查、服务间 websocket 同步地址修改、divide 上游注册与网关代理验证及常见故障。
一、环境信息
| 项目 | 说明 |
|---|---|
| 宿主系统 | Ubuntu 22.04.5 LTS,Docker 27.x(compose v2 插件) |
| 基础镜像 | ub2204-systemd:consul-lab(本地已有 Ubuntu 22.04 镜像) |
| ShenYu 版本 | 2.7.1(admin-bin 与 bootstrap-bin 官方二进制 tar.gz) |
| Java | openjdk-17-jre-headless(镜像内 apt 安装) |
| 服务编排 | shenyu-admin(9095)、shenyu-bootstrap(9195)、shenyu-backend(8500) |
| 堆内存 | admin 与 bootstrap 均以 -server -Xms256m -Xmx256m -Xmn128m 前台运行 |
| 元数据库 | H2 内存库(演示),生产切换 MySQL 或 PostgreSQL |
编排拓扑:shenyu-bootstrap 通过内网域名 shenyu-admin 与 admin 建立 websocket 配置同步;shenyu-backend 是 python3 内置 http.server 模拟的业务后端,供 divide 插件代理演示。
二、镜像选型说明
Apache ShenYu 官方在 Docker Hub 发布 apache/shenyu-admin 与 apache/shenyu-bootstrap 镜像,可直接引用;本文为保证配置与二进制实测环境完全一致,采用自建镜像方式:以本地 Ubuntu 22.04 基础镜像为底,安装 openjdk-17-jre-headless,COPY 官方 tar.gz 并解压,构建时一次性完成配置修改。自建镜像同时承载三个服务(ROLE 环境变量区分 admin 与 bootstrap 角色),镜像名 shenyu-lab:2.7.1,实测构建后镜像约 2.23GB。
三、前置条件
- 宿主机已安装 Docker 与 compose v2 插件(docker compose version 可用)。
- 已获取 apache-shenyu-2.7.1-admin-bin.tar.gz 与 apache-shenyu-2.7.1-bootstrap-bin.tar.gz(可从 dlcdn.apache.org/shenyu/2.7.1/ 下载,或从既有物理部署目录拷贝)。
- 宿主机 9095、9195、8500 端口空闲。
四、部署步骤
4.1 创建目录结构
$ mkdir -p /opt/shenyu-compose && cd /opt/shenyu-compose
$ ls
apache-shenyu-2.7.1-admin-bin.tar.gz apache-shenyu-2.7.1-bootstrap-bin.tar.gz schema.sql Dockerfile docker-compose.yml
schema.sql 为 admin H2 初始化脚本(见 4.3),两个 tar.gz 放在同目录作为构建上下文。
4.2 编写自建镜像的 Dockerfile
FROM ub2204-systemd:consul-lab
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -qq && apt-get install -y openjdk-17-jre-headless curl iproute2 python3 && rm -rf /var/lib/apt/lists/*
COPY apache-shenyu-2.7.1-admin-bin.tar.gz /tmp/apache-shenyu-2.7.1-admin-bin.tar.gz
COPY apache-shenyu-2.7.1-bootstrap-bin.tar.gz /tmp/apache-shenyu-2.7.1-bootstrap-bin.tar.gz
RUN tar -xzf /tmp/apache-shenyu-2.7.1-admin-bin.tar.gz -C /opt && tar -xzf /tmp/apache-shenyu-2.7.1-bootstrap-bin.tar.gz -C /opt && rm -f /tmp/apache-shenyu-*.tar.gz
COPY schema.sql /opt/apache-shenyu-2.7.1-admin-bin/conf/sql-script/h2/schema.sql
RUN mkdir -p /var/www/backend && echo '<h1>Hello from backend on port 8500</h1>' > /var/www/backend/index.html \
&& sed -i 's#ws://localhost:9095/websocket#ws://shenyu-admin:9095/websocket#' /opt/apache-shenyu-2.7.1-bootstrap-bin/conf/application.yml \
&& sed -i 's/password: 123456/password: q1w2e3r4/' /opt/apache-shenyu-2.7.1-bootstrap-bin/conf/application.yml \
&& python3 -c "p='/opt/apache-shenyu-2.7.1-bootstrap-bin/conf/application.yml'; s=open(p).read(); s=s.replace('upstreamCheck:\n enabled: false','upstreamCheck:\n enabled: true'); open(p,'w').write(s)"
EXPOSE 9095 9195
CMD ["/bin/bash", "-c", "if [ \"$ROLE\" = admin ]; then cd /opt/apache-shenyu-2.7.1-admin-bin && exec java -server -Xms256m -Xmx256m -Xmn128m -classpath .:conf:lib/*:ext-lib/* org.apache.shenyu.admin.ShenyuAdminBootstrap; else cd /opt/apache-shenyu-2.7.1-bootstrap-bin && exec java -server -Xms256m -Xmx256m -Xmn128m -classpath .:conf:lib/*:ext-lib/* org.apache.shenyu.bootstrap.ShenyuBootstrapApplication; fi"]
三处构建期修改的含义:
| 修改 | 目的 |
|---|---|
| websocket urls 指向 ws://shenyu-admin:9095/websocket | 网关通过 compose 内网域名订阅 admin 配置同步 |
| bootstrap heartbeat password 改为 q1w2e3r4 | 与 4.3 中 admin 初始化的示例账号密码保持一致 |
| upstreamCheck.enabled 改为 true | 开启网关侧上游健康探测,避免新注册上游因未探测而不可用(实测默认关闭会导致 -119) |
注意 CMD 中必须先 cd 到对应目录再 exec java:classpath 中的 conf、lib 均为相对路径,实测漏掉 cd 会报 Error: Could not find or load main class org.apache.shenyu.admin.ShenyuAdminBootstrap。
4.3 准备 admin 初始化脚本(schema.sql 覆盖)
从官方 jar 中提取 H2 初始化脚本并替换默认密码哈希,使示例账号 admin 的密码为 q1w2e3r4:
# 先从 tar.gz 解出 admin 主包 jar
$ tar -xzf apache-shenyu-2.7.1-admin-bin.tar.gz apache-shenyu-2.7.1-admin-bin/lib/shenyu-admin-2.7.1.jar
# 从 jar 内提取 schema.sql 并替换 admin 默认密码哈希
$ python3 -c "
import zipfile
z=zipfile.ZipFile('apache-shenyu-2.7.1-admin-bin/lib/shenyu-admin-2.7.1.jar')
s=z.read('sql-script/h2/schema.sql').decode()
old='ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413'
new='e553465e3d1ad816a8a8c33176a2ff00fb58f6f55502c89e7593242accc1b0d3c2a2b5fc300a085b5051ecbdd2195b05a53a198ec98d9f75d323cc3c563592f9'
open('schema.sql','w').write(s.replace(old,new))
print('schema.sql written')"
schema.sql written
old 是 sha512("123456") 的默认哈希,new 是 sha512("q1w2e3r4") 的哈希。classpath 中 conf 目录优先于 lib 内 jar 加载,因此 COPY 到 conf/sql-script/h2/ 即可覆盖默认初始化;admin 重启或首次启动均生效。
4.4 编写 docker-compose.yml
services:
shenyu-admin:
build:
context: .
image: shenyu-lab:2.7.1
container_name: shenyu-admin
environment:
ROLE: admin
ports:
- "9095:9095"
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:9095/actuator/health"]
interval: 10s
timeout: 5s
retries: 30
restart: unless-stopped
shenyu-backend:
image: shenyu-lab:2.7.1
container_name: shenyu-backend
entrypoint: ["python3"]
command: ["-m", "http.server", "8500", "--directory", "/var/www/backend"]
ports:
- "8500:8500"
restart: unless-stopped
shenyu-bootstrap:
image: shenyu-lab:2.7.1
container_name: shenyu-bootstrap
environment:
ROLE: bootstrap
depends_on:
shenyu-admin:
condition: service_healthy
shenyu-backend:
condition: service_started
ports:
- "9195:9195"
restart: unless-stopped
说明:admin 健康检查探活 /actuator/health(实测 admin 启动约 12 秒);bootstrap 依赖 admin healthy 后再启动,保证 websocket 一次连接成功;backend 与 bootstrap 共用镜像,backend 仅跑 python3 http.server。
4.5 构建并启动服务
$ docker compose build
# ...(构建输出节选)...
#13 DONE 38.6s
$ docker compose up -d
Network shenyu-compose_default Created
Container shenyu-backend Started
Container shenyu-admin Started
Container shenyu-admin Waiting
Container shenyu-bootstrap Starting
Container shenyu-bootstrap Started
4.6 验证服务
$ docker compose ps
NAME IMAGE COMMAND SERVICE STATUS PORTS
shenyu-admin shenyu-lab:2.7.1 "/bin/bash -c 'if [ "$ROLE" (截断)" shenyu-admin Up About a minute (healthy) 0.0.0.0:9095->9095/tcp, [::]:9095->9095/tcp, 9195/tcp
shenyu-backend shenyu-lab:2.7.1 "python3 -m http.ser (截断)" shenyu-backend Up About a minute 9095/tcp, 0.0.0.0:8500->8500/tcp, [::]:8500->8500/tcp, 9195/tcp
shenyu-bootstrap shenyu-lab:2.7.1 "/bin/bash -c 'if [ "$ROLE" (截断)" shenyu-bootstrap Up About a minute 9095/tcp, 0.0.0.0:9195->9195/tcp, [::]:9195->9195/tcp
$ curl -s http://localhost:9095/actuator/health
{"status":"UP"}
$ curl -s http://localhost:8500/
<h1>Hello from backend on port 8500</h1>
admin 日志确认启动成功(docker logs shenyu-admin):
Tomcat started on port 9095 (http) with context path '/'
Started ShenyuAdminBootstrap in 11.941 seconds (process running for 12.836)
bootstrap 日志确认 websocket 同步建立(docker logs shenyu-bootstrap):
Netty started on port 9195 (http)
Started ShenyuBootstrapApplication in 7.15 seconds (process running for 8.632)
4.7 注册 divide 上游并验证网关代理
登录并获取 token,注册选择器、规则与上游(完整 API 说明见同专栏《Apache ShenYu 常用 CLI 命令与工具详解》):
$ TOKEN=$(curl -s "http://localhost:9095/platform/login?userName=admin&password=q1w2e3r4" | python3 -c "import json,sys; print(json.load(sys.stdin)['data']['token'])")
$ SELID=$(curl -s -X POST http://localhost:9095/selector -H "X-Access-Token: $TOKEN" -H "Content-Type: application/json" -d '{
"pluginId": "5", "name": "http-backend", "matchMode": 0, "type": 0, "sort": 1,
"enabled": true, "loged": true, "continued": true, "matchRestful": false,
"handle": "[]", "selectorConditions": [],
"namespaceId": "649330b6-c2d7-4edc-be8e-8a54df9eb385" }' | python3 -c "import json,sys; print(json.load(sys.stdin)['data'])")
$ echo $SELID
2109481475587895296
$ curl -s -X POST http://localhost:9095/rule -H "X-Access-Token: $TOKEN" -H "Content-Type: application/json" -d '{
"selectorId": "2109481475587895296", "name": "index-html", "matchMode": 0, "sort": 1,
"enabled": true, "loged": true, "matchRestful": false,
"handle": "{\"loadBalance\":\"random\",\"retry\":0,\"timeout\":3000}",
"ruleConditions": [{"paramType":"uri","operator":"=","paramName":"/","paramValue":"/index.html"}],
"namespaceId": "649330b6-c2d7-4edc-be8e-8a54df9eb385" }'
{"code":200,"message":"create success","data":1}
关键差异:compose 内上游地址必须用服务名 shenyu-backend 而非 localhost(网关进程与后端分属不同网络命名空间):
$ curl -s -X POST http://localhost:9095/proxy-selector/binding -H "X-Access-Token: $TOKEN" -H "Content-Type: application/json" -d '{
"selectorId": "2109481475587895296", "name": "http-backend", "pluginName": "divide",
"type": "local", "forwardPort": 8500, "listenerNode": "", "handler": "{}", "props": "{}",
"discovery": {"discoveryType": "local", "serverList": "", "props": "{}", "name": "http-backend"},
"discoveryUpstreams": [{"protocol": "http://", "url": "shenyu-backend:8500", "status": 1, "weight": 50, "props": "{}"}],
"namespaceId": "649330b6-c2d7-4edc-be8e-8a54df9eb385" }'
{"code":200,"message":"create success","data":null}
等待健康探测通过(首次探测间隔 5000 毫秒),验证代理:
$ curl -s http://localhost:9195/index.html
<h1>Hello from backend on port 8500</h1>
五、数据持久化说明
H2 为内存库,shenyu-admin 重建后选择器、规则、上游等配置全部清空,网关会返回 -107 错误,需重新注册。生产环境两种持久化路径:
- 切换外部数据库:构建时将 admin 的 spring.profiles.active 改为 mysql 或 pg,并在对应 application-*.yml 中填写数据源,compose 中通过 environment 覆盖 SPRING_PROFILES_ACTIVE。
- compose 编排 MySQL 服务并在 depends_on 中等待其健康后启动 admin。
演示环境如需保留配置,不要对 shenyu-admin 执行 docker compose restart 以外的重建操作,重启进程即可(H2 内存库随进程存活)。
六、常用环境变量表
| 变量 | 作用 | 示例值 |
|---|---|---|
| ROLE | 区分容器角色:admin 启动管理端,其余启动网关 | admin / bootstrap |
| SPRING_PROFILES_ACTIVE | 覆盖 admin 存储类型 | h2 / mysql / pg |
| SHENYU_SYNC_WEBSOCKET_URLS | 覆盖网关配置同步地址(spring relaxed binding) | ws://shenyu-admin:9095/websocket |
| SERVER_PORT | 覆盖进程监听端口 | 9095 / 9195 |
| TZ | 时区 | Asia/Shanghai |
其中 ROLE 由本文 Dockerfile 的 CMD 消费;其余为 spring boot 通用环境变量覆盖机制,均可在 compose 的 environment 段直接追加。
七、常用配置参数说明(Dockerfile 构建期修改)
| 参数 | 位置 | 默认值 | 实测说明 |
|---|---|---|---|
| shenyu.sync.websocket.urls | bootstrap application.yml | ws://localhost:9095/websocket | 指向 compose 服务名 shenyu-admin |
| shenyu.heartbeat.props.password | bootstrap application.yml | 123456 | 与 admin 示例账号一致,改为 q1w2e3r4 |
| shenyu.upstreamCheck.enabled | bootstrap application.yml | false | 实测必须改 true,否则新上游永远不进健康列表 |
| spring.profiles.active | admin application.yml | h2 | 生产切 mysql 或 pg |
| shenyu.database.init_enable | admin application-h2.yml | true | 关闭后不再执行 schema 初始化 |
| shenyu.jwt.expired-seconds | admin application.yml | 86400000 | 登录 token 有效期 24 小时 |
八、等价 docker run 运行方式
不使用 compose 时,可用等价 docker run 三步复现(先建网络):
$ docker network create shenyu-net
$ docker run -d --name shenyu-admin --network shenyu-net -p 9095:9095 -e ROLE=admin shenyu-lab:2.7.1
$ docker run -d --name shenyu-backend --network shenyu-net -p 8500:8500 --entrypoint python3 shenyu-lab:2.7.1 -m http.server 8500 --directory /var/www/backend
$ docker run -d --name shenyu-bootstrap --network shenyu-net -p 9195:9195 -e ROLE=bootstrap shenyu-lab:2.7.1
验证方式与 4.6、4.7 相同。清理:
$ docker rm -f shenyu-admin shenyu-backend shenyu-bootstrap && docker network rm shenyu-net
九、常用运维命令
$ docker compose ps # 服务状态与健康检查结果
$ docker compose logs -f shenyu-admin # 跟踪管理端日志
$ docker compose logs -f shenyu-bootstrap
$ docker compose restart shenyu-bootstrap
$ docker compose down # 停止并移除服务与网络
实测 docker compose down 回显:
Network shenyu-compose_default Removing
Network shenyu-compose_default Removed
十、常见问题(FAQ)
10.1 启动即退出,日志报 Could not find or load main class
Error: Could not find or load main class org.apache.shenyu.admin.ShenyuAdminBootstrap
Caused by: java.lang.ClassNotFoundException: org.apache.shenyu.admin.ShenyuAdminBootstrap
CMD 未 cd 到发行目录,classpath 中 conf、lib 相对路径失效。在 CMD 的 bash -c 中加入 cd /opt/apache-shenyu-2.7.1-admin-bin(或对应 bootstrap 目录)后重建。
10.2 网关返回 -119 Can not find healthy upstream url
上游已通过 websocket 同步(bootstrap 日志可见 DISCOVER_UPSTREAM、pluginName divide 事件),但健康探测未开启。实测根因:bootstrap 默认 shenyu.upstreamCheck.enabled 为 false,而上游 props 默认 healthCheckEnabled 为 true,未探测的上游不进健康列表。在 Dockerfile 构建期将该项改为 true(注意不要用全局 sed 替换 enabled: false,实测会误改 register.enabled 等同名字段,应按 upstreamCheck 上下文精确替换)。
10.3 bootstrap 起来后 admin 配置未同步
检查三点:bootstrap 日志是否出现 WebsocketSyncDataService 与 admin 连接成功记录;websocket urls 是否已在构建期改为 ws://shenyu-admin:9095/websocket;admin 是否 healthy(compose depends_on 仅保证启动顺序,健康检查失败时 bootstrap 不会被拉起,docker compose ps 查看 STATUS)。
10.4 网关返回 -107 Can not find selector
shenyu-admin 被重建后 H2 内存库清空所致。重新执行 4.7 的注册流程即可;生产环境按第五章切换外部数据库。
10.5 上游绑定后仍代理失败,url 写 localhost 不通
网关与后端分属不同服务,localhost 指向网关自身。上游 url 必须写 compose 服务名 shenyu-backend:8500 或宿主机可达地址。
十一、参考链接
- ShenYu 官方文档(含 Docker 部署章节):https://shenyu.apache.org/docs/index/
- ShenYu 2.7.1 发行包:https://dlcdn.apache.org/shenyu/2.7.1/
- 源码仓库:https://github.com/apache/shenyu
- compose 文件参考:https://github.com/apache/shenyu/tree/v2.7.1/shenyu-dist