Skip to content

Docker CI/CD 集成

本章将介绍如何将 Docker 集成到持续集成和持续部署(CI/CD)流程中。

CI/CD 与 Docker

Docker 在 CI/CD 中的作用:

代码提交 → 构建镜像 → 运行测试 → 推送镜像 → 部署容器
阶段Docker 的作用
构建使用 Dockerfile 构建标准化镜像
测试在容器中运行测试,环境一致
推送将镜像推送到 Registry
部署拉取镜像并运行容器

GitHub Actions

构建并推送到 Docker Hub

yaml
# .github/workflows/docker.yml
name: Build and Push Docker Image

on:
  push:
    branches: [main]

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

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

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

构建、测试、部署完整流程

yaml
name: CI/CD Pipeline

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build test image
        run: docker build -t myapp:test --target test .
      - name: Run tests
        run: docker run --rm myapp:test

  build-and-push:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - name: Build and Push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: myuser/myapp:${{ github.sha }}

  deploy:
    needs: build-and-push
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to server
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            docker pull myuser/myapp:${{ github.sha }}
            docker stop myapp || true
            docker rm myapp || true
            docker run -d --name myapp -p 80:3000 myuser/myapp:${{ github.sha }}

GitLab CI/CD

yaml
# .gitlab-ci.yml
stages:
  - test
  - build
  - deploy

variables:
  IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

test:
  stage: test
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t myapp:test --target test .
    - docker run --rm myapp:test

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $IMAGE_TAG .
    - docker push $IMAGE_TAG

deploy:
  stage: deploy
  script:
    - ssh $SERVER "docker pull $IMAGE_TAG && docker stop myapp; docker rm myapp; docker run -d --name myapp -p 80:3000 $IMAGE_TAG"
  only:
    - main

多阶段 Dockerfile(支持测试)

dockerfile
# 基础阶段
FROM node:20-alpine AS base
WORKDIR /app
COPY package*.json ./
RUN npm ci

# 测试阶段
FROM base AS test
COPY . .
CMD ["npm", "test"]

# 构建阶段
FROM base AS build
COPY . .
RUN npm run build

# 生产阶段
FROM nginx:alpine AS production
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

镜像标签策略

策略标签格式适用场景
Git SHAmyapp:abc1234精确追踪每次构建
语义化版本myapp:v1.2.3正式发布
分支名myapp:main开发环境
latestmyapp:latest最新稳定版
bash
# 多标签构建
docker build -t myapp:v1.2.3 -t myapp:latest .

Docker Compose 部署

使用 Docker Compose 进行生产部署

yaml
# docker-compose.prod.yml
services:
  app:
    image: myuser/myapp:${IMAGE_TAG:-latest}
    ports:
      - "80:3000"
    environment:
      - NODE_ENV=production
    restart: always
    deploy:
      replicas: 2

  db:
    image: postgres:16
    volumes:
      - db-data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    restart: always

volumes:
  db-data:
bash
# 部署
IMAGE_TAG=abc1234 docker compose -f docker-compose.prod.yml up -d

# 更新
IMAGE_TAG=def5678 docker compose -f docker-compose.prod.yml up -d --no-deps app

零停机部署

蓝绿部署

bash
# 启动新版本(绿色)
docker run -d --name app-green -p 3001:3000 myapp:v2

# 测试新版本
curl http://localhost:3001/health

# 切换流量(更新 Nginx 配置)
# 停止旧版本(蓝色)
docker stop app-blue && docker rm app-blue

滚动更新(Docker Compose)

bash
# 逐个更新服务实例
docker compose up -d --no-deps --scale app=2 app

本章小结

Docker 与 CI/CD 的结合可以实现从代码提交到生产部署的全自动化流程。通过标准化的镜像构建和部署,确保了环境一致性和部署可靠性。

关键要点:

  • 使用多阶段 Dockerfile 支持测试和构建
  • 合理的镜像标签策略便于版本追踪
  • GitHub Actions 和 GitLab CI 都能很好地集成 Docker
  • 零停机部署保证服务可用性

延伸阅读