Docker-CI/CD:集成 GitHub Actions 实现自动化构建与部署

Docker-CI/CD:集成 GitHub Actions 实现自动化构建与部署

文章目录

  • [Docker-CI/CD:集成 GitHub Actions 实现自动化构建与部署](#Docker-CI/CD:集成 GitHub Actions 实现自动化构建与部署)
    • 摘要
    • [一、为什么选择 GitHub Actions?](#一、为什么选择 GitHub Actions?)
    • 二、核心流程设计
    • 三、准备工作
      • [3.1 项目结构要求](#3.1 项目结构要求)
      • [3.2 配置 Secrets(敏感信息)](#3.2 配置 Secrets(敏感信息))
    • [四、编写 GitHub Actions 工作流](#四、编写 GitHub Actions 工作流)
    • 五、关键步骤解析
      • [5.1 镜像标签策略](#5.1 镜像标签策略)
      • [5.2 安全扫描为何放在推送后?](#5.2 安全扫描为何放在推送后?)
      • [5.3 部署逻辑:覆盖式更新](#5.3 部署逻辑:覆盖式更新)
    • 六、优化与进阶
      • [6.1 缓存 Docker 层加速构建](#6.1 缓存 Docker 层加速构建)
      • [6.2 多环境分离(推荐)](#6.2 多环境分离(推荐))
      • [6.3 使用自建 Registry(如 Harbor)](#6.3 使用自建 Registry(如 Harbor))
    • 七、常见问题排查
      • [❌ 问题 1:SSH 连接被拒绝](#❌ 问题 1:SSH 连接被拒绝)
      • [❌ 问题 2:Docker Compose 启动失败](#❌ 问题 2:Docker Compose 启动失败)
      • [❌ 问题 3:镜像推送权限不足](#❌ 问题 3:镜像推送权限不足)
    • 八、安全最佳实践回顾
    • 结语

关键字: GitHub ActionsDocker CI/CD自动化部署Docker 镜像构建Trivy 扫描docker-compose 部署DevOps 实战

摘要

"手动 docker build && scp && ssh restart?那是石器时代的运维。"

在现代 DevOps 流程中,一次 git push 就应触发完整的构建、测试、部署链条------而 Docker 正是这条链的核心载体。

你是否经历过这些"痛苦时刻"?

  • 本地开发一切正常,上线后却报错"依赖缺失";
  • 发布新版本要手动登录服务器,停容器、拉镜像、启服务;
  • 团队成员各自打包镜像,版本混乱难以追溯;
  • 测试环境和生产环境配置不一致,Bug 难以复现......

这些问题的根源,在于缺乏标准化的自动化交付流程

GitHub Actions + Docker 的组合,正是解决这些问题的利器。它能让你:

✅ 代码提交即自动构建镜像

✅ 自动运行单元测试与安全扫描

✅ 按分支策略发布到不同环境(dev/staging/prod)

✅ 镜像版本与 Git 提交一一对应,可追溯、可回滚

本文将手把手教你搭建一套完整的 CI/CD 流水线,真正实现"提交即部署"。


一、为什么选择 GitHub Actions?

作为 GitHub 原生 CI/CD 工具,Actions 具有天然优势:

优势 说明
无缝集成 无需额外账号,仓库内直接配置
免费额度高 公开仓库完全免费,私有仓库每月 2000 分钟
生态丰富 官方提供 docker/build-push-actionaws-actions 等成熟 Action
YAML 驱动 流程定义即代码(Infrastructure as Code)

💡 适用场景:中小型项目、开源项目、个人博客、内部工具等。


二、核心流程设计

我们的目标流水线如下:
main 分支 dev 分支 开发者 git push 触发 GitHub Actions 构建 Docker 镜像 运行单元测试 Trivy 扫描漏洞 推送镜像到 Docker Hub SSH 到服务器执行 docker compose pull && up 部署到测试环境

关键原则:

  • main 分支 → 生产环境
  • dev 分支 → 测试环境
  • 每次构建生成带 Git SHA 的镜像标签 (如 myapp:abc1234

三、准备工作

3.1 项目结构要求

确保你的项目包含:

  • Dockerfile(位于根目录或子目录)
  • docker-compose.yml(用于部署)
  • 可运行的测试脚本(如 pytestnpm test

示例结构:

text 复制代码
my-web-app/
├── Dockerfile
├── docker-compose.yml
├── app.py
├── tests/
│   └── test_app.py
└── .github/workflows/ci-cd.yml   ← CI/CD 配置文件

3.2 配置 Secrets(敏感信息)

在 GitHub 仓库中设置以下 Secrets(Settings → Secrets and variables → Actions):

Secret 名称 用途
DOCKERHUB_USERNAME Docker Hub 用户名
DOCKERHUB_TOKEN Docker Hub 访问令牌(非密码!)
SERVER_HOST 生产服务器 IP
SERVER_USER SSH 用户名(如 ubuntu)
SERVER_SSH_KEY 服务器私钥(PEM 格式)

🔒 安全提示:

  • Docker Hub Token 创建路径:Account Settings → Security → New Access Token
  • SSH 私钥需去除密码(或使用 ssh-agent),内容以 -----BEGIN OPENSSH PRIVATE KEY----- 开头

四、编写 GitHub Actions 工作流

创建 .github/workflows/ci-cd.yml

yaml 复制代码
name: CI/CD Pipeline

on:
  push:
    branches: [ "main", "dev" ]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      # 1. 检出代码
      - name: Checkout code
        uses: actions/checkout@v4

      # 2. 登录 Docker Hub
      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      # 3. 构建并推送镜像(带 Git SHA 标签)
      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: |
            your-dockerhub-username/my-web-app:${{ github.sha }}
            your-dockerhub-username/my-web-app:latest-${{ github.ref_name }}

      # 4. 运行测试(可选但推荐)
      - name: Run tests
        run: |
          docker build -t my-web-app-test .
          docker run --rm my-web-app-test pytest tests/

      # 5. 安全扫描(使用 Trivy)
      - name: Scan image for vulnerabilities
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'your-dockerhub-username/my-web-app:${{ github.sha }}'
          format: 'table'
          exit-code: '1'
          severity: 'CRITICAL,HIGH'

      # 6. 部署到服务器
      - name: Deploy to server
        if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev'
        env:
          SERVER_HOST: ${{ secrets.SERVER_HOST }}
          SERVER_USER: ${{ secrets.SERVER_USER }}
          SERVER_SSH_KEY: ${{ secrets.SERVER_SSH_KEY }}
        run: |
          # 创建临时密钥文件
          mkdir -p ~/.ssh
          echo "$SERVER_SSH_KEY" > ~/.ssh/deploy_key
          chmod 600 ~/.ssh/deploy_key

          # 动态生成 docker-compose.override.yml
          ENV_TAG="latest-main"
          if [[ "${{ github.ref }}" == "refs/heads/dev" ]]; then
            ENV_TAG="latest-dev"
          fi

          cat > deploy-compose.yml <<EOF
          version: '3.8'
          services:
            backend:
              image: your-dockerhub-username/my-web-app:$ENV_TAG
          EOF

          # 上传并部署
          scp -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key \
            deploy-compose.yml $SERVER_USER@$SERVER_HOST:/home/$SERVER_USER/app/

          ssh -o StrictHostKeyChecking=no -i ~/.ssh/deploy_key \
            $SERVER_USER@$SERVER_HOST <<'EOF'
            cd /home/ubuntu/app
            docker compose -f docker-compose.yml -f deploy-compose.yml up -d
          EOF

📌 替换 your-dockerhub-username 为你的实际用户名!


五、关键步骤解析

5.1 镜像标签策略

我们使用两种标签:

  • ${``{ github.sha }}:唯一标识每次提交,用于精确回滚;
  • latest-main / latest-dev:便于 Compose 文件引用。

这样既保证可追溯性,又简化部署配置。


5.2 安全扫描为何放在推送后?

虽然也可以扫描本地镜像,但推送后再扫描更贴近真实环境,且 Trivy Action 支持直接拉取远程镜像分析。

若发现高危漏洞,流水线立即失败,阻止问题镜像上线。


5.3 部署逻辑:覆盖式更新

通过 docker-compose.override.yml 机制,动态覆盖镜像标签:

  • 生产服务器上的 docker-compose.yml 保持不变(含网络、卷等定义);
  • CI/CD 仅推送一个轻量级 deploy-compose.yml,指定新镜像;
  • 最终效果 = 基础配置 + 新镜像。

这种方式避免了频繁修改主 Compose 文件,降低出错风险。


六、优化与进阶

6.1 缓存 Docker 层加速构建

build-push-action 中启用缓存:

yaml 复制代码
- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3

- name: Build and push
  uses: docker/build-push-action@v5
  with:
    ...
    cache-from: type=gha
    cache-to: type=gha,mode=max

首次构建较慢,后续提交可复用中间层,速度提升 5~10 倍。


6.2 多环境分离(推荐)

为不同环境创建独立工作流:

  • .github/workflows/deploy-dev.yml → 监听 dev 分支
  • .github/workflows/deploy-prod.yml → 监听 main 分支 + 手动审批

生产部署加入人工确认:

yaml 复制代码
environment:
  name: production
  url: https://your-app.com

并在仓库 Settings → Environments 中配置审批者。


6.3 使用自建 Registry(如 Harbor)

若不想依赖 Docker Hub,可替换为私有仓库:

yaml 复制代码
- name: Log in to Harbor
  uses: docker/login-action@v3
  with:
    registry: harbor.yourcompany.com
    username: ${{ secrets.HARBOR_USER }}
    password: ${{ secrets.HARBOR_PASS }}

镜像标签改为:harbor.yourcompany.com/project/my-app:${``{ github.sha }}


七、常见问题排查

❌ 问题 1:SSH 连接被拒绝

原因:服务器未允许密钥登录,或防火墙限制。

检查

bash 复制代码
# 本地测试
ssh -i your-key.pem ubuntu@your-server-ip

确保 /etc/ssh/sshd_config 包含:

text 复制代码
PubkeyAuthentication yes
PasswordAuthentication no

❌ 问题 2:Docker Compose 启动失败

原因 :服务器缺少 docker-compose.yml 或依赖服务未启动。

建议

  • 在服务器预置完整的 docker-compose.yml
  • 使用 depends_on 确保数据库等先启动;
  • 查看日志:docker compose logs backend

❌ 问题 3:镜像推送权限不足

原因:Docker Hub Token 权限不够,或用户名拼写错误。

验证

  • Token 需勾选 "Read & Write" 权限;
  • 镜像仓库名必须与用户名匹配(如 john/my-app)。

八、安全最佳实践回顾

风险点 防护措施
密钥硬编码 使用 GitHub Secrets
镜像含漏洞 集成 Trivy 扫描
无回滚机制 使用 Git SHA 作为镜像标签
生产误操作 生产部署加人工审批
构建污染 每次构建使用干净 Runner

结语

通过 GitHub Actions 与 Docker 的结合,我们成功将"代码 → 服务"的过程自动化、标准化、安全化。

现在,当你修复一个 Bug 并推送到 main 分支,系统会自动:

  1. 构建新镜像
  2. 运行测试
  3. 扫描漏洞
  4. 更新线上服务

整个过程无需人工干预,且每一步都可审计、可回溯。

这不仅是效率的提升,更是工程可靠性的飞跃


系列总结预告

下一篇(最终篇)→ 《Docker 实战全景图:从开发到生产的完整技术栈梳理》

我们将回顾整个系列,绘制一张涵盖构建、网络、安全、监控、CI/CD 的 Docker 全景图,并给出学习路径建议!


参考资料


相关推荐
z***I3942 小时前
Docker书籍
运维·docker·容器
❀͜͡傀儡师2 小时前
docker 安装WPS
docker·容器·wps
Broken Arrows3 小时前
容器的生命周期以及容器常用的操作命令
docker
西维4 小时前
告别手动部署!Docker + Drone 前端自动化部署指南
前端·ci/cd·docker
hqzing4 小时前
介绍一个容器化的鸿蒙环境
c++·docker
TH_15 小时前
腾讯云-(9)-宝塔面板-Docker下安装RabbitMQ
docker·rabbitmq·腾讯云
yifengyiyufjq6 小时前
Docker 镜像制作教程
java·docker·node.js
凯子坚持 c10 小时前
Docker 容器实战:从镜像管理到私有仓库构建深度解析
java·docker·eureka
Radan小哥16 小时前
Docker学习笔记—day007
笔记·学习·docker