docker compose滚动部署实践

生产环境发版 Django 后端,往往要求 HTTP 服务全程可用 。本文介绍一种基于 Docker Compose 的滚动更新方案:应用代码打入镜像,部署两个 Gunicorn 节点,通过分步 up -d 配合 --wait,在更新过程中始终保留至少一个可访问的后端实例。

方案概览

复制代码
                    ┌─────────────┐
                    │    Nginx    │
                    │  (upstream) │
                    └──────┬──────┘
                           │
              ┌────────────┴────────────┐
              ▼                         ▼
     ┌─────────────────┐       ┌─────────────────┐
     │    backend      │       │    backend2     │
     │   :8001         │       │   :8002         │
     └────────┬────────┘       └────────┬────────┘
              │                         │
              └────────────┬────────────┘
                           ▼
                  ┌─────────────────┐
                  │  celery_worker  │
                  └─────────────────┘

三个服务共用同一应用镜像,职责如下:

服务 端口 职责
backend 8001 HTTP 节点 1,镜像构建入口
backend2 8002 HTTP 节点 2,滚动更新期间承接流量
celery_worker --- 异步任务 Worker + Beat

Nginx 将两个 backend 配置为 upstream。更新节点 1 时,节点 2 继续对外服务;更新节点 2 时,节点 1 已就绪,同样可承接流量。


一、应用镜像 Dockerfile

应用代码与 Python 依赖均在镜像构建阶段写入,运行时直接启动服务。

dockerfile 复制代码
FROM registry.example.com/myorg/app-base:1.0

WORKDIR /app

COPY requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir -r /tmp/requirements.txt

COPY . /app

requirements.txt 先于源码 COPY,Docker 可缓存依赖安装层------仅代码变更时,无需重复执行 pip install


二、docker-compose.yaml

backend 定义 build 并产出镜像;backend2celery_worker 引用同一镜像 tag。日志等需持久化的目录通过 volume 挂载,其余内容均来自镜像。

yaml 复制代码
version: "3.8"

services:
  backend:
    build:
      context: .
      dockerfile: Dockerfile
    image: registry.example.com/myorg/app:latest
    volumes:
      - /var/log/app/backend/:/var/log/backend/
    command: sh /app/deploy/runtime/run_backend.sh
    restart: unless-stopped
    ports:
      - "8001:8000"
    healthcheck:
      test: ["CMD-SHELL", "python -c \"import requests; requests.get('http://127.0.0.1:8000/health/', timeout=5)\""]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 120s
    networks:
      - app_net

  backend2:
    image: registry.example.com/myorg/app:latest
    volumes:
      - /var/log/app/backend2/:/var/log/backend/
    command: sh /app/deploy/runtime/run_backend.sh
    restart: unless-stopped
    depends_on:
      backend:
        condition: service_healthy
    ports:
      - "8002:8000"
    healthcheck:
      test: ["CMD-SHELL", "python -c \"import requests; requests.get('http://127.0.0.1:8000/health/', timeout=5)\""]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 120s
    networks:
      - app_net

  celery_worker:
    image: registry.example.com/myorg/app:latest
    volumes:
      - /var/log/app/backend/:/var/log/backend/
    command: sh deploy/runtime/run_celery.sh
    restart: unless-stopped
    networks:
      - app_net

networks:
  app_net:
    driver: bridge

三、滚动更新

发版命令

bash 复制代码
docker compose build
docker compose up -d celery_worker
docker compose up -d backend --wait
docker compose up -d backend2
步骤 命令 说明
1 docker compose build 构建新镜像,不影响正在运行的容器
2 up -d celery_worker 先更新异步任务,HTTP 链路不受影响
3 up -d backend --wait 重建节点 1 并等待就绪;此期间节点 2 正常服务
4 up -d backend2 重建节点 2;此期间节点 1 已就绪,正常服务

核心原则:任意时刻,Nginx upstream 中至少有一个 backend 处于运行状态。

时序

