Docker自动化部署实战:用CI/CD流水线实现零停机发布

容器化应用的标准目录结构

一个可复用的Docker部署项目,目录结构不能随意。约定比配置重要——团队所有人看到相同的目录就知道文件在哪。

project/
├── Dockerfile
├── docker-compose.yml
├── .dockerignore
├── deploy/
│   ├── nginx.conf
│   ├── supervisord.conf
│   └── entrypoint.sh
├── scripts/
│   ├── build.sh
│   └── deploy.sh
└── src/
    ├── app.py
    └── requirements.txt

Dockerfile是容器构建的核心,写法直接决定镜像大小和构建速度:

# 多阶段构建:编译阶段
FROM python:3.11-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --user -r requirements.txt --no-cache-dir

# 运行阶段:只拷贝编译产物
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY src/ .
ENV PATH=/root/.local/bin:$PATH
EXPOSE 8000
CMD ["gunicorn", "app:app", "-w", "4", "-b", "0.0.0.0:8000"]

多阶段构建的关键价值在于最终镜像不包含编译工具链。python:3.11-slim基础镜像约150MB,如果用完整版python:3.11则超过1GB。更小的镜像意味着更快的拉取速度和更小的攻击面。

docker-compose编排与健康检查

单容器部署的场景越来越少,至少前端加后端加数据库加缓存,四个容器起步。docker-compose是管理这种小型编排的最佳工具:

version: "3.8"
services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://app:secret@db:5432/appdb
      - REDIS_URL=redis://cache:6379/0
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 30s
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
      interval: 5s
      timeout: 3s
      retries: 5

  cache:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./deploy/nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      web:
        condition: service_healthy

volumes:
  pgdata:

depends_on配合condition: service_healthy,确保数据库和缓存真正就绪后再启动web服务。没有健康检查的depends_on只保证容器启动,不保证服务可用,这是很多人的踩坑点。

GitHub Actions构建流水线

CI/CD流水线的目标:每次push到main分支,自动构建镜像、跑测试、推送到镜像仓库、触发部署。

# .github/workflows/deploy.yml
name: Build and Deploy

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and Push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ghcr.io/${{ github.repository }}:${{ github.sha }}
            ghcr.io/${{ github.repository }}:latest

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to Server
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.DEPLOY_HOST }}
          username: deploy
          key: ${{ secrets.DEPLOY_KEY }}
          script: |
            docker pull ghcr.io/org/app:${{ github.sha }}
            cd /opt/app
            export IMAGE_TAG=${{ github.sha }}
            docker compose up -d --no-deps web
            sleep 5
            curl -f http://localhost:8000/health || (echo "Health check failed, rolling back" && docker compose up -d --no-deps --force-recreate web && exit 1)

流水线的关键设计:部署后立即做健康检查,检查失败自动回滚。这个5秒的sleep等待应用启动,然后curl验证/health端点。如果失败,回退到上一个镜像。

蓝绿部署实现零停机

滚动更新在单实例场景下必然有短暂停机。蓝绿部署的思路是同时维护两套环境,切换流量完成发布:

#!/bin/bash
# deploy_blue_green.sh
set -e

CURRENT=$(docker compose ps --format json | jq -r '.[0].Name' | grep -o 'blue\|green' || echo "none")

if [ "$CURRENT" = "blue" ]; then
    TARGET="green"
    SOURCE="blue"
else
    TARGET="blue"
    SOURCE="green"
fi

echo "当前活跃: $SOURCE, 部署目标: $TARGET"

# 构建目标环境
export COMPOSE_PROJECT_NAME="app_$TARGET"
docker compose -f docker-compose.yml -f docker-compose.$TARGET.yml up -d --build

# 健康检查
for i in $(seq 1 12); do
    if curl -sf http://localhost:8000/health > /dev/null 2>&1; then
        echo "目标环境 $TARGET 健康检查通过"
        break
    fi
    if [ $i -eq 12 ]; then
        echo "健康检查超时,终止部署"
        docker compose -p "app_$TARGET" down
        exit 1
    fi
    sleep 5
