GitHub Actions 实战指南
概述
GitHub Actions 是 GitHub 原生的 CI/CD 平台,通过 YAML 定义 Workflow,在事件驱动(push/PR/release)下自动执行。
核心概念
Workflow(工作流)
└── Job(作业,可并行/串行)
└── Step(步骤)
└── Action(可复用组件) 或 Shell 命令
| 概念 | 职责 | 示例 |
|---|
| Workflow | 一个完整的自动化流程 | .github/workflows/ci.yml |
| Event | 触发条件 | push, pull_request, schedule, workflow_dispatch |
| Job | 在同一个 Runner 上执行的一组 Step | build, test, deploy |
| Step | 最小执行单元 | uses: actions/checkout@v4 或 run: npm test |
| Action | 可复用的步骤组件 | docker/login-action, actions/setup-go |
| Runner | 执行 Job 的机器 | ubuntu-latest, self-hosted |
Job 间的依赖与并行
jobs:
lint: # 无依赖,最先执行
runs-on: ubuntu-latest
steps: [ ... ]
test:
needs: lint # 等 lint 完成
runs-on: ubuntu-latest
steps: [ ... ]
build:
needs: test # 等 test 完成
strategy:
matrix: # 矩阵构建:3 个并行 Job
go-version: ['1.21', '1.22', '1.23']
runs-on: ubuntu-latest
steps: [ ... ]
标准 CI Workflow(Go 项目)
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
GO_VERSION: '1.23'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# ── 代码检查 ──
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: '${{ env.GO_VERSION }}' }
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with: { version: latest }
# ── 测试 ──
test:
needs: lint
runs-on: ubuntu-latest
services:
mysql: # 声明 Service Container
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: testdb
ports: ['3306:3306']
options: >-
--health-cmd "mysqladmin ping -h localhost"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with: { go-version: '${{ env.GO_VERSION }}' }
- name: Run tests
run: go test -v -race -coverprofile=coverage.out ./...
- name: Upload coverage
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage.out
# ── 安全扫描 ──
security:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Trivy scan
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: 'trivy-results.sarif' }
# ── 构建与推送镜像 ──
build-push:
needs: security
if: github.ref == 'refs/heads/main' # 仅 main 分支推送镜像
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # 需要推送 GHCR 权限
steps:
- uses: actions/checkout@v4
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,format=short
type=ref,event=branch
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
关键技巧
1. Context 与 Expressions
# 常用的 Context
${{ github.ref }} # refs/heads/main 或 refs/tags/v1.0
${{ github.sha }} # 完整的 commit SHA
${{ github.event_name }} # push / pull_request / ...
${{ github.repository }} # owner/repo
${{ github.run_id }} # 本次 Workflow 的唯一 ID
# 条件表达式
if: ${{ github.ref == 'refs/heads/main' }}
if: ${{ failure() }} # 前面步骤失败了执行
if: ${{ always() }} # 无论如何都执行(即使失败)
2. Matrix Strategy(矩阵构建)
strategy:
fail-fast: false # 一个失败不取消其他
matrix:
os: [ubuntu-latest, macos-latest]
go-version: ['1.22', '1.23']
# 排除特定组合
exclude:
- os: macos-latest
go-version: '1.22'
3. 缓存加速
# Go modules 缓存
- uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-
# Docker 层缓存(不需要显式配置,直接用 build-push-action 的 gha cache)
# npm/node_modules 缓存
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
4. Secrets 与环境变量
env:
GLOBAL_VAR: 'shared value'
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # 绑定 Environment(需 GitHub 端配置审批策略)
env:
JOB_VAR: 'job-level value'
steps:
- run: echo ${{ secrets.DEPLOY_TOKEN }} # Secret 自动遮蔽
- run: echo $GLOBAL_VAR
- run: echo $JOB_VAR
5. 自定义 Action(复用)
.github/actions/my-action/
├── action.yml
└── script.sh
# action.yml
name: 'My Custom Action'
description: 'Do something'
inputs:
name:
description: 'Your name'
required: true
default: 'World'
outputs:
result:
description: 'Result'
value: ${{ steps.hello.outputs.greeting }}
runs:
using: 'composite'
steps:
- id: hello
run: echo "greeting=Hello, ${{ inputs.name }}" >> $GITHUB_OUTPUT
shell: bash
# 使用自定义 Action
- uses: ./.github/actions/my-action
with:
name: 'CI User'
常用 Actions 速查
| Action | 用途 |
|---|
actions/checkout@v4 | 检出代码 |
actions/setup-go/node/python/java@v5 | 设置语言环境 |
actions/cache@v4 | 缓存依赖 |
actions/upload-artifact@v4 | 上传构建产物 |
actions/download-artifact@v4 | 下载构建产物 |
docker/login-action@v3 | Docker 登录 |
docker/build-push-action@v6 | 构建 + 推送镜像 |
docker/metadata-action@v5 | 生成镜像标签 |
aquasecurity/trivy-action | 安全扫描 |
golangci/golangci-lint-action@v6 | Go Lint |
github/codeql-action | SAST 代码安全分析 |
softprops/action-gh-release@v2 | 创建 GitHub Release |
CI/CD 部署到 K8s 示例
deploy:
needs: build-push
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v4
- name: Set K8s context
uses: azure/k8s-set-context@v4
with:
kubeconfig: ${{ secrets.KUBECONFIG }}
- name: Deploy with Helm
run: |
helm upgrade --install my-app ./helm/chart \
--set image.tag=${{ github.sha }} \
--namespace production
常见问题 / 坑点
| 问题 | 原因 | 解决方案 |
|---|
| Secrets 在 PR from fork 不可用 | 安全策略,防止泄露 | 使用 pull_request_target 事件(需谨慎) |
| 自建 Runner 被标记 offline | 内存/磁盘不足或服务停止 | 监控 Runner 状态 + 配置 ephemeral Runner |
| Docker 构建慢 | 未启用缓存 | cache-from: type=gha, cache-to: type=gha |
| Workflow 超时 | 默认 360 分钟 | timeout-minutes: 30 合理设限 |
| 矩阵构建中一个失败全停 | fail-fast: true | 设 fail-fast: false |
关联知识
参考资源
学习时间
| 阶段 | 时间 | 备注 |
|---|
| 初次学习 | 2026-07-14 | Workflow/Job/Step + 缓存 + Docker + K8s 部署 |
状态: 📖 已掌握
下次复习日期: 2026-08-14