Docker Compose 部署
本小节,讲解如何使用项目自带的 script/docker-compose (opens new window) 目录,通过 Docker Compose 将前端 + 后端 + MySQL + Redis + Nacos 一起部署到一台 Linux 服务器上。
后端采用最小化的部署,包括 gateway-server 网关、system-server 服务、infra-server 服务。整体链路如下:
浏览器 ──WEB_PORT(默认 8080)──> web 容器(Nginx:前端静态文件 + 反向代理)
│ /admin-api/、/app-api/、/infra/ws
↓
gateway 容器(48080)
│ 从 Nacos 获取服务实例(容器 IP),负载均衡转发
↓
system-server 容器(48081) <──Feign──> infra-server 容器(48082)
│ │
└──> mysql 容器 + redis 容器 <┘
以上 3 个后端服务,都注册到 nacos 容器(8848 / 9848)
注意:服务器的 IP 地址。
- 外网 IP:139.9.196.247
下属所有涉及到 IP 的配置,需要替换成你自己的。
友情提示:
- 本文的部署过程,本质和 《Docker 部署》 一样,只是把多条
docker run命令收敛到仓库的script/docker-compose/docker-compose.yml中,容器之间通过 Compose 服务名 互相访问。 - 本文是入门级的单机部署示例,用于体验与测试,不涉及高可用。建议服务器可用内存不低于 4G。
- 这里的“可用内存”,指 Docker 实际还能使用的内存,而不是宿主机的总内存。使用 Docker Desktop 时,请确认它分配的内存上限,并扣除已有容器的占用,否则可能因为内存不足(OOM)导致服务启动失败。
- 完整的变量说明,以同目录的
README.md(opens new window) 为准,本文主要讲解步骤与注意点。
# 1. 环境准备
# 1.1 安装 Docker 与 Docker Compose
① 参考 《Docker 部署》 的「1.1 安装 Docker」小节,完成 Docker 的安装。
② 执行如下命令,安装 Docker Compose 插件,并确认版本不低于 v2.20.2(docker-compose.yml 使用了 depends_on.required、COMPOSE_PROFILES 等特性):
dnf install -y docker-compose-plugin
docker compose version
友情提示:
本文使用的是 Compose V2 的 docker compose(中间是空格)命令,而不是老的 docker-compose 命令。如果拉取镜像较慢,可参考 《Docker 部署》 中的镜像加速说明。
# 1.2 确认后端分支与 JDK 版本
后端项目有 3 个分支,JDK 版本、运行镜像、Redis 配置前缀、Nacos 客户端版本都不同,必须一一对应:
| 后端分支 | JDK | Spring Boot | 各服务 Dockerfile 的运行镜像 | Redis 环境变量 | Nacos 客户端 |
|---|---|---|---|---|---|
master | 8 | 2.7 | eclipse-temurin:8-jre | SPRING_REDIS_* | 2.x |
master-jdk17 | 17 / 21 | 3.5 | eclipse-temurin:17-jre | SPRING_DATA_REDIS_* | 3.x |
master-jdk25 | 25 | 4.x | eclipse-temurin:25-jre | SPRING_DATA_REDIS_* | 3.x |
注意:目前只有 `master-jdk17` 分支提供 `script/docker-compose` 目录!
master、master-jdk25 分支尚未同步。如需在这两个分支使用,可以复制 master-jdk17 的目录自行适配,主要替换三处:
- ① 运行镜像:使用对应分支各服务自带的
Dockerfile,它的FROM已经与分支的 JDK 匹配。 - ② Redis 环境变量:
master(JDK 8)分支需要把docker-compose.yml中的SPRING_DATA_REDIS_*改成SPRING_REDIS_*,否则 Redis 配置不会生效。 - ③ Nacos 镜像:按该分支
nacos-client的版本选择,可以执行unzip -l yudao-gateway.jar | grep nacos-client查看。
另外,JDK 25 编译的 Jar 包放到 8-jre 镜像中运行,会报 UnsupportedClassVersionError 错误,不要混用。
# 1.3 了解部署目录
docker-compose.yml 中的构建上下文、SQL 文件都使用 ../../ 相对路径,指向源码根目录下的文件。所以服务器上需要有如下目录结构,不能只上传 script/docker-compose 子目录:
yudao-cloud # 源码根目录
├── yudao-gateway
│ ├── Dockerfile # 构建上下文 ../../yudao-gateway
│ └── target/yudao-gateway.jar
├── yudao-module-system/yudao-module-system-server
│ ├── Dockerfile
│ └── target/yudao-module-system-server.jar
├── yudao-module-infra/yudao-module-infra-server
│ ├── Dockerfile
│ └── target/yudao-module-infra-server.jar
├── sql/mysql
│ └── ruoyi-vue-pro.sql # 首次启动时导入
└── script/docker-compose # 部署目录,docker compose 命令都在这里执行
├── docker-compose.yml
├── .env.example # 复制为 .env 后修改
├── nginx/default.conf # Nginx 配置
└── web/dist # 需自行放入前端打包产物
友情提示:
推荐直接在服务器上 git clone 源码,并在服务器上打包后端。如果在本机打包后上传,需要保持上述相对路径不变。
docker-compose.yml 中包含如下 7 个服务:
| 服务 | 镜像 | 说明 |
|---|---|---|
mysql | mysql:8.4 | 首次启动导入 ruoyi-vue-pro.sql,数据卷 yudao-cloud_mysql-data |
redis | redis:7.4-alpine | 开启密码与 AOF,数据卷 yudao-cloud_redis-data |
nacos | nacos/nacos-server:v3.0.3 | 内置 Nacos(可选,profile nacos),单机 + 嵌入式存储,数据卷 yudao-cloud_nacos-data |
gateway | yudao-gateway:${IMAGE_TAG} | 端口 48080,Nacos 服务名 gateway-server。只依赖 Nacos,不连接 MySQL、Redis |
system-server | yudao-module-system-server:${IMAGE_TAG} | 端口 48081,Nacos 服务名 system-server |
infra-server | yudao-module-infra-server:${IMAGE_TAG} | 端口 48082,Nacos 服务名 infra-server |
web | nginx:1.28-alpine | 前端 + 反向代理到 gateway,对宿主机开放 ${WEB_PORT},默认 8080 |
MySQL、Redis、Nacos、网关默认不映射到宿主机,不会与本机已有的 3306、6379、8848、48080 冲突。需要时,可以取消 docker-compose.yml 中对应 ports 的注释(只绑定 127.0.0.1)。
# 2. 打包
# 2.1 打包后端
在源码根目录下,执行如下命令,构建出 3 个服务各自 target 目录下的 Jar 包:
mvn clean package -pl yudao-gateway,yudao-module-system/yudao-module-system-server,yudao-module-infra/yudao-module-infra-server -am -Dmaven.test.skip=true
友情提示:
后端不需要修改 application-dev.yaml 中的 Nacos、MySQL、Redis 地址,docker-compose.yml 会通过环境变量覆盖它们。新版本的模块名是 yudao-module-xxx-server,不再是老文档中的 yudao-module-xxx-biz。
# 2.2 打包前端
前端的打包方式,和 《Linux 部署》 的「3. 部署前端」小节一致。不同的是,前端和后端通过同一个 Nginx 同源访问,所以“后端地址”要填写 Nginx 的访问地址(例如说 http://139.9.196.247:8080),不要填写 gateway、48080 等容器名或后端端口:
| 前端项目 | 配置文件 | 修改的配置项 | 打包命令 => 产物目录 |
|---|---|---|---|
yudao-ui-admin-vue3 | .env.prod | VITE_BASE_URL='http://139.9.196.247:8080',VITE_API_URL=/admin-api 保持不变 | pnpm build:prod => dist-prod |
yudao-ui-admin-vben | apps/web-antd/.env.production | VITE_BASE_URL=http://139.9.196.247:8080,VITE_GLOB_API_URL=/admin-api | pnpm build:antd => apps/web-antd/dist |
- 前端的
VITE_APP_CAPTCHA_ENABLE,要与下文.env中的YUDAO_CAPTCHA_ENABLE一致,默认都是true。 yudao-ui-admin-vue2同理,把VUE_APP_BASE_API改成 Nginx 的访问地址即可。
打包完成后,在源码根目录下,执行如下命令,将产物目录里面的文件复制到 web/dist 目录:
mkdir -p script/docker-compose/web/dist
cp -R /path/to/前端打包产物目录/. script/docker-compose/web/dist/
复制后,script/docker-compose/web/dist 下应该直接有 index.html 文件。
# 3. 配置 .env
执行如下命令,创建 .env 文件:
cd script/docker-compose
cp .env.example .env
至少替换 MYSQL_ROOT_PASSWORD、MYSQL_PASSWORD、REDIS_PASSWORD 三个示例密码(形如 Root@ChangeMe2026);使用内置 Nacos 时,同时替换 NACOS_AUTH_TOKEN(可用 openssl rand -base64 32 生成)、NACOS_AUTH_IDENTITY_VALUE。主要的变量如下:
| 变量 | 默认值 | 说明 |
|---|---|---|
WEB_PORT | 8080 | 前端访问端口。需要在服务器安全组中放行 |
IMAGE_TAG | local | 后端镜像的 tag,修改后便于回滚 |
MYSQL_DATABASE | ruoyi-vue-pro | 数据库名 |
MYSQL_ROOT_PASSWORD | 示例值 | MySQL root 密码,仅供初始化与运维使用 |
MYSQL_USER / MYSQL_PASSWORD | yudao / 示例值 | 后端使用的账号,只拥有 MYSQL_DATABASE 库的权限 |
REDIS_PASSWORD | 示例值 | Redis 密码 |
SPRING_PROFILES_ACTIVE | dev | 后端的 profile,同时决定 Nacos Data ID 的后缀 |
YUDAO_CAPTCHA_ENABLE | true | 是否开启登录验证码 |
COMPOSE_PROFILES | nacos | 为 nacos 时启动内置 Nacos;复用已部署的 Nacos 时清空 |
NACOS_SERVER_ADDR | nacos:8848 | Nacos 地址,必须是容器内可访问的地址 |
NACOS_NAMESPACE | public | 命名空间 ID,注册中心与配置中心共用 |
NACOS_GROUP | DEFAULT_GROUP | 分组,注册中心与配置中心共用 |
NACOS_USERNAME / NACOS_PASSWORD | 空 | 已部署的 Nacos 开启鉴权时填写 |
docker-compose.yml 会将它们转换成后端的环境变量,覆盖 Jar 包中 application-dev.yaml 的配置:
- 数据库主库
master、从库slave,以及 Redis,指向 Compose 内的mysql、redis。Redis 库索引沿用application-dev.yaml中的1。 - Nacos 的地址、账号、命名空间、分组,对应
spring.cloud.nacos.*。 XXL_JOB_ENABLED=false:本编排不提供 XXL-Job 调度中心,关闭执行器。YUDAO_DEMO=false:application-dev.yaml默认开启演示模式,会禁止写操作,这里关闭。
注意:`.env` 中的 MySQL 账号密码,只在首次初始化时生效!
mysql-data 数据卷创建后,再修改 .env 中的 MYSQL_*,不会改变数据库中已有的账号密码,反而会导致服务连接失败。另外,.env 已被 .gitignore 忽略,不要提交到 Git 仓库。
# 3.1 Nacos 的两种用法
方式一:内置 Nacos(默认)。保持 COMPOSE_PROFILES=nacos、NACOS_SERVER_ADDR=nacos:8848、NACOS_NAMESPACE=public 即可,不需要手动创建命名空间。Java 服务会等待 Nacos 的 8848、9848 端口可连接后再启动。
内置 Nacos 没有开启客户端鉴权,端口也默认不对宿主机开放,只适合本机体验。如需查看 Nacos 控制台,取消 docker-compose.yml 中 nacos 的 ports 注释,执行 docker compose up -d nacos 后,在服务器上访问 http://127.0.0.1:18080(远程可使用 ssh -L 18080:127.0.0.1:18080 root@139.9.196.247 转发)。首次访问需要初始化 nacos 用户的密码。
方式二:复用已部署的 Nacos。建议使用 Nacos 3.x(与项目的 nacos-client 3.x 对应),在 .env 中:
- ① 清空
COMPOSE_PROFILES(即COMPOSE_PROFILES=),不再启动内置 Nacos。 - ②
NACOS_SERVER_ADDR填写容器内可访问的地址,不能写127.0.0.1。Nacos 部署在本机时,使用host.docker.internal:8848。8848 与 9848(gRPC 端口,等于 8848 + 1000)两个端口都要放通。 - ③
NACOS_NAMESPACE填写命名空间 ID,并且该命名空间需要已经存在;NACOS_GROUP填写分组。 - ④ Nacos 开启鉴权时,填写
NACOS_USERNAME、NACOS_PASSWORD。
注意:同一个 Nacos 命名空间 + 分组中的服务实例,必须能够互相访问!
服务注册到 Nacos 的是 Compose 网络内的容器 IP(例如说 172.18.0.5),只有同一个 Compose 网络中的容器才能访问。
所以复用 Nacos 时,不要和本地 IDE 启动的服务、或其它服务器上的服务,共用同一个命名空间 + 分组,否则网关可能把请求转发到一个不可达的 IP 上。请为 Compose 部署使用独立的命名空间或分组。
# 3.2 配置的优先级
网关转发 /admin-api/system/** 时,使用的是 grayLb://system-server(项目自定义的灰度负载均衡);system-server 与 infra-server 之间的 Feign 调用,使用的也是 Nacos 服务名。它们都从 Nacos 获取实例后直接访问,而不是使用 Compose 服务名。
每个服务的配置,按照优先级从高到低,来自如下 4 个地方:
- ①
docker-compose.yml中的环境变量 - ② Nacos 配置中心:命名空间
NACOS_NAMESPACE、分组NACOS_GROUP下,Data ID为${spring.application.name}-${SPRING_PROFILES_ACTIVE}.yaml的配置,例如说gateway-server-dev.yaml、system-server-dev.yaml、infra-server-dev.yaml。不存在时会忽略 - ③ Jar 包中的
application-dev.yaml - ④ Jar 包中的
application.yaml
也就是说,Nacos 中的数据库、Redis、Nacos 等配置,会被上述环境变量覆盖;而其它配置项,会覆盖 Jar 包中的配置。配置中心的使用,可见 《配置中心 Nacos》 文档。
# 4. 启动
在 script/docker-compose 目录下,执行如下命令:
# ① 检查配置:变量缺失会直接报错
docker compose config
# ② 构建后端镜像,并启动所有容器
docker compose up -d --build
# ③ 查看状态与日志
docker compose ps
docker compose logs -f gateway system-server infra-server
MySQL 首次启动时需要导入 SQL,大约 1 分钟左右。system-server、infra-server 会等到 mysql、redis(以及内置 nacos)的健康检查通过后,才开始启动。
3 个服务的日志中,分别出现 Started GatewayServerApplication、Started SystemServerApplication、Started InfraServerApplication,说明启动完成。
# 5. 验证
① 执行如下命令,确认服务使用容器 IP 注册到了 Nacos:
docker compose logs system-server | grep "register finished"
看到类似 nacos registry, DEFAULT_GROUP system-server 172.18.0.6:48081 register finished 的内容即可。gateway、infra-server 同理。
② 执行如下命令,验证 Nginx => 网关 => Nacos => system-server => MySQL 的链路:
curl -G --data-urlencode "name=芋道源码" http://127.0.0.1:8080/admin-api/system/tenant/get-id-by-name
返回 {"code":0,"data":1,"msg":""},说明从数据库中查询到了默认租户。
③ 执行如下命令,验证 网关 => infra-server 的转发正常:
curl http://127.0.0.1:8080/admin-api/infra/
返回 {"code":401,"data":null,"msg":"账号未登录"},这是 infra-server 返回的未登录提示。
友情提示:服务刚启动时,网关返回 503 怎么办?
网关的负载均衡会缓存从 Nacos 获取的实例列表,服务刚注册时,可能需要等待几十秒才会生效。如果持续 503,参见「7. 常见问题」。
④ 请求 http://139.9.196.247:8080 (opens new window) 地址(“需要换成你的外网 IP”),成功访问前端项目。使用默认账号 admin、密码 admin123 登录。
⑤ 登录成功后,验证服务之间的 Feign 调用:
system-server=>infra-server:system-server的访问日志,是通过 Feign 调用infra-server写入数据库的。执行如下命令,可以看到application_name为system-server的记录:
docker compose exec mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE" -e "SELECT application_name, request_url, create_time FROM infra_api_access_log ORDER BY id DESC LIMIT 5"'
infra-server=>system-server:在前端打开 [基础设施 -> 文件管理] 等infra-server的菜单,能正常加载数据。因为infra-server需要通过 Feign 调用system-server,进行权限校验。
⑥ 执行如下命令,验证 后端 => Redis 正常,可以看到登录的访问令牌(redis 容器已经通过 REDISCLI_AUTH 配置了密码):
docker compose exec redis redis-cli -n 1 --scan --pattern 'oauth2_access_token:*'
# 6. 日常运维
# 6.1 更新后端
# 回到源码根目录重新打包,再回到部署目录重建、重启
cd ../..
mvn clean package -pl yudao-gateway,yudao-module-system/yudao-module-system-server,yudao-module-infra/yudao-module-infra-server -am -Dmaven.test.skip=true
cd script/docker-compose
docker compose up -d --build gateway system-server infra-server
只更新某个服务时,打包与 docker compose up -d --build 只写对应模块即可。Nginx 使用 Docker 内置 DNS 动态解析服务名,网关容器重建后,无需重启 web。如需回滚,可以在打包前修改 .env 的 IMAGE_TAG,保留旧 tag 的镜像。
# 6.2 更新前端
# 清空 web/dist 内的文件(保留 dist 目录本身),复制新产物,再重启 web
rm -rf web/dist/*
cp -R /path/to/前端打包产物目录/. web/dist/
docker compose restart web
不要删除 web/dist 目录本身:它是 bind mount 挂载,目录被删掉重建后,容器会看不到新文件。修改 nginx/default.conf 后,同样执行 docker compose restart web。
# 6.3 扩展其它服务
如果需要部署 bpm-server、pay-server 等其它服务,可以参考 system-server 在 docker-compose.yml 中增加一个服务:build.context 指向对应的 yudao-module-xxx/yudao-module-xxx-server 目录,environment 同样使用 <<: *app-env。网关中已经配置了各服务的路由,服务注册到 Nacos 后,即可通过网关访问。部分模块有额外的 SQL 或中间件依赖,请先阅读对应模块的“功能开启”文档。
# 6.4 查看日志
docker compose logs -f --tail=200 system-server ## 服务控制台日志
docker compose exec system-server tail -f /root/logs/system-server.log ## 容器内的应用日志文件,文件名为 spring.application.name
docker compose logs -f web ## Nginx 访问日志
# 6.5 停止与数据
# 停止并删除容器,保留数据卷
docker compose down
注意:不要执行 `docker compose down -v`!
它会删除 yudao-cloud_mysql-data、yudao-cloud_redis-data、yudao-cloud_nacos-data 数据卷,数据库内容、Nacos 中的配置将全部丢失。
# 6.6 数据库升级
SQL 只在 mysql-data 数据卷为空(首次启动)时执行一次。后续项目升级时,请先备份,再参考【更新日志】中对应版本的说明,手动执行升级 SQL:
docker compose exec -T mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" "$MYSQL_DATABASE"' < /path/to/upgrade.sql
如需使用外部 MySQL,可参考 README.md 的「数据库初始化说明」,删除 mysql 服务并修改 x-app-env 中的数据源地址。
# 7. 常见问题
① docker compose config 报 请在 .env 中设置 xxx:没有执行 cp .env.example .env,或者没有在 script/docker-compose 目录下执行命令。
② docker compose up 报 web/dist 或 SQL 文件不存在:挂载使用了 create_host_path: false,需要先完成「2.2 打包前端」的复制,并确认源码根目录下有 sql/mysql/ruoyi-vue-pro.sql 文件。
③ 访问接口返回 503 Service Unavailable:网关在 Nacos 中找不到可用的服务实例。
- 服务刚启动时,等待几十秒再重试。
- 复用 Nacos 时,确认
NACOS_NAMESPACE填的是命名空间 ID,并且没有其它机器的同名服务注册到同一个命名空间 + 分组。
④ 服务反复重启,执行 docker compose logs system-server 查看原因:
- 连接 Nacos 失败:复用 Nacos 时,
NACOS_SERVER_ADDR写了127.0.0.1,或 9848 端口不通。 Access denied:.env中的 MySQL 密码,在数据卷初始化后修改过。- 首次导入中途被中断,数据卷处于半初始化状态:确认数据可以丢弃后,执行
docker compose down和docker volume rm yudao-cloud_mysql-data,再重新启动。 - 环境变量之外的配置不符合预期:检查 Nacos 中是否存在同名的
Data ID配置,参见「3.2 配置的优先级」。
⑤ 前端请求跑到了 localhost:48080 等地址,或验证码报错:前端打包时,没有把后端地址改成 Nginx 的访问地址,或 VITE_APP_CAPTCHA_ENABLE 与 YUDAO_CAPTCHA_ENABLE 不一致,参见「2.2 打包前端」。
⑥ Swagger(/doc.html)、Spring Boot Admin(/admin/)等页面无法访问:出于安全考虑,nginx/default.conf 只代理 /admin-api/、/app-api/、/infra/ws,需要时请自行增加 location。
# 666. 更多说明
① 如果你希望部署到 Kubernetes 集群,可参考 《Kubernetes 部署》 文档。
② Compose 的启动顺序、文件格式,可参考 Docker 官方的 《Control startup order》 (opens new window)、《Services top-level elements》 (opens new window) 文档。
③ 如果需要 HTTPS 访问,可参考 《HTTPS 证书》 文档,在 nginx/default.conf 中增加 443 的 server 配置,并在 docker-compose.yml 中暴露 443 端口、挂载证书目录。