done

# 切换Nginx上游并reload
# 更新upstream指向新环境
nginx -s reload

# 关闭旧环境
docker compose -p "app_$SOURCE" down
echo "发布完成: $TARGET 环境已激活"

蓝绿部署的代价是需要双倍的服务器资源。在容器化环境里,多一套容器的资源开销远比停机损失的销售额低。

回滚策略与版本管理

镜像标签策略决定了回滚的难易程度。latest标签在生产环境是灾难——你不知道当前跑的是哪个版本,回滚无从下手。

正确的标签策略:

# 每次构建打两个标签
# 1. Git SHA精确版本,用于回滚
docker tag app:latest registry/app:a1b2c3d
# 2. 语义化版本,用于追踪
docker tag app:latest registry/app:v1.2.3

回滚脚本:

#!/bin/bash
# rollback.sh - 回滚到指定版本
TARGET_VERSION=$1

if [ -z "$TARGET_VERSION" ]; then
    echo "用法: ./rollback.sh <version>"
    echo "可用版本:"
    docker images --format '{{.Repository}}:{{.Tag}}' registry/app | head -10
    exit 1
fi

export IMAGE_TAG=$TARGET_VERSION
docker compose up -d --no-deps web
echo "已回滚到版本: $TARGET_VERSION"

Docker自动化部署的完整闭环:代码提交触发CI构建,构建产物推送到镜像仓库,CD流水线拉取新镜像并部署,部署后健康检查,异常自动回滚。这套机制建立后,发布从高危手工操作变成可重复的自动化流程,半夜三点出问题也能安心让系统自己回滚。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/docker-zi-dong-hua-bu-shu-shi-zhan-yong-cicd-liu-shui-xian/

(0)
小编小编
上一篇 1小时前
下一篇 1小时前

相关推荐

Docker自动化部署实战:用CI/CD流水线实现零停机发布

容器化应用的标准目录结构

一个可复用的Docker部署项目,目录结构不能随意。约定比配置重要——团队所有人看到相同的目录就知道文件在哪。

project/
├── Dockerfile
├── docker-compose.yml
├── .dockerignore
├── deploy/
│   ├── nginx.conf
│   ├── supervisord.conf
│   └── entrypoint.sh
├── scripts/
│   ├── build.sh
│   └── deploy.sh
└── src/
    ├── app.py
    └── requirements.txt

Dockerfile是容器构建的核心,写法直接决定镜像大小和构建速度:

# 多阶段构建:编译阶段
FROM python:3.11-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --user -r requirements.txt --no-cache-dir

# 运行阶段:只拷贝编译产物
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY src/ .
ENV PATH=/root/.local/bin:$PATH
EXPOSE 8000
CMD ["gunicorn", "app:app", "-w", "4", "-b", "0.0.0.0:8000"]

多阶段构建的关键价值在于最终镜像不包含编译工具链。python:3.11-slim基础镜像约150MB,如果用完整版python:3.11则超过1GB。更小的镜像意味着更快的拉取速度和更小的攻击面。

docker-compose编排与健康检查

单容器部署的场景越来越少,至少前端加后端加数据库加缓存,四个容器起步。docker-compose是管理这种小型编排的最佳工具:

version: "3.8"
services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://app:secret@db:5432/appdb
      - REDIS_URL=redis://cache:6379/0
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 30s
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: appdb
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
      interval: 5s
      timeout: 3s
      retries: 5

  cache:
    image: redis:7-alpine
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./deploy/nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      web:
        condition: service_healthy

volumes:
  pgdata:

depends_on配合condition: service_healthy,确保数据库和缓存真正就绪后再启动web服务。没有健康检查的depends_on只保证容器启动,不保证服务可用,这是很多人的踩坑点。

GitHub Actions构建流水线

