Docker Compose 部署多个独立 Jar 服务完整实操步骤
场景说明:一台服务器,同时运行多个 SpringBoot jar(例如:api-gateway.jar、user-service.jar、order-service.jar) 架构: 多个 Java 微服务容器 + Nginx(网关 / 静态前端,可选)+ MySQL + Redis
关键点:
- 每个 jar = 独立服务条目
- 端口不能冲突,宿主机映射端口区分开
- 共用 compose 自动创建的内网网络,容器之间使用服务名互相访问
- 每个微服务单独准备 Dockerfile
一、整体目录结构(标准规范)
plaintext
deploy/
├── docker-compose.yml
├── .env # 统一环境变量:数据库地址、账号密码、配置开关
├── nginx/ # 可选,前端+反向代理
│ ├── conf.d/
│ └── dist/
├── services/
│ ├── gateway/ # 网关服务1
│ │ ├── Dockerfile
│ │ └── api-gateway.jar
│ ├── user-service/ # 用户服务2
│ │ ├── Dockerfile
│ │ └── user-service.jar
│ └── order-service/ # 订单服务3
│ ├── Dockerfile
│ └── order-service.jar
└── logs/ # 统一挂载日志目录
二、单个微服务通用 Dockerfile
路径:services/gateway/Dockerfile
所有 jar 服务可以共用一模一样的 Dockerfile,只替换 jar 名称
dockerfile
# 使用JDK基础镜像,推荐openjdk17 / 8,和项目编译版本匹配
FROM openjdk:17-jdk-slim
WORKDIR /app
# 拷贝jar包
COPY api-gateway.jar app.jar
# JVM启动参数,生产按需调整
ENTRYPOINT ["java",
"-Xms512m",
"-Xmx1024m",
"-jar",
"app.jar",
"--spring.profiles.active=prod"]
user-service、order-service 目录内 Dockerfile 同理,只修改 COPY 后的 jar 文件名。
三、.env 环境变量文件(推荐)
env
# MySQL配置
MYSQL_ROOT_PASSWORD=Root@123456
MYSQL_DATABASE=business_db
MYSQL_USER=appuser
MYSQL_PASSWORD=App@6789
# 各个服务内部端口(容器内端口统一8080,不用改)
# 宿主机对外端口,自行分配,不能重复
GATEWAY_HOST_PORT=8080
USER_HOST_PORT=8081
ORDER_HOST_PORT=8082
四、核心 docker-compose.yml
yaml
version: "3.8"
# 全局网络,所有服务自动加入,容器之间通过服务名通信
networks:
app-net:
driver: bridge
# 持久化卷
volumes:
mysql-data:
services:
# 数据库
mysql:
image: mysql:8.0
restart: always
networks:
- app-net
env_file: .env
volumes:
- mysql-data:/var/lib/mysql
- ./init-sql:/docker-entrypoint-initdb.d # 数据库初始化脚本
environment:
TZ: Asia/Shanghai
ports:
- "3306:3306"
redis:
image: redis:7-alpine
restart: always
networks:
- app-net
ports:
- "6379:6379"
command: redis-server --requirepass Redis@123
# 1.网关服务 api-gateway
gateway:
build: ./services/gateway
restart: always
networks:
- app-net
env_file: .env
ports:
- "${GATEWAY_HOST_PORT}:8080"
volumes:
- ./logs/gateway:/app/logs
depends_on:
- mysql
- redis
# 2.用户服务 user-service
user-service:
build: ./services/user-service
restart: always
networks:
- app-net
env_file: .env
ports:
- "${USER_HOST_PORT}:8080"
volumes:
- ./logs/user-service:/app/logs
depends_on:
- mysql
- redis
# 3.订单服务 order-service
order-service:
build: ./services/order-service
restart: always
networks:
- app-net
env_file: .env
ports:
- "${ORDER_HOST_PORT}:8080"
volumes:
- ./logs/order-service:/app/logs
depends_on:
- mysql
- redis
# 可选:Nginx前端反向代理
nginx:
image: nginx:alpine
restart: always
networks:
- app-net
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/dist:/usr/share/nginx/html
- ./nginx/ssl:/etc/nginx/ssl
depends_on:
- gateway
⚠️【重点通信规则】容器内部调用地址
容器内部所有服务不要使用 127.0.0.1 或者宿主机 IP 直接使用 compose 的服务名访问:
- user-service 访问 mysql →
mysql:3306 - gateway 调用 user 服务 →
http://user-service:8080 - user-service 调用 order 服务 →
http://order-service:8080
在 application-prod.yml 配置示例:
yaml
spring:
datasource:
url: jdbc:mysql://mysql:3306/business_db?useUnicode=true&characterEncoding=utf8mb4
redis:
host: redis
port: 6379
五、完整部署操作步骤
1. 服务器前置条件
已经安装 docker + docker-compose-plugin
bash
docker -v
docker compose version
2. 上传文件到服务器
在服务器创建目录 /opt/deploy 把本地整理好的目录全部上传:各个 jar、Dockerfile、yml、.env
3. 首次构建并后台启动整套服务
bash
cd /opt/deploy
# --build 首次必须加,构建各个jar服务镜像
docker compose up -d --build
4. 常用日常运维命令
bash
# 查看所有运行容器
docker compose ps
# 只查看网关实时日志
docker compose logs -f gateway
# 单独重启某一个服务(升级jar常用)
docker compose restart user-service
# 更新jar包后重新构建并重启单个服务
docker compose up -d --build user-service
# 停止全部服务(保留数据卷)
docker compose stop
# 销毁所有容器(数据库卷默认保留)
docker compose down
# 销毁容器+清空数据库数据(慎用!)
docker compose down -v
六、版本升级标准流程(线上规范)
以更新 user-service.jar 为例
- 备份旧 jar 包
- 上传新 user-service.jar 替换
services/user-service/下文件 - 执行构建重启:
bash
docker compose up -d --build user-service
- 查看日志
docker compose logs -f user-service确认启动成功 - 功能验证,异常立刻换回旧 jar 重新构建
七、高频踩坑点
-
宿主机端口冲突 每个服务左侧端口
${xxx_HOST_PORT}不能重复;容器内部统一 8080 没关系。 -
服务之间连接超时 检查连接地址是否写的服务名 ,不要写localhost。
-
depends_on 只是控制启动顺序,不会等待数据库就绪 解决方案:程序内部增加重连机制,或者使用启动脚本等待 mysql 就绪。
-
日志容器内看不到,无法持久化 yml 中配置 volumes 挂载日志目录到宿主机。
-
密码硬编码 所有敏感配置统一放到 .env,不要写死在 yml 或 jar 配置文件。
扩展方案选择
- 如果服务数量很多(>5 个微服务):建议拆分多个 compose 项目或者直接转向 K8s
- 如果不需要外部直接访问后端服务,可以不映射端口,只让 Nginx/Gateway 容器内网调用,更安全。