Skip to content

Docker Stack 零中断部署实践手册

本文档整理了本项目从创建、部署、版本更新到后期运维的全过程命令,并汇总了实践中遇到的问题与结论。

1. 项目说明

这是一个用于验证 Docker Swarm Stack 滚动更新 是否“无损”的 Node.js 演示服务。

端点作用
GET /version/返回版本号、容器 hostname、pid、uptime
GET /health健康检查;优雅停机时返回 503
版本号通过构建参数 APP_VERSION 和运行时环境变量注入,便于观察更新是否生效。

关键配置(docker-compose.yml

yaml
image: ${IMAGE_TAG:-version-demo:latest}   # CI/手动用环境变量注入,勿写死 latest 反复部署
environment:
  APP_VERSION: ${APP_VERSION:-unknown}
deploy:
  replicas: 1                              # 平时 1 台省资源;要减少闪断可临时改为 2
  update_config:
    parallelism: 1                         # 每次只更新 1 个副本
    order: start-first                     # 先起新,再停旧
    delay: 10s
    monitor: 15s
    failure_action: rollback
stop_grace_period: 15s                     # 给进程优雅退出时间

2. 全过程命令

以下命令均在项目根目录 docker_stack 下执行(PowerShell)。

2.1 初始化(仅首次)

powershell
# 查看 Swarm 状态(inactive = 未开启)
docker info --format "{{.Swarm.LocalNodeState}}"
# 初始化 Swarm
docker swarm init

2.2 首次构建与部署

powershell
$ver = "1.0.0"
# 构建镜像(版本打进镜像)
docker build --build-arg APP_VERSION=$ver -t "version-demo:$ver" .
# 用环境变量注入镜像标签与版本(不要手改 compose 里的版本号)
$env:IMAGE_TAG = "version-demo:$ver"
$env:APP_VERSION = $ver
# 部署 Stack(--detach=false 会等待收敛完成)
docker stack deploy -c docker-compose.yml version-demo --detach=false

2.3 验证部署

powershell
# 服务概览(副本数、镜像)
docker stack services version-demo
# 各任务状态
docker service ps version-demo_app
# 访问版本接口
curl http://localhost:3000/version
# 或
Invoke-WebRequest http://localhost:3000/version -UseBasicParsing | Select-Object -ExpandProperty Content

期望返回类似:

json
{"version":"1.0.0","hostname":"...","pid":1,"uptime":...,"timestamp":"..."}

2.4 压测(验证更新是否闪断)

另开一个终端,持续请求:

powershell
while ($true) {
  try {
    (Invoke-WebRequest http://localhost:3000/version -UseBasicParsing -TimeoutSec 2).Content
  } catch {
    Write-Host "FAILED: $_" -ForegroundColor Red
  }
  Start-Sleep -Milliseconds 100
}

观察:出现红色 FAILED 即表示该次请求在更新窗口丢失。

2.5 版本更新(滚动更新)

每次必须使用新的镜像 tag(如 1.0.01.0.1),不能反复只用 latest

powershell
$ver = "1.0.1"
docker build --build-arg APP_VERSION=$ver -t "version-demo:$ver" .
$env:IMAGE_TAG = "version-demo:$ver"
$env:APP_VERSION = $ver
docker stack deploy -c docker-compose.yml version-demo --detach=false
# 确认版本已切换
curl http://localhost:3000/version

2.6 强制更新(tag 未变或怀疑未拉到新镜像时)

powershell
docker service update --force --image "version-demo:1.0.1" --env-add "APP_VERSION=1.0.1" version-demo_app

2.7 不改 compose、直接更新服务(适合 CI)

powershell
$ver = "1.0.2"
docker build --build-arg APP_VERSION=$ver -t "version-demo:$ver" .
docker service update --image "version-demo:$ver" --env-add "APP_VERSION=$ver" version-demo_app

2.8 副本扩缩(运维)

powershell
# 查看当前副本
docker service ls
# 临时扩到 2(发布前减少闪断)
docker service scale version-demo_app=2
# 发布完成后再缩回 1(省内存)
docker service scale version-demo_app=1

推荐发布流程(平时 1 台、发布时临时 2 台):

powershell
$ver = "1.0.3"
docker service scale version-demo_app=2
# 等新副本 Running
docker service ps version-demo_app
docker build --build-arg APP_VERSION=$ver -t "version-demo:$ver" .
$env:IMAGE_TAG = "version-demo:$ver"
$env:APP_VERSION = $ver
docker stack deploy -c docker-compose.yml version-demo --detach=false
docker service scale version-demo_app=1

注意:若 docker-compose.yml 里写死 replicas: 1,下次 stack deploy 可能又把副本数改回 1。临时扩缩后若还要用 compose 部署,请同步改 compose,或发布窗口内只用 service update

2.9 日常运维监控

powershell
# Stack / 服务列表
docker stack ls
docker stack services version-demo
# 任务与失败历史