第十九篇:《Docker 在生产环境中的 CI/CD 实践》

将 Docker 集成到 CI/CD 流水线中,可以实现从代码提交到镜像构建、测试、部署的全自动化。本文介绍如何使用 Jenkins、GitLab CI 和 GitHub Actions 构建镜像、推送到私有仓库,并通过滚动更新部署到 Swarm 或 Kubernetes 集群。同时涵盖镜像缓存、安全扫描、蓝绿部署等生产级实践。

一、CI/CD 中的 Docker 典型流程

text

代码提交 → 触发构建 → 运行单元测试 → 构建镜像 → 推送镜像 → 部署到测试环境 → 集成测试 → 部署到生产环境

每个阶段都可以在容器中执行,确保环境一致性。

二、使用 Jenkins Pipeline 构建 Docker 镜像

2.1 环境准备

Jenkins 安装 Docker Pipeline 插件。

Jenkins 节点上安装 Docker,并将 Jenkins 用户加入 docker 组(或使用 Docker outside of Docker 方式)。

2.2 Jenkinsfile 示例

groovy

pipeline {

agent any

environment {

DOCKER_REGISTRY = 'myregistry.com:5000'

DOCKER_IMAGE = "DOCKERREGISTRY/myapp:{DOCKER_REGISTRY}/myapp:DOCKERREGISTRY/myapp:{BUILD_NUMBER}"

}

stages {

stage('Checkout') {

steps { git 'https://github.com/your/app.git' }

}

stage('Unit Test') {

steps {

sh 'docker run --rm -v $(pwd):/app -w /app node:18 npm test'

}

}

stage('Build Image') {

steps {

sh "docker build -t ${DOCKER_IMAGE} ."

}

}

stage('Push Image') {

steps {

withCredentials(string(credentialsId: 'registry_password', variable: 'REG_PASS')) {

sh '''

echo {REG_PASS} \| docker login -u youruser --password-stdin {DOCKER_REGISTRY}

docker push ${DOCKER_IMAGE}

'''

}

}

}

stage('Deploy to Test') {

steps {

sh "docker stack deploy -c docker-compose.test.yml myapp --with-registry-auth"

}

}

stage('Integration Test') {

steps {

sh './integration-tests.sh'

}

}

stage('Deploy to Production') {

input { message "Deploy to production?" }

steps {

sh "docker stack deploy -c docker-compose.prod.yml myapp --with-registry-auth"

}

}

}

post {

always {

cleanWs() // 清理工作空间

}

}

}

2.3 使用 Docker 缓存加速构建

在构建阶段,可以挂载宿主机的 Docker 缓存目录,避免重复下载基础镜像层:

groovy

sh '''

docker build --cache-from {DOCKER_IMAGE} -t {DOCKER_IMAGE} .

'''

或在 docker build 中使用 --build-arg BUILDKIT_INLINE_CACHE=1 配合 registry 缓存。

三、GitLab CI 集成

.gitlab-ci.yml 示例:

yaml 复制代码
stages:
  - test
  - build
  - deploy

variables:
  DOCKER_REGISTRY: myregistry.com:5000
  IMAGE_TAG: $CI_COMMIT_SHORT_SHA

before_script:
  - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $DOCKER_REGISTRY

unit-test:
  stage: test
  script:
    - docker run --rm -v $(pwd):/app -w /app node:18 npm test

build:
  stage: build
  script:
    - docker build -t $DOCKER_REGISTRY/myapp:$IMAGE_TAG .
    - docker push $DOCKER_REGISTRY/myapp:$IMAGE_TAG

deploy-test:
  stage: deploy
  script:
    - docker stack deploy -c docker-compose.test.yml myapp --with-registry-auth
  environment: test

deploy-prod:
  stage: deploy
  script:
    - docker stack deploy -c docker-compose.prod.yml myapp --with-registry-auth
  environment: production
  only:
    - main

四、GitHub Actions 集成

.github/workflows/docker-ci.yml:

yaml 复制代码
name: Docker CI/CD

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run unit tests
        run: docker run --rm -v ${{ github.workspace }}:/app -w /app node:18 npm test

  build-and-push:
    needs: test
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v3
      - name: Login to Registry
        uses: docker/login-action@v2
        with:
          registry: myregistry.com:5000
          username: ${{ secrets.REG_USER }}
          password: ${{ secrets.REG_PASS }}
      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: myregistry.com:5000/myapp:${{ github.sha }}
      - name: Deploy to Swarm
        uses: appleboy/ssh-action@v0.1.5
        with:
          host: ${{ secrets.SWARM_MANAGER }}
          username: ${{ secrets.SSH_USER }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            docker login -u ${{ secrets.REG_USER }} -p ${{ secrets.REG_PASS }} myregistry.com:5000
            docker stack deploy -c /path/to/docker-compose.prod.yml myapp --with-registry-auth

五、镜像安全扫描

在 CI 中集成漏洞扫描,可阻断含高危漏洞的镜像。

5.1 使用 Trivy

bash 复制代码
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy image --severity HIGH,CRITICAL myapp:latest

在 Jenkins 中若扫描失败则终止流水线。

5.2 使用 Docker Scout(官方)

bash 复制代码
docker scout quickview myapp:latest

六、部署策略

6.1 滚动更新(Swarm)

Swarm 服务支持滚动更新,只需在 stack 文件中配置更新策略:

yaml 复制代码
deploy:
  replicas: 5
  update_config:
    parallelism: 2
    delay: 10s
    failure_action: rollback

6.2 蓝绿部署(手动实现)

使用两个环境标签(blue / green),通过负载均衡切换。

bash 复制代码
# 部署新版本 green
docker service update --label-add env=green myapp
# 切换负载均衡器路由到 green
# 验证成功后移除 blue
docker service rm myapp_blue

6.3 金丝雀发布(Istio + Kubernetes)

更复杂的金丝雀发布需要服务网格,不在 Docker Swarm 原生支持范围内,可考虑迁移到 K8s。

七、构建缓存优化

使用 BuildKit:DOCKER_BUILDKIT=1 docker build,支持并行构建和跳过未使用的阶段。

缓存外部依赖:将 package.json / go.mod 先复制,安装依赖,再复制源码。

使用 registry 作为缓存源:--cache-from 参数。

示例优化版 Dockerfile 已在前文提及。

八、清理 CI 环境

避免 CI 节点磁盘被大量旧镜像占满。定期执行:

bash 复制代码
docker system prune -f --filter "until=24h"

或在 GitLab Runner 配置中设置 cleanup 脚本。

九、小结

将 Docker 融入 CI/CD 流水线,可以显著提升交付速度和可靠性。核心要点:

每个阶段使用容器保证一致。

镜像缓存和分层构建加速构建。

安全扫描嵌入流水线。

选择合适的部署策略(滚动更新、蓝绿)。

相关推荐
Patrick_Wilson2 天前
从「改个端口」到 502:Next.js on k8s 的容器端口、Service 映射与 env 覆盖
docker·kubernetes·next.js
Suroy2 天前
DockerView-Go:用 Go 写一个终端 Docker 监控工具,顺便做了个 Web 仪表盘
docker
云恒要逆袭2 天前
运行你的第一个Docker容器
后端·docker·容器
宋均浩3 天前
# Docker 镜像瘦身实战:从 1.2G 到 80MB 的五个优化步骤
ci/cd·docker
程序员老赵4 天前
10 分钟部署 OpenCode:Docker 一键安装,浏览器打开就能用 AI 写代码(附完整命令与排错)
docker·容器·ai编程
WangMingHua1114 天前
LM Studio Docker 部署——本地大模型一键启动
docker
曲幽5 天前
别再用网页翻译看源码了!你的私人翻译神器LibreTranslate,部署避坑指南来了
python·docker·web·pot·translate·libretranslate·arogstranslate
武子康7 天前
调查研究-183 Apple container:Mac 上用轻量 VM 跑 Linux 容器,Swift 会改写本地容器体验吗?
docker·容器·apple
宋均浩8 天前
# GitHub Actions 实战:从零搭建 CI/CD 流水线的 5 个核心配置
ci/cd
Alsn8610 天前
等待学习-学习目录:Docker 容器安全攻防
学习·安全·docker