在微服务架构日益普及的今天,单机部署已无法满足生产环境的高可用和可扩展性需求。本文将详细指导您如何将一个基于 RocketMQ 的 SpringBoot 微服务项目从单机 Docker Compose 部署升级为生产级的 Docker Swarm 集群部署。
一、Docker Swarm 架构概述
1.1 Swarm 集群核心组件
- 管理节点 (Manager Nodes) :负责集群管理、服务调度
- 工作节点 (Worker Nodes) :运行容器实例
- Raft 共识算法:保证管理节点高可用
- 覆盖网络 (Overlay Network) :实现跨主机容器通信
1.2 集群架构设计
lua
+-----------------+
| 负载均衡器 |
| (Nginx/Haproxy) |
+-----------------+
|
+-----------------------------------+
| Swarm 集群 |
+-----------------------------------+
| Manager1 | Manager2 | Manager3 | ← 管理节点(奇数个)
+-----------------------------------+
| Worker1 | Worker2 | Worker3 | ← 工作节点
+-----------------------------------+
二、环境准备与集群初始化
2.1 服务器规划
假设我们有 3 台服务器:
- 192.168.1.10 (manager1)
- 192.168.1.11 (worker1)
- 192.168.1.12 (worker2)
2.2 所有节点基础环境配置
bash
# 1. 安装 Docker(所有节点)
curl -fsSL https://get.docker.com | sh
sudo systemctl enable docker
sudo systemctl start docker
# 2. 开放防火墙端口
sudo ufw allow 22/tcp
sudo ufw allow 2377/tcp # Swarm 管理端口
sudo ufw allow 7946/tcp # 节点通信
sudo ufw allow 7946/udp
sudo ufw allow 4789/udp # 覆盖网络
# 3. 设置主机名(可选)
sudo hostnamectl set-hostname manager1
sudo hostnamectl set-hostname worker1
sudo hostnamectl set-hostname worker2
2.3 初始化 Swarm 集群
bash
# 在 manager1 上执行
docker swarm init --advertise-addr 192.168.1.10
# 输出示例:
# Swarm initialized: current node (xyz) is now a manager.
# To add a worker to this swarm, run the following command:
# docker swarm join --token SWMTKN-1-xxx 192.168.1.10:2377
# 在工作节点上执行加入命令
# 在 worker1 和 worker2 上分别执行:
docker swarm join --token SWMTKN-1-xxx 192.168.1.10:2377
2.4 验证集群状态
bash
# 在管理节点查看节点状态
docker node ls
# 输出示例:
# ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
# xyz123 * manager1 Ready Active Leader 20.10.12
# abc456 worker1 Ready Active 20.10.12
# def789 worker2 Ready Active 20.10.12
三、改造 Docker Compose 文件支持 Swarm
3.1 创建 Swarm 专用配置文件
创建 docker-compose.swarm.yml:
yaml
version: '3.8'
services:
# SpringBoot 应用服务 - 无状态,可水平扩展
my-springboot-app:
image: my-springboot-app:latest
deploy:
replicas: 3 # 启动3个实例
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
update_config:
parallelism: 1 # 滚动更新:每次更新1个实例
delay: 10s
order: start-first
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
placement:
constraints:
- node.role==worker # 只部署在工作节点
ports:
- target: 8080
published: 8080
protocol: tcp
mode: host # 使用host模式便于直接访问
environment:
- rocketmq.client.logRoot=/home/spring/logs/rocketmqlogs
- SPRING_PROFILES_ACTIVE=prod
volumes:
- springboot_logs:/home/spring/logs
networks:
- app-network
depends_on:
- redis
- rmqnamesrv
- rmqbroker
- mongo
# Redis 服务 - 有状态,单实例+持久化
redis:
image: redis:7-alpine
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints:
- node.labels.redis==true # 固定部署在特定节点
ports:
- target: 6379
published: 6379
protocol: tcp
mode: host
command: redis-server --requirepass 123456 --appendonly yes
volumes:
- redis_data:/data
networks:
- app-network
# RocketMQ NameServer - 有状态,建议单实例
rmqnamesrv:
image: apache/rocketmq:5.1.0
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints:
- node.labels.rocketmq==true
ports:
- target: 9876
published: 9876
protocol: tcp
mode: host
command: sh mqnamesrv
volumes:
- rmqnamesrv_data:/home/rocketmq/store
networks:
- app-network
# RocketMQ Broker - 有状态,需要与NameServer同节点或网络互通
rmqbroker:
image: apache/rocketmq:5.1.0
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints:
- node.labels.rocketmq==true
ports:
- target: 10911
published: 10911
protocol: tcp
mode: host
- target: 10909
published: 10909
protocol: tcp
mode: host
environment:
NAMESRV_ADDR: "rmqnamesrv:9876"
JAVA_OPTS: " -Duser.home=/opt"
JAVA_OPT_EXT: "-server -Xms256m -Xmx256m -Xmn128m"
volumes:
- type: bind
source: ./broker.conf
target: /opt/rocketmq/conf/broker.conf
- rmqbroker_data:/home/rocketmq/store
command: sh mqbroker -c /opt/rocketmq/conf/broker.conf
networks:
- app-network
# MongoDB 服务 - 有状态,单实例+持久化
mongo:
image: mongo:5
deploy:
replicas: 1
restart_policy:
condition: on-failure
placement:
constraints:
- node.labels.mongo==true
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: root
ports:
- target: 27017
published: 27017
protocol: tcp
mode: host
volumes:
- mongo_data:/data/db
- mongo_config:/data/configdb
networks:
- app-network
# 可选:添加监控服务
visualizer:
image: dockersamples/visualizer:latest
deploy:
replicas: 1
placement:
constraints:
- node.role==manager
ports:
- "8081:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
networks:
- app-network
# 覆盖网络定义
networks:
app-network:
driver: overlay
attachable: true
# 数据卷定义
volumes:
redis_data:
driver: local
mongo_data:
driver: local
mongo_config:
driver: local
rmqnamesrv_data:
driver: local
rmqbroker_data:
driver: local
springboot_logs:
driver: local
3.2 创建 Broker 配置文件
创建 broker.conf适配集群环境:
ini
# Broker 配置 - 集群优化版
brokerClusterName = DefaultCluster
brokerName = broker-a
brokerId = 0
deleteWhen = 04
fileReservedTime = 48
brokerRole = ASYNC_MASTER
flushDiskType = ASYNC_FLUSH
# 集群配置
namesrvAddr = rmqnamesrv:9876
brokerIP1 = 192.168.1.11 # 根据实际节点IP修改
# 性能优化
mapedFileSizeCommitLog = 1073741824
mapedFileSizeConsumeQueue = 300000
maxMessageSize = 65536
四、节点标签与资源规划
4.1 为节点打标签
ini
# 为运行有状态服务的节点打标签
docker node update --label-add redis=true worker1
docker node update --label-add rocketmq=true worker1
docker node update --label-add mongo=true worker1
# 验证标签
docker node inspect worker1 | grep Labels
4.2 资源规划策略
- 有状态服务:固定部署在特定节点(使用标签约束)
- 无状态服务:可在工作节点间自动调度
- 管理节点:只运行管理服务,不运行业务容器
五、集群网络与存储配置
5.1 创建覆盖网络
sql
# 创建用于服务发现的覆盖网络
docker network create -d overlay --attachable app-network
# 验证网络
docker network ls | grep overlay
5.2 配置共享存储(生产环境建议)
对于有状态服务的数据持久化,建议使用网络存储:
yaml
volumes:
redis_data:
driver: local
# 生产环境建议使用:
# driver: nfs
# driver_opts:
# share: "192.168.1.100:/data/redis"
六、部署与验证
6.1 部署应用栈
bash
# 在管理节点执行部署
docker stack deploy -c docker-compose.swarm.yml rocketmq-app
# 查看服务状态
docker stack services rocketmq-app
# 实时监控部署进度
watch docker service ls
6.2 验证服务状态
ruby
# 查看所有服务状态
docker service ls
# 查看具体服务详情
docker service ps rocketmq-app_my-springboot-app
# 查看服务日志
docker service logs rocketmq-app_my-springboot-app
# 测试服务连通性
curl http://192.168.1.10:8080/actuator/health
curl http://192.168.1.11:8080/actuator/health
curl http://192.168.1.12:8080/actuator/health
6.3 验证 RocketMQ 集群
bash
# 进入容器测试 RocketMQ
docker exec -it $(docker ps -q -f name=rocketmq-app_my-springboot-app) sh
# 在容器内测试
./mqadmin clusterList -n rmqnamesrv:9876
./mqadmin topicList -n rmqnamesrv:9876
七、集群运维与管理
7.1 常用管理命令
ini
# 扩展应用实例数
docker service scale rocketmq-app_my-springboot-app=5
# 滚动更新服务
docker service update --image my-springboot-app:v2.0 rocketmq-app_my-springboot-app
# 查看服务详情
docker service inspect rocketmq-app_my-springboot-app
# 故障节点处理
docker node update --availability drain worker1 # 排空节点
docker node update --availability active worker1 # 重新激活
7.2 监控与日志
yaml
# 设置日志驱动(在docker-compose中配置)
deploy:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# 集中日志收集(建议)
# 可集成ELK或Fluentd进行日志聚合
7.3 备份与恢复
bash
# 备份有状态服务数据
docker run --rm -v rocketmq-app_redis_data:/source -v $(pwd)/backup:/backup alpine \
tar czf /backup/redis_$(date +%Y%m%d).tar.gz -C /source .
# 创建管理节点备份
docker swarm init --force-new-cluster # 在故障恢复时使用
八、高可用与故障转移测试
8.1 模拟节点故障
sql
# 模拟工作节点故障
docker node update --availability drain worker1
# 观察服务自动迁移
watch docker service ps rocketmq-app_my-springboot-app
# 恢复节点
docker node update --availability active worker1
8.2 管理节点高可用
bash
# 提升其他节点为管理节点(实现管理节点HA)
docker node promote worker1
docker node promote worker2
# 查看管理节点状态
docker node ls
九、生产环境优化建议
9.1 安全加固
csharp
# 使用TLS加密集群通信
docker swarm init --advertise-addr 192.168.1.10 --autolock
# 定期轮换加密密钥
docker swarm unlock-key --rotate
9.2 资源限制与预留
yaml
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 512M
9.3 健康检查配置
bash
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
十、常见问题排查
10.1 服务无法启动
bash
# 查看详细错误信息
docker service logs rocketmq-app_my-springboot-app --details
# 检查网络连通性
docker network inspect app-network
# 检查节点资源
docker node ps $(docker node ls -q)
10.2 数据持久化问题
bash
# 检查卷状态
docker volume ls
# 进入容器检查挂载点
docker exec -it <container_id> df -h
总结
通过本文的详细步骤,您已成功将 RocketMQ 微服务项目从单机 Docker Compose 部署升级为高可用的 Docker Swarm 集群部署。关键改进包括:
- ✅ 高可用性:多节点部署,自动故障转移
- ✅ 弹性伸缩:无状态服务水平扩展,有状态服务稳定运行
- ✅ 服务发现:覆盖网络实现跨主机服务通信
- ✅ 滚动更新:零停机部署新版本
- ✅ 资源管理:精细化的CPU/内存控制