Nginx backend2 :8002 backend :8001 Celery 运维 Nginx backend2 :8002 backend :8001 Celery 运维 #mermaid-svg-tEjAI0gibk2NQ5Xe{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tEjAI0gibk2NQ5Xe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tEjAI0gibk2NQ5Xe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tEjAI0gibk2NQ5Xe .error-icon{fill:#552222;}#mermaid-svg-tEjAI0gibk2NQ5Xe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tEjAI0gibk2NQ5Xe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tEjAI0gibk2NQ5Xe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tEjAI0gibk2NQ5Xe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tEjAI0gibk2NQ5Xe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tEjAI0gibk2NQ5Xe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tEjAI0gibk2NQ5Xe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tEjAI0gibk2NQ5Xe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tEjAI0gibk2NQ5Xe .marker.cross{stroke:#333333;}#mermaid-svg-tEjAI0gibk2NQ5Xe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tEjAI0gibk2NQ5Xe p{margin:0;}#mermaid-svg-tEjAI0gibk2NQ5Xe .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tEjAI0gibk2NQ5Xe text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-tEjAI0gibk2NQ5Xe .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-tEjAI0gibk2NQ5Xe .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-tEjAI0gibk2NQ5Xe .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-tEjAI0gibk2NQ5Xe .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-tEjAI0gibk2NQ5Xe #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-tEjAI0gibk2NQ5Xe .sequenceNumber{fill:white;}#mermaid-svg-tEjAI0gibk2NQ5Xe #sequencenumber{fill:#333;}#mermaid-svg-tEjAI0gibk2NQ5Xe #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-tEjAI0gibk2NQ5Xe .messageText{fill:#333;stroke:none;}#mermaid-svg-tEjAI0gibk2NQ5Xe .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tEjAI0gibk2NQ5Xe .labelText,#mermaid-svg-tEjAI0gibk2NQ5Xe .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-tEjAI0gibk2NQ5Xe .loopText,#mermaid-svg-tEjAI0gibk2NQ5Xe .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-tEjAI0gibk2NQ5Xe .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-tEjAI0gibk2NQ5Xe .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-tEjAI0gibk2NQ5Xe .noteText,#mermaid-svg-tEjAI0gibk2NQ5Xe .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-tEjAI0gibk2NQ5Xe .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tEjAI0gibk2NQ5Xe .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tEjAI0gibk2NQ5Xe .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-tEjAI0gibk2NQ5Xe .actorPopupMenu{position:absolute;}#mermaid-svg-tEjAI0gibk2NQ5Xe .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-tEjAI0gibk2NQ5Xe .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-tEjAI0gibk2NQ5Xe .actor-man circle,#mermaid-svg-tEjAI0gibk2NQ5Xe line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-tEjAI0gibk2NQ5Xe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 期间 B2 仍服务流量 期间 B1 已就绪,仍服务流量 docker compose buildup -d celery_workerup -d backend --wait节点 1 就绪up -d backend2

关于 --wait

第三步中的 --wait 会让 Compose 阻塞到 backend 就绪后再返回,再执行第四步更新 backend2。整条发版链路可直接写入脚本或 CI,无需额外轮询。


四、FAQ

为什么发版前要先 build

应用代码在 build 阶段写入镜像。只有执行 up -d 才会用新镜像重建容器;restart 仅重启现有容器,不会加载新镜像。

为什么不一次性 docker compose up -d

一次性更新会同时重建两个 backend,造成短暂的全员下线。分步更新确保始终有一个 HTTP 节点在线。


五、其他实现方式

本文方案基于 Docker Compose 手动编排,适合单机或少量节点。若部署在多节点集群上,同样的滚动发布目标也可交由 Docker SwarmKubernetes 等平台自动完成副本逐批替换与流量切换。


相关推荐
用户0328472220704 小时前
如何搭建本地yum源(上)
运维
武子康5 小时前
调查研究-183 Apple container:Mac 上用轻量 VM 跑 Linux 容器,Swift 会改写本地容器体验吗?
docker·容器·apple
大树883 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠3 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质3 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
Inhand陈工3 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
Alsn863 天前
等待学习-学习目录:Docker 容器安全攻防
学习·安全·docker
酣大智3 天前
ARP代理--工作原理
运维·网络·arp·arp代理
shushangyun_3 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
施努卡机器视觉3 天前
SNK施努卡侧滑门锁上滑轮总成自动化装配线,从零件到组件,全流程精密制造方案
运维·自动化·制造