Docker Swarm之Java 应用部署与平滑更新

Docker Swarm Java 应用部署与平滑更新

  • [📘 一、概述](#📘 一、概述)
  • [🧩 二、准备工作](#🧩 二、准备工作)
  • [🚀 三、首次部署](#🚀 三、首次部署)
  • [🔄 四、平滑更新 Java 服务](#🔄 四、平滑更新 Java 服务)
  • [🧰 五、问题排查与回滚](#🧰 五、问题排查与回滚)
  • [✅ 六、总结](#✅ 六、总结)

📘 一、概述

本文介绍如何使用 Docker Swarm 集群部署 Java 应用,并实现 零停机的平滑滚动更新。

适用于中小型分布式系统、微服务架构项目的生产环境。

🧩 二、准备工作

1、docker-compose-swarm.yml

说明:Swarm 不支持 docker-compose build,因此需要提前构建并推送镜像到远程仓库(如腾讯云容器镜像服务)。

yaml 复制代码
version: "3.9"

services:
  redis:
    image: redis:7.2
    networks:
      - app-net
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
        max_attempts: 3
      resources:
        limits:
          memory: 512M
        reservations:
          memory: 256M

  java-app:
    image: ccr.ccs.tencentyun.com/lensung_supply/aigc-api-aiyunhua:aigc-api-assistant-1.0.0
    depends_on:
      - redis
    environment:
      SPRING_PROFILES_ACTIVE: prod
      SPRING_REDIS_HOST: redis
      SPRING_REDIS_PORT: 6379
    ports:
      - "9799:9799"
    networks:
      - app-net
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9799/actuator/health"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 90s
    deploy:
      replicas: 2  # 至少两个副本实现平滑切换
      restart_policy:
        condition: on-failure
        max_attempts: 3
      update_config:
        parallelism: 1       # 每次更新1个副本
        delay: 15s           # 每两个副本更新间隔15秒
        monitor: 60s         # 监控健康状态60秒
        failure_action: rollback
        order: start-first   # 先启动新副本,再停止旧副本
      resources:
        limits:
          memory: 2G
        reservations:
          memory: 1G

  nginx:
    image: nginx:1.25
    depends_on:
      - java-app
    volumes:
      - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./nginx/logs:/var/log/nginx
    ports:
      - "8000:80"
    networks:
      - app-net
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
        max_attempts: 3
      resources:
        limits:
          memory: 256M
        reservations:
          memory: 128M

networks:
  app-net:
    driver: overlay

🟡 小贴士:

⚠️ Swarm 环境不支持 container_name,会自动命名副本。

💡 如果 Java 服务启动较慢,start_period 可调大到 120s。

✅ 建议在各节点上提前执行 docker login ccr.ccs.tencentyun.com

2、nginx.conf

支持 CORS、WebSocket、Gzip 压缩,转发到 Swarm 服务名 java-app。

bash 复制代码
user  nginx;
worker_processes  auto;

events { worker_connections  1024; }

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    tcp_nopush      on;
    tcp_nodelay     on;
    keepalive_timeout  65;
    server_tokens off;

    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 2;
    gzip_types text/plain text/css application/javascript application/json application/xml;
    gzip_vary on;

    map $http_upgrade $connection_upgrade {
        default     keep-alive;
        websocket   upgrade;
    }

    server {
        listen 80;
        server_name aigc.aiyunhua.com;

        location /v1 {
            add_header Access-Control-Allow-Origin * always;
            add_header Access-Control-Allow-Headers Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Requested-With,token,platform,satoken always;
            add_header Access-Control-Allow-Methods GET,POST,OPTIONS,HEAD,PUT,DELETE always;
            add_header Access-Control-Allow-Credentials true always;
            if ($request_method = OPTIONS) { return 200; }

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_pass http://java-app:9799;
            proxy_redirect off;
            proxy_connect_timeout 60s;
            proxy_send_timeout    300s;
            proxy_read_timeout    300s;
        }

        location / { return 403; }
    }
}

3、prod.sh + Dockerfile(构建并推送镜像)

bash 复制代码
#!/bin/bash -v
buildPath="ccr.ccs.tencentyun.com/lensung_supply/aigc-api-aiyunhua"
name="aigc-api-assistant"
version="1.0.1"

git pull
#mvn clean install package -Dmaven.test.skip=true

docker login --username=100009090170 --password=hzls2020 ccr.ccs.tencentyun.com
docker build -t $buildPath:$name-$version --platform=linux/amd64 .
docker push $buildPath:$name-$version
docker rmi $buildPath:$name-$version

4、diagnose.sh(诊断脚本,可选)

此脚本可快速检测:

  • Swarm 集群状态
  • 服务副本是否健康
  • 镜像版本是否匹配
  • 网络配置是否存在
bash 复制代码
#!/bin/bash

# Docker Swarm 服务诊断脚本
# 使用方法: ./diagnose.sh

set -e

# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

STACK_NAME="aigc-stack"
SERVICE_NAME="${STACK_NAME}_java-app"
CORRECT_IMAGE="ccr.ccs.tencentyun.com/lensung_supply/aigc-api-aiyunhua/aigc-api-assistant-1.0.0"

echo -e "${BLUE}=== Docker Swarm 服务诊断 ===${NC}"
echo ""

# 1. 检查Swarm状态
echo -e "${BLUE}1. 检查Docker Swarm状态${NC}"
if docker info | grep -q "Swarm: active"; then
    echo -e "${GREEN}✓ Docker Swarm已激活${NC}"
else
    echo -e "${RED}✗ Docker Swarm未激活${NC}"
    echo -e "${YELLOW}请执行: docker swarm init${NC}"
    exit 1
fi

# 2. 检查服务状态
echo -e "\n${BLUE}2. 检查服务状态${NC}"
docker service ls --filter name="${STACK_NAME}_"

# 3. 检查Java服务详情
echo -e "\n${BLUE}3. 检查Java服务详情${NC}"
if docker service ls | grep -q "$SERVICE_NAME"; then
    echo -e "${YELLOW}当前镜像地址:${NC}"
    docker service inspect "$SERVICE_NAME" --format "{{.Spec.TaskTemplate.ContainerSpec.Image}}"
    
    echo -e "\n${YELLOW}期望镜像地址:${NC}"
    echo "$CORRECT_IMAGE"
    
    # 检查镜像地址是否匹配
    CURRENT_IMAGE=$(docker service inspect "$SERVICE_NAME" --format "{{.Spec.TaskTemplate.ContainerSpec.Image}}")
    if [[ "$CURRENT_IMAGE" == "$CORRECT_IMAGE" ]]; then
        echo -e "${GREEN}✓ 镜像地址正确${NC}"
    else
        echo -e "${RED}✗ 镜像地址不匹配${NC}"
        echo -e "${YELLOW}需要更新服务镜像${NC}"
    fi
else
    echo -e "${RED}✗ 服务 $SERVICE_NAME 不存在${NC}"
fi

# 4. 检查服务副本状态
echo -e "\n${BLUE}4. 检查服务副本状态${NC}"
if docker service ls | grep -q "$SERVICE_NAME"; then
    docker service ps "$SERVICE_NAME" --no-trunc
else
    echo -e "${RED}✗ 无法检查副本状态${NC}"
fi

# 5. 检查镜像是否存在
echo -e "\n${BLUE}5. 检查镜像是否存在${NC}"
if docker images | grep -q "aigc-api-aiyunhua"; then
    echo -e "${GREEN}✓ 本地存在相关镜像${NC}"
    docker images | grep "aigc-api-aiyunhua"
else
    echo -e "${YELLOW}! 本地不存在相关镜像${NC}"
fi

# 6. 检查网络
echo -e "\n${BLUE}6. 检查网络${NC}"
docker network ls --filter name="${STACK_NAME}_"

# 7. 提供修复建议
echo -e "\n${BLUE}=== 修复建议 ===${NC}"

# 检查镜像地址问题
CURRENT_IMAGE=$(docker service inspect "$SERVICE_NAME" --format "{{.Spec.TaskTemplate.ContainerSpec.Image}}" 2>/dev/null || echo "")
if [[ "$CURRENT_IMAGE" != "$CORRECT_IMAGE" ]]; then
    echo -e "${YELLOW}1. 镜像地址不匹配,需要更新服务:${NC}"
    echo -e "   docker service update --image $CORRECT_IMAGE $SERVICE_NAME"
fi

# 检查副本问题
REPLICAS=$(docker service ls --filter name="$SERVICE_NAME" --format "{{.Replicas}}" 2>/dev/null || echo "0/0")
if [[ "$REPLICAS" == "0/"* ]]; then
    echo -e "${YELLOW}2. 副本数为0,可能的原因:${NC}"
    echo -e "   - 镜像拉取失败"
    echo -e "   - 健康检查失败"
    echo -e "   - 资源不足"
    echo -e "   - 配置错误"
    echo -e "\n${YELLOW}建议检查服务日志:${NC}"
    echo -e "   docker service logs $SERVICE_NAME"
fi

echo -e "\n${YELLOW}3. 如果问题持续,建议重新部署:${NC}"
echo -e "   docker stack rm $STACK_NAME"
echo -e "   docker stack deploy -c docker-compose-swarm.yml $STACK_NAME"

echo -e "\n${GREEN}=== 诊断完成 ===${NC}"

🚀 三、首次部署

bash 复制代码
# 初始化 Swarm
docker swarm init

# 登录镜像仓库
docker login ccr.ccs.tencentyun.com

# 拉取镜像
docker pull ccr.ccs.tencentyun.com/lensung_supply/aigc-api-aiyunhua:aigc-api-assistant-1.0.0

# 部署服务
docker stack deploy -c docker-compose-swarm.yml aigc-stack

# 查看服务状态
docker service ls

# 查看 Java 应用副本详情
docker service ps aigc-stack_java-app

# 查看运行日志
docker logs -f <容器ID>

# 删除整个堆栈
docker stack rm aigc-stack

🔄 四、平滑更新 Java 服务

可使用版本号迭代(如 1.0.0 → 1.0.1 → 1.0.2),也可使用固定的 latest 标签。

bash 复制代码
docker service update \
  --image ccr.ccs.tencentyun.com/lensung_supply/aigc-api-aiyunhua:aigc-api-assistant-1.0.1 \
  --update-parallelism 1 \
  --update-delay 15s \
  --update-monitor 60s \
  --update-failure-action rollback \
  --update-order start-first \
  aigc-stack_java-app

✅ 更新策略说明

参数 含义 推荐值
--update-parallelism 同时更新副本数 1
--update-delay 两次更新间隔 10--20s
--update-monitor 健康检测周期 60s
--update-failure-action 更新失败操作 rollback
--update-order 更新顺序 start-first

🧰 五、问题排查与回滚

场景 排查命令 解决方式
新镜像无法拉取 docker pull 确认仓库登录权限
服务更新失败 docker service ps 查看退出状态与错误
健康检查失败 docker logs 检查启动慢、依赖未连接
强制回滚 docker service rollback aigc-stack_java-app 回到上一个稳定版本

✅ 六、总结

阶段 关键点 说明
镜像构建 确保远程仓库可访问 否则 Swarm 管理节点无法获取 digest
健康检查 /actuator/health 必须返回 200 影响滚动更新的成功率
滚动更新 start-first + 2 副本 保证无中断平滑切换
自动回滚 failure_action: rollback 避免错误镜像影响生产
相关推荐
beyond阿亮5 小时前
nacos支持MCP Server注册与发现
java·python·ai·nacos·mcp
zl9798995 小时前
SpringBoot-数据访问之JDBC
java·spring boot
oak隔壁找我5 小时前
SpringBoot 项目不继承 parent 的实现方法
java·后端
.ZGR.5 小时前
蓝桥杯题库——部分简单题题解(Java)
java·数据结构·算法
ajax_beijing5 小时前
修改k8s的镜像源为国内镜像源
云原生·容器·kubernetes
A-刘晨阳5 小时前
K8S 二进制集群搭建(一主两从)
linux·运维·云原生·容器·kubernetes
Boop_wu5 小时前
[MySQL] 数据库设计
java·数据库·oracle
墨白曦煜6 小时前
Java集合框架整体分类(完整的集合框架关系)
java·开发语言
后端小张6 小时前
【JAVA 进阶】SpringBoot集成Sa-Token权限校验框架深度解析
java·spring boot·spring·架构·sa-token·springboot·权限框架