CI/CD流水线的目标:每次push到main分支,自动构建镜像、跑测试、推送到镜像仓库、触发部署。

# .github/workflows/deploy.yml
name: Build and Deploy

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Login to Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and Push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ghcr.io/${{ github.repository }}:${{ github.sha }}
            ghcr.io/${{ github.repository }}:latest

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to Server
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.DEPLOY_HOST }}
          username: deploy
          key: ${{ secrets.DEPLOY_KEY }}
          script: |
            docker pull ghcr.io/org/app:${{ github.sha }}
            cd /opt/app
            export IMAGE_TAG=${{ github.sha }}
            docker compose up -d --no-deps web
            sleep 5
            curl -f http://localhost:8000/health || (echo "Health check failed, rolling back" && docker compose up -d --no-deps --force-recreate web && exit 1)

流水线的关键设计:部署后立即做健康检查,检查失败自动回滚。这个5秒的sleep等待应用启动,然后curl验证/health端点。如果失败,回退到上一个镜像。

蓝绿部署实现零停机

滚动更新在单实例场景下必然有短暂停机。蓝绿部署的思路是同时维护两套环境,切换流量完成发布:

#!/bin/bash
# deploy_blue_green.sh
set -e

CURRENT=$(docker compose ps --format json | jq -r '.[0].Name' | grep -o 'blue\|green' || echo "none")

if [ "$CURRENT" = "blue" ]; then
    TARGET="green"
    SOURCE="blue"
else
    TARGET="blue"
    SOURCE="green"
fi

echo "当前活跃: $SOURCE, 部署目标: $TARGET"

# 构建目标环境
export COMPOSE_PROJECT_NAME="app_$TARGET"
docker compose -f docker-compose.yml -f docker-compose.$TARGET.yml up -d --build

# 健康检查
for i in $(seq 1 12); do
    if curl -sf http://localhost:8000/health > /dev/null 2>&1; then
        echo "目标环境 $TARGET 健康检查通过"
        break
    fi
    if [ $i -eq 12 ]; then
        echo "健康检查超时,终止部署"
        docker compose -p "app_$TARGET" down
        exit 1
    fi
    sleep 5
done

# 切换Nginx上游并reload
# 更新upstream指向新环境
nginx -s reload

# 关闭旧环境
docker compose -p "app_$SOURCE" down
echo "发布完成: $TARGET 环境已激活"

蓝绿部署的代价是需要双倍的服务器资源。在容器化环境里,多一套容器的资源开销远比停机损失的销售额低。

回滚策略与版本管理

镜像标签策略决定了回滚的难易程度。latest标签在生产环境是灾难——你不知道当前跑的是哪个版本,回滚无从下手。

正确的标签策略:

# 每次构建打两个标签
# 1. Git SHA精确版本,用于回滚
docker tag app:latest registry/app:a1b2c3d
# 2. 语义化版本,用于追踪
docker tag app:latest registry/app:v1.2.3

回滚脚本:

#!/bin/bash
# rollback.sh - 回滚到指定版本
TARGET_VERSION=$1

if [ -z "$TARGET_VERSION" ]; then
    echo "用法: ./rollback.sh <version>"
    echo "可用版本:"
    docker images --format '{{.Repository}}:{{.Tag}}' registry/app | head -10
    exit 1
fi

export IMAGE_TAG=$TARGET_VERSION
docker compose up -d --no-deps web
echo "已回滚到版本: $TARGET_VERSION"

Docker自动化部署的完整闭环:代码提交触发CI构建,构建产物推送到镜像仓库,CD流水线拉取新镜像并部署,部署后健康检查,异常自动回滚。这套机制建立后,发布从高危手工操作变成可重复的自动化流程,半夜三点出问题也能安心让系统自己回滚。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/docker-zi-dong-hua-bu-shu-shi-zhan-yong-cicd-liu-shui-xian/

(0)
小编小编
上一篇 1小时前
下一篇 1小时前

相关推荐