GitHub Actions 完全指南
相关文档:Docker Compose完全指南(/docker-compose-wan-quan-zhi-nan/) Docker高级指南(/docker-gao-ji-zhi-nan/) pytest完全指南(/pytest-wan-quan-zhi-nan/) GitHub Actions 是 GitHub 内置的 CI/CD 平台,通过在仓库的 .github/workflows/ 目录下创建 YAML 文件定义自动化流程。 GitHub Actions 对 YAML 缩进敏感,uses 和 run 必须在同一级: 在 Windows Runner
官方文档:https://docs.github.com/zh/actions
适用版本:GitHub Actions(2026-05-07 核实)
相关文档:Docker Compose完全指南 Docker高级指南 pytest完全指南
1. 基础概念
GitHub Actions 是什么
GitHub Actions 是 GitHub 内置的 CI/CD 平台,通过在仓库的 .github/workflows/ 目录下创建 YAML 文件定义自动化流程。
| 概念 | 说明 |
|---|---|
| Workflow(工作流) | 一个 YAML 文件,定义一套完整的自动化流程 |
| Event(触发事件) | 触发 Workflow 的事件(push、PR、cron 等) |
| Job(作业) | Workflow 中的一个独立任务单元,默认并行运行 |
| Step(步骤) | Job 中的一个操作,按顺序执行 |
| Action(动作) | 可复用的步骤单元(marketplace 有大量现成的) |
| Runner(运行器) | 执行 Job 的服务器(GitHub 托管或自托管) |
免费额度(GitHub 托管 Runner)
| 账户类型 | 免费分钟数 / 月 |
|---|---|
| 个人免费账户 | 2000 分钟(Linux) |
| 公开仓库 | 无限制 |
2. Workflow 文件结构
# .github/workflows/ci.yml
name: CI # Workflow 名称
on: # 触发条件
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test: # Job ID
name: Run Tests # Job 显示名
runs-on: ubuntu-latest # 运行环境
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run tests
run: pytest
3. 触发事件(on)
on:
# 推送到指定分支
push:
branches:
- main
- "release/**" # 通配符
paths:
- "src/**" # 只有 src/ 下的文件变化才触发
paths-ignore:
- "docs/**"
- "*.md"
# Pull Request
pull_request:
types: [opened, synchronize, reopened]
branches: [main]
# 定时任务(cron)
schedule:
- cron: "0 2 * * *" # 每天凌晨 2 点 UTC
# 手动触发
workflow_dispatch:
inputs:
environment:
description: "部署环境"
required: true
default: "staging"
type: choice
options: [staging, production]
# 其他 Workflow 调用
workflow_call:
# 发布 Release
release:
types: [published]
4. Job 配置
jobs:
build:
runs-on: ubuntu-latest # ubuntu-latest / ubuntu-22.04 / windows-latest / macos-latest
# 并发控制:同一 PR 只保留最新的 Workflow 运行
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# 超时限制
timeout-minutes: 30
# 环境变量(Job 级别)
env:
PYTHONPATH: src
DATABASE_URL: sqlite:///test.db
# 矩阵策略:多版本并行测试
strategy:
fail-fast: false # 一个失败不取消其他
matrix:
python-version: ["3.11", "3.12", "3.13"]
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
5. 常用步骤
Checkout 代码
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 获取完整历史(覆盖率比较需要)
设置 Python 环境
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip" # 缓存 pip 依赖
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install -r requirements-dev.txt
缓存依赖
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
restore-keys: |
${{ runner.os }}-pip-
设置 Node.js 环境
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
6. 实用 Workflow 模板
Python CI(测试 + 代码质量)
# .github/workflows/ci.yml
name: Python CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.11", "3.12"]
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: testuser
POSTGRES_PASSWORD: testpass
POSTGRES_DB: testdb
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
- name: Install dependencies
run: pip install -r requirements.txt -r requirements-dev.txt
- name: Lint(Ruff)
run: ruff check src tests
- name: Type check(mypy)
run: mypy src
- name: Run tests with coverage
env:
DATABASE_URL: postgresql+asyncpg://testuser:testpass@localhost:5432/testdb
run: pytest --cov=src --cov-report=xml -v
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: coverage.xml
前端 CI(Lint + 构建 + 测试)
# .github/workflows/frontend-ci.yml
name: Frontend CI
on:
push:
branches: [main]
paths: ["frontend/**"]
pull_request:
paths: ["frontend/**"]
defaults:
run:
working-directory: frontend
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: frontend/package-lock.json
- run: npm ci
- name: Type check
run: npm run type-check
- name: Lint
run: npm run lint
- name: Build
run: npm run build
- name: Test
run: npm run test
Docker 构建 + 推送
# .github/workflows/docker-publish.yml
name: Docker Publish
on:
release:
types: [published]
push:
branches: [main]
jobs:
build-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
# 设置 Docker Buildx(多平台构建)
- uses: docker/setup-buildx-action@v3
# 登录 GitHub Container Registry
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# 生成标签(main 分支 → latest,release → 版本号)
- uses: docker/metadata-action@v5
id: meta
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=sha-
# 构建并推送
- uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha # 使用 GitHub Actions 缓存加速构建
cache-to: type=gha,mode=max
部署到服务器(SSH)
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # 关联 GitHub 环境,可配置审批
steps:
- uses: actions/checkout@v4
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /opt/myapp
git pull origin main
docker compose pull
docker compose up -d --no-deps web
docker compose exec web alembic upgrade head
7. Secrets 与变量
# 使用 Secrets(Settings → Secrets and variables → Actions)
steps:
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: ./deploy.sh
# 使用 Variables(非敏感配置)
- name: Build
env:
APP_VERSION: ${{ vars.APP_VERSION }}
ENVIRONMENT: ${{ vars.ENVIRONMENT }}
run: npm run build
内置变量
| 变量 | 说明 |
|---|---|
github.sha |
触发 Workflow 的 commit SHA |
github.ref |
触发的分支/标签(refs/heads/main) |
github.ref_name |
分支/标签名(main) |
github.actor |
触发者用户名 |
github.event_name |
事件类型(push/pull_request) |
github.repository |
仓库名(owner/repo) |
github.run_id |
本次运行 ID |
runner.os |
运行器 OS(Linux/Windows/macOS) |
8. Job 间数据传递
输出变量
jobs:
build:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get_version.outputs.version }}
steps:
- id: get_version
run: echo "version=$(cat VERSION)" >> $GITHUB_OUTPUT
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- run: echo "Deploying version ${{ needs.build.outputs.version }}"
上传/下载 Artifact
# 上传构建产物
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
retention-days: 7
# 在另一个 job 下载
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
9. 最佳实践
固定 Action 版本,使用 SHA 而非 tag(安全)
# 不推荐(tag 可以被强制推送覆盖)
uses: actions/checkout@v4
# 推荐(SHA 不可变,防止供应链攻击)
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
最小权限原则
permissions:
contents: read # 只读代码
packages: write # 写 GitHub Packages(只有需要时才开)
耗时任务加缓存
# pip、npm、cargo、maven 依赖都应该缓存
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip # 自动缓存
10. 踩坑与注意事项
YAML 缩进问题
GitHub Actions 对 YAML 缩进敏感,uses 和 run 必须在同一级:
# 错误
steps:
- name: test
uses: actions/checkout@v4 # 缩进错误!
# 正确
steps:
- name: test
uses: actions/checkout@v4
services 容器需要时间启动
# PostgreSQL 需要健康检查,不能直接用
services:
postgres:
image: postgres:16
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-retries 5
Windows Runner 换行符问题
在 Windows Runner 上,shell 脚本的换行符可能导致问题,明确指定 shell:
- name: Run script
shell: bash # 强制使用 bash(Windows 上也有)
run: echo "hello"
最佳实践
将机密存入 Repository Secrets,不硬编码:API 密钥、Docker 凭证等敏感信息必须存入 GitHub Secrets(Settings → Secrets and variables → Actions),通过 ${{ secrets.MY_KEY }} 引用,不出现在 YAML 或日志中。
使用 cache action 加速依赖安装:Python pip、Node npm、Go mod 每次都下载会导致 CI 耗时 3–5 分钟,缓存后通常 15–30 秒恢复。
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-${{ hashFiles('requirements.txt') }}
restore-keys: pip-
用 matrix 策略做多版本测试:一次定义,自动在多个 Python/Node 版本上并行运行,比重复写多个 job 简洁。
strategy:
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
部署步骤加 environment 保护:对 production 部署的 job 设置 environment: production,可以配置审批者(required reviewers),防止误推。
用 concurrency 避免同一分支并行部署:PR 多次推送会触发多个 Workflow 同时运行,配置 concurrency 自动取消旧的运行。
concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: true
常见陷阱
陷阱:secrets 在 fork 的 PR 中不可用
现象: 外部贡献者提交 PR 后,CI 中访问 secrets.DOCKER_TOKEN 报错或为空。
原因: 出于安全考虑,fork 仓库触发的 pull_request 事件无法访问父仓库的 secrets,防止恶意 PR 窃取密钥。
解决: 使用 pull_request_target 事件(谨慎使用,有安全风险)或将需要 secrets 的步骤移到需要 merge 后才触发的工作流(push 到 main)。
陷阱:job 间共享文件需要 artifact
现象: Job A 生成了一个构建产物,Job B 需要使用,但 Job B 找不到该文件。
原因: 每个 job 在独立的 runner 实例上运行,文件系统不共享。
解决: Job A 用 upload-artifact 上传,Job B 用 download-artifact 下载。
# Job A
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
# Job B(需声明 needs: [build])
- uses: actions/download-artifact@v4
with:
name: dist
陷阱:workflow 文件语法错误静默失败
现象: 推送后 workflow 没有触发,或 GitHub 显示 workflow 文件错误。
原因: YAML 缩进错误(用 tab 而非空格)、on 关键字不加引号被解析为布尔值、step 的 uses 和 run 同时存在等常见语法错误。
解决: 用 actionlint 本地静态检查 workflow 文件;在 VS Code 中安装 GitHub Actions 扩展实时提示。
# 本地检查
brew install actionlint
actionlint .github/workflows/*.yml