从 Docker Compose 到 Docker Swarm:RocketMQ 微服务项目集群部署实战指南

在微服务架构日益普及的今天,单机部署已无法满足生产环境的高可用和可扩展性需求。本文将详细指导您如何将一个基于 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 集群部署。关键改进包括:

  1. ✅ 高可用性:多节点部署,自动故障转移
  2. ✅ 弹性伸缩:无状态服务水平扩展,有状态服务稳定运行
  3. ✅ 服务发现:覆盖网络实现跨主机服务通信
  4. ✅ 滚动更新:零停机部署新版本
  5. ✅ 资源管理:精细化的CPU/内存控制
相关推荐
iOS开发上架哦2 小时前
防止 iOS 应用被二次打包,从完整性校验到 IPA 成品混淆的多层安全方案
后端
IUGEI2 小时前
【计算机网络】HTTP/3如何实现可靠传输?
java·网络·后端·网络协议·tcp/ip·计算机网络·http
天下不喵2 小时前
安全小白入门(2)-----跨站脚本(XSS)
前端·后端·安全
谁黑皮谁肘击谁在连累直升机2 小时前
包及其导入
前端·后端
架构师专栏2 小时前
从 Spring Boot 3 升级到 4:完整迁移指南
spring boot·后端
u***u6853 小时前
JavaGraphQL案例
java·spring boot·后端
云闲不收3 小时前
GraphQL教程
后端·状态模式·graphql
席万里4 小时前
Go开源库gcurl实际生产级应用
开发语言·后端·golang
yuuki2332334 小时前
【数据结构&C语言】排序大汇总
c语言·数据结构·后端·排序算法