4、CI/CD 流水线基础:GitHub Actions / YAML 语法、触发条件、Job 与 Step 设计
CI/CD 流水线是现代后端发布的核心引擎。GitHub Actions 作为与代码仓库深度集成的 CI/CD 平台,通过 YAML 声明式配置即可完成构建、测试、部署与回滚。本章将拆解其核心语法、触发策略与任务编排,为后续的 Go 后端发布流水线打下基础。
4.1 YAML 基础语法与 GitHub Actions 结构
GitHub Actions 使用 YAML 1.2 标准,以缩进表示层级关系。一个完整的流水线文件通常包含以下顶层字段:
| 字段 | 必填 | 说明 |
|---|---|---|
name |
否 | 工作流名称,显示在 GitHub 仓库的 Actions 标签页 |
on |
是 | 触发条件,定义何时启动流水线 |
env |
否 | 全局环境变量,作用于所有 Job |
jobs |
是 | 任务集合,每个 Job 运行在独立的 Runner 上 |
以下是一个最小化的 Go 后端 CI 流水线示例:
name: Go CI Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
GO_VERSION: '1.22'
REGISTRY: ghcr.io
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Build
run: go build -o ./bin/app ./cmd/server
- name: Test
run: go test ./... -v -race -count=1
缩进规范:YAML 严格使用空格缩进,禁止使用 Tab。推荐 2 个空格作为一级缩进。字段名与冒号之间必须有一个空格。
4.2 触发条件(on)详解
触发条件决定了流水线何时自动执行。GitHub Actions 支持多种事件类型,按使用频率可分为三类:
4.2.1 分支推送与 PR 触发
最常用的触发方式,适用于代码提交和合并请求场景:
on:
push:
branches:
- main
- 'release/**'
paths-ignore:
- 'docs/**'
- '*.md'
pull_request:
branches:
- main
types: [ opened, synchronize, reopened ]
- branches:支持 glob 模式匹配,
release/**匹配所有 release 子分支。 - paths-ignore:当变更仅涉及文档或 Markdown 文件时,跳过流水线执行。
- types:PR 事件子类型,
synchronize表示 PR 分支有新的推送。
4.2.2 定时与手动触发
| 触发方式 | 配置示例 | 适用场景 |
|---|---|---|
| 定时(cron) | schedule: [ { cron: '0 2 * * *' } ] |
每日凌晨构建、依赖扫描 |
| 手动(workflow_dispatch) | workflow_dispatch: { inputs: { env: { type: choice, options: [staging, prod] } } } |
手动触发部署到指定环境 |
| 完成上游流水线 | workflow_run: { workflows: [ "Build" ], types: [ completed ] } |
多流水线串联,如构建完成后触发部署 |
注意:定时触发使用 UTC 时间。国内时区(UTC+8)需换算,例如
0 2 * * * 对应北京时间上午 10:00。手动触发支持输入参数,可用于选择部署环境或版本号。
4.3 Job 与 Step 设计原则
Job 是流水线的执行单元,Step 是 Job 内的最小操作步骤。合理的 Job/Step 设计直接影响流水线的并行效率与可维护性。
4.3.1 Job 依赖与并行
默认情况下,所有 Job 并行执行。通过 needs 关键字可以建立依赖关系:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: golangci-lint run
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: go test ./... -race
build:
needs: [ lint, test ] # 等待 lint 和 test 都通过
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: go build -o app .
deploy:
needs: [ build ] # 等待 build 完成
runs-on: ubuntu-latest
steps:
- run: echo "Deploying..."
上述流水线的执行流程如下:
4.3.2 Step 复用与矩阵策略
Step 可以通过 uses 引用社区 Action 或本地 Action,避免重复代码。矩阵策略(strategy.matrix)允许在多个版本或环境中并行执行同一 Job:
jobs:
test-matrix:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [ '1.21', '1.22' ]
os: [ ubuntu-latest, windows-latest ]
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Setup Go ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Test on ${{ matrix.os }}
run: go test ./... -v
| 策略参数 | 默认值 | 说明 |
|---|---|---|
matrix |
— | 定义组合维度,每个组合生成一个独立的 Job 实例 |
fail-fast |
true | 当任一矩阵 Job 失败时,取消所有正在运行的矩阵 Job |
max-parallel |
无限制 | 限制同时运行的矩阵 Job 数量,避免资源耗尽 |
4.4 上下文与表达式
GitHub Actions 提供丰富的上下文对象,用于在流水线中动态获取信息:
jobs:
show-context:
runs-on: ubuntu-latest
steps:
- name: Print GitHub context
run: |
echo "Event name: ${{ github.event_name }}"
echo "Branch: ${{ github.ref_name }}"
echo "Commit SHA: ${{ github.sha }}"
echo "Runner OS: ${{ runner.os }}"
- name: Conditional step
if: github.ref_name == 'main'
run: echo "This step only runs on main branch"
常用上下文:
github— 仓库、分支、PR、事件等元数据env— 环境变量secrets— 加密密钥,用于敏感信息(如 Docker 密码)steps— 前序 Step 的输出runner— Runner 操作系统、架构等信息
4.5 流水线可视化与调试
GitHub Actions 提供内置的可视化界面,但理解其底层执行模型有助于排查问题。以下是一个典型的 Step 执行生命周期:
4.6 最佳实践与避坑指南
- Step 命名清晰:每个 Step 的
name字段应描述其功能,便于在日志中快速定位。 - 避免硬编码:使用
env或vars上下文管理版本号、路径等可变值。 - 缓存依赖:Go 模块依赖可使用
actions/cache缓存~/.cache/go-build和vendor目录,加速后续构建。 - Job 粒度控制:将构建、测试、部署拆分为独立 Job,利用
needs控制依赖,避免单 Job 过长导致超时。 - 条件执行:使用
if条件控制 Step 是否执行,例如仅在 main 分支上触发部署。
常见陷阱:
- YAML 布尔值歧义:
on字段中的true/false必须加引号,否则可能被解析为布尔类型。 - Secrets 泄露:不要在日志中打印
${{ secrets.* }},GitHub 会自动屏蔽,但建议在 Step 中明确标记为敏感。 - 矩阵爆炸:矩阵组合过多会导致大量并发 Job,消耗免费额度或 Runner 资源。使用
max-parallel限制并行数。