第十九篇:《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 流水线,可以显著提升交付速度和可靠性。核心要点:

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

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

安全扫描嵌入流水线。

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

相关推荐
todoitbo2 小时前
群晖NAS部署JmalCloud:Docker安装、文件管理、博客与公网访问完整教程
运维·docker·容器
是枚小菜鸡儿吖8 小时前
Home Assistant跨品牌智能家居教程:Docker部署、米家接入、vivo桥接与远程访问
docker·容器·智能家居
螺蛳粉 螺蛳粉11 小时前
第 02 篇:镜像分层与 containerd 2.x 实战:SystemdCgroup 与 pause 镜像配置踩坑(底座认知 02)
docker·云原生·容器·kubernetes·etcd·containerd·kube-apiserver
wefg112 小时前
【Docker】镜像相关指令
运维·docker·容器
java_logo13 小时前
Docker 部署 DPanel:轻松搭建轻量容器管理平台
运维·docker·容器·podman·容器管理·dpanel·轩辕镜像
死磕音视频13 小时前
Open WebUI 入门:用 Docker 装上本地对话界面并连接 Ollama
docker·ollama·本地大模型·open webui
分布式存储与RustFS13 小时前
CI 老被 Docker Hub 的 429 卡住,自建 Registry 把镜像搬进内网
运维·docker·开源·镜像仓库·对象存储·ci·rustfs
n1121214 小时前
Docker 容器时区错 8 小时:3 个坑
运维·docker·容器·故障排查·服务器运维·容器时区
小白的码BUG之路14 小时前
K8s -- 搭建过程中经常遇到的问题
云原生·容器·kubernetes
慈云数据15 小时前
用 DSH 辅助部署一个网站监控平台:Uptime Kuma + Docker 实战
运维·docker·容器