← 编程返回顶部

CI/CD:GitHub Actions

CI/CD 是通过自动化流程完成代码检查、测试、构建和部署的工程实践。

1. CI 与 CD

概念全称主要作用
CIContinuous Integration持续集成,自动测试和验证代码
CDContinuous Delivery持续交付,保证代码随时可以发布
CDContinuous Deployment持续部署,验证通过后自动发布到生产环境

典型流程:

Developer
    ↓
Git Push / Pull Request
    ↓
GitHub Actions
    │
    ├── Lint / Type Check
    ├── Unit / Integration Tests
    └── Build
           ↓
        CI Passed
           ↓
      Docker Image
           ↓
     Image Registry
           ↓
    Deployment Server
           ↓
    Running Application

CI 负责保证代码质量,CD 负责交付和部署。

CI 并不要求必须自动部署;可以先实现 CI,再逐步增加 CD。

2. GitHub Actions 核心模型

GitHub Actions 是 GitHub 提供的自动化工作流平台。

GitHub Event
     ↓
Workflow
     ↓
Jobs
     ↓
Runner
     ↓
Steps
     ├── uses: Action
     └── run: Shell Command

核心概念:

概念含义
Workflow完整自动化流程,使用 YAML 定义
Event触发 Workflow 的事件
Job一组在同一 Runner 上执行的任务
StepJob 内的单个执行步骤
Runner执行 Job 的机器
Action可复用的自动化步骤
ArtifactWorkflow 产生的文件或构建结果
Secret加密管理的敏感配置

Workflow 文件保存在:

.github/
└── workflows/
    ├── ci.yml
    └── deploy.yml

一个仓库可以定义多个 Workflow。

3. 基本 Workflow

name: CI

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

permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install dependencies
        run: pip install -r requirements.txt

      - name: Run tests
        run: pytest

执行过程:

Push to main / PR to main
             ↓
      Start Workflow
             ↓
   Create Ubuntu Runner
             ↓
      Checkout Code
             ↓
      Install Python
             ↓
   Install Dependencies
             ↓
          pytest
             ↓
       Pass / Fail

这里假设项目依赖及测试环境已经正确配置。如果 Django 使用 PostgreSQL,还需要提供测试数据库服务。

重要 YAML 字段

字段作用
nameWorkflow 或 Step 名称
on触发条件
jobs定义 Job
runs-on选择 Runner
steps定义执行步骤
uses调用现有 Action
run执行 Shell 命令
with传递 Action 参数
env设置环境变量
if条件执行
needsJob 之间的依赖
permissionsGITHUB_TOKEN 权限
concurrency控制并发执行

uses 与 run 的区别:

- uses: actions/checkout@v4

调用已经实现的 Action。

- run: pytest

直接执行命令。

4. Event:Workflow 触发条件

Push

on:
  push:
    branches: [main]

每次向 main 推送代码时触发。

Pull Request

on:
  pull_request:
    branches: [main]

创建或更新目标为 main 的 PR 时触发。

手动触发

on:
  workflow_dispatch:

可以在 GitHub Actions 页面手动运行。

Tag / Release

on:
  push:
    tags:
      - "v*"

例如推送 v1.2.0 时执行发布。

定时任务

on:
  schedule:
    - cron: "0 2 * * *"

使用 UTC 时间,每天计划在 02:00 触发。定时 Workflow 可能发生延迟,并不保证严格准时。

5. Job、Step 与 Runner

一个 Workflow 可以包含多个 Job:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Testing"

  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building"

默认情况下,不同 Job 可以并行执行。

同一个 Job 中的 Steps 通常按顺序执行。

needs:Job 依赖

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - run: pytest

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - run: docker build -t myapp .

表示必须先完成 test,且通常需要成功,才能执行 build。

Test
  ↓
Build
  ↓
Deploy

Job 隔离

每个 GitHub-hosted Runner 上的 Job 通常运行在独立环境中。

因此,不同 Job 不会自动共享本地文件。

如果需要传递构建产物,可以使用 Artifact 或镜像仓库。

6. 实际 CI:Django + React

对于前后端分离项目,可以分别定义 Backend 和 Frontend Job。

name: CI

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

permissions:
  contents: read

jobs:
  backend:
    runs-on: ubuntu-latest

    defaults:
      run:
        working-directory: backend

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
          cache: pip
          cache-dependency-path: backend/requirements.txt

      - run: pip install -r requirements.txt

      - name: Run tests
        run: pytest

      - name: Validate OpenAPI
        run: >
          python manage.py spectacular
          --file openapi.yaml
          --validate
          --fail-on-warn

  frontend:
    runs-on: ubuntu-latest

    defaults:
      run:
        working-directory: frontend

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: "24"
          cache: pnpm
          cache-dependency-path: frontend/pnpm-lock.yaml

      - run: corepack enable

      - run: pnpm install --frozen-lockfile

      - name: Type Check
        run: pnpm exec tsc -b

      - name: Build
        run: pnpm build

这是一个简化示例。实际使用时需要根据目录结构、数据库和环境变量调整。尤其是 pytest 依赖 PostgreSQL 时,需要添加 services 或其他测试数据库配置。

此外,前端 Orval 生成代码应与最新 OpenAPI Schema 保持一致,可以在 CI 中增加生成结果检查。

常见 CI 检查

工具检查内容
RuffPython Lint / Format
pytestDjango 业务和 API 测试
drf-spectacularOpenAPI Schema 验证
TypeScript静态类型检查
ESLintJavaScript / React 代码质量
Vite前端生产构建
Docker Build容器镜像能否成功构建

不必一开始就启用全部检查。建议先保证 pytest、TypeScript 和生产构建能稳定通过。

7. Cache 与 Artifact

Cache:加快构建

例如:

- uses: actions/setup-node@v4
  with:
    node-version: "24"
    cache: pnpm

它可以缓存包管理器下载的依赖,加快后续 Workflow。

也可以使用:

- uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: pip-${{ runner.os }}-${{ hashFiles('requirements.txt') }}

注意:Cache 用于性能优化,不应依赖缓存的存在保证构建正确。

Artifact:保存构建结果

例如:

- uses: actions/upload-artifact@v4
  with:
    name: frontend-dist
    path: frontend/dist

可以保存:

  • 前端构建结果。
  • 测试报告。
  • Coverage 报告。
  • 其他构建产物。

区别:

概念主要用途
Cache加快后续任务
Artifact保存或传递工作流产物
Container Registry存储和分发 Docker 镜像

8. Secrets、Variables 与 Contexts

Secrets

在 GitHub 仓库中:

Settings
  ↓
Secrets and variables
  ↓
Actions

可以配置:

DEPLOY_HOST
DEPLOY_USER
SSH_PRIVATE_KEY

Workflow 读取:

env:
  DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}

Secrets 适合密码、Token、SSH Private Key 等。

Variables

非敏感配置可以使用 Variables:

env:
  APP_ENV: ${{ vars.APP_ENV }}

Contexts

GitHub Actions 提供内置上下文:

${{ github.ref }}
${{ github.sha }}
${{ github.actor }}
${{ github.repository }}
${{ github.event_name }}
${{ secrets.MY_SECRET }}
${{ vars.APP_ENV }}

${{ ... }} 是 GitHub Actions 的表达式语法,不是 Bash 变量语法。

而:

$APP_ENV

通常是 Shell 环境变量。

GITHUB_TOKEN

GitHub 为 Workflow 提供临时的 GITHUB_TOKEN,用于访问 GitHub API 和部分仓库资源。

建议遵循最小权限原则:

permissions:
  contents: read

如果需要推送 GHCR 镜像:

permissions:
  contents: read
  packages: write

9. CD:Docker 镜像发布

对于 Docker Compose 部署,常见 CD 流程:

Merge to main
      ↓
CI Pass
      ↓
Docker Build
      ↓
Push Image to GHCR
      ↓
VPS Pull Image
      ↓
Docker Compose Up
      ↓
Health Check

GHCR

GitHub Container Registry:

ghcr.io/username/sorivel-backend:1.2.0

可以使用 GitHub Actions 构建并推送 Docker 镜像。

示例:

name: Publish Backend

on:
  push:
    tags:
      - "v*"

permissions:
  contents: read
  packages: write

jobs:
  publish:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

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

      - uses: docker/build-push-action@v6
        with:
          context: ./backend
          push: true
          tags: ghcr.io/your-org/sorivel-backend:${{ github.ref_name }}

这里需要替换 your-org,并确保镜像命名和发布权限正确。实际应将发布 Workflow 与 CI 成功条件关联,避免测试失败的代码被发布。

VPS 部署

服务器 Compose 使用镜像:

services:
  backend:
    image: ghcr.io/your-org/sorivel-backend:v1.2.0
    restart: unless-stopped

更新:

docker compose pull backend
docker compose up -d backend

这种方式将镜像构建放在 GitHub Actions,而不是每次在 VPS 上重新构建。

更复杂的自动部署可以通过 SSH、Self-hosted Runner 或其他部署系统实现,但不建议直接在生产服务器上执行不受信任的 PR 代码。

10. Environment 与部署保护

GitHub Actions 支持 Deployment Environment。

例如:

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production

可以为 Production 环境配置:

  • 环境级 Secrets。
  • 环境级 Variables。
  • 审批规则。
  • 分支或 Tag 限制。

某些保护功能取决于仓库类型和 GitHub Plan。

对于生产部署,建议区分:

Development
Staging(可选)
Production

即使只有一台 VPS,也可以使用 Production Environment 管理部署凭据和发布权限。

11. Concurrency:防止并发部署

concurrency:
  group: production-deploy
  cancel-in-progress: false

确保同一个 Concurrency Group 中不会有多个部署同时运行。

cancel-in-progress: false 表示不主动取消已经运行的部署,但新触发的 Pending Run 仍可能取代旧的 Pending Run;它并不提供严格 FIFO 部署队列。

对于 CI,可以使用:

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

新提交可以取消同一分支上尚未完成的旧 CI,减少资源浪费。

12. CI/CD 安全与回滚

安全原则

  1. 使用最小权限的 GITHUB_TOKEN。
  2. Secrets 不写入仓库或 Dockerfile。
  3. 不让不受信任的 PR 访问生产凭据。
  4. 第三方 Actions 优先固定到完整 Commit SHA,提高供应链安全性。
  5. 不随意使用具有高权限 Token 的 pull_request_target 执行 PR 中的不可信代码。
  6. 部署前执行必要的测试和构建检查。

回滚(Rollback)

不要只依赖 latest 标签。

推荐使用明确版本:

sorivel-backend:v1.2.0
sorivel-backend:v1.2.1

如果新版本有问题:

Current: v1.2.1
      ↓
Rollback
      ↓
Previous: v1.2.0

修改镜像版本并重新部署:

docker compose pull backend
docker compose up -d backend

还需要注意:应用镜像回滚不等于数据库回滚。 如果部署同时执行了破坏性 Migration,必须单独设计数据库兼容和恢复策略。

13. CI/CD 的推荐实践

对于单台 VPS + Docker Compose 项目,可以采用三个阶段。

第一阶段:CI

PR / Push
   ↓
pytest
   ↓
Type Check
   ↓
Build

目标:自动检查代码是否可靠。

第二阶段:自动发布镜像

Main / Release Tag
       ↓
CI Passed
       ↓
Docker Build
       ↓
Push to GHCR

目标:构建可部署、可追踪版本的镜像。

第三阶段:自动部署

Approved Release
       ↓
Deploy to VPS
       ↓
docker compose pull
       ↓
docker compose up -d
       ↓
Health Check

目标:让部署可重复、可验证、可回滚。

总结

GitHub Actions 最重要的概念:

分类核心内容
基础结构Workflow、Event、Job、Step、Runner
YAML 配置on、uses、run、needs、if、env
CILint、Test、Type Check、Build
性能Cache、Artifact
安全Secrets、GITHUB_TOKEN、Permissions
CDRegistry、Docker Build/Push、Deployment
生产保障Environment、Concurrency、Health Check、Rollback

GitHub Actions 的核心作用是:当特定事件发生时,在 Runner 中自动执行预先定义好的工作流。

对于日常开发,优先掌握:

  1. 如何根据 Push / PR 触发 Workflow。
  2. 如何编写包含多个 Job 的 YAML。
  3. 如何执行 pytest、TypeScript 和 Vite 构建。
  4. 如何使用 Cache、Secrets 和环境变量。
  5. 如何构建 Docker 镜像并发布到 GHCR。
  6. 如何在 VPS 上部署及回滚。

参考文档