手动部署 → 凌晨 3 点修 bug → 一气之下把整个流程塞进 GitHub Actions,3 分钟搞定。
引言
去年接手一个遗留项目,发布流程是纯手动的:git pull → 本地跑 pytest → 手动打包 → scp 上传服务器 → ssh 重启。三步一检查,一步错了从头来。
有一次依赖没同步,线上挂了 40 分钟。那之后我把整套流程迁移到了 GitHub Actions,现在 push 代码到 main 分支,测试、构建、部署全自动完成。
这篇文章不是 GitHub Actions 的入门教程------官方文档已经够好了。我想分享的是实际项目中踩过坑之后沉淀下来的 5 个配置模式,覆盖了从"能跑"到"生产级"的关键步骤。每个配置都可以直接复制,改个分支名就能用。
1. 基础骨架:push 自动跑测试 + 失败通知
任何 CI 的起点都是自动化测试。下面是一个可以直接用的 Python 项目测试 workflow:
yaml
# .github/workflows/test.yml
name: Run Tests
on:
push:
branches: [main, dev]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- 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
pip install pytest pytest-cov
- name: Run tests
run: pytest --cov=src --cov-report=term-missing
几个值得注意的点:
- 双触发器
push+pull_request:push保证你自己的分支变更被验证,pull_request保证别人提的 PR 自动跑测试。没过审的代码根本合不进main。 pytest --cov生成覆盖率报告,在 PR 页面直接看哪些行没覆盖到。runs-on: ubuntu-latest是目前性价比最高的 runner,启动快,免费额度够用。如果你的项目依赖 Windows 特定功能,可以换成windows-latest(但注意 Windows runner 消耗的免费分钟数是 Linux 的 2 倍)。
进阶:加失败通知
测试挂了不能靠人盯着看。用 webhook 推送到企业微信/钉钉/Slack:
yaml
- name: Notify failure
if: failure()
run: |
curl -X POST "${{ secrets.WECOM_WEBHOOK }}" \
-H "Content-Type: application/json" \
-d '{"msgtype":"text","text":{"content":"❌ CI 测试失败:${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}}'
把 webhook URL 存在 GitHub Secrets(Settings → Secrets and variables → Actions)里,不要硬编码。failure() 是 GitHub Actions 的内置条件函数,只有前面某一步挂了才会执行。
2. Matrix 策略:一行配置覆盖 N 个环境
在实际项目中,"我本地能跑"不等于"CI 上能跑","Python 3.10 能跑"不等于"3.12 能跑"。提前发现环境兼容性问题,靠 Matrix:
yaml
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- run: pip install -r requirements.txt
- run: pytest
3 个 Python 版本 × 2 个操作系统 = 6 个 job 并行跑,总耗时约等于最慢那个 job 的时间。
text
test (3.10, ubuntu) ✅ PASSED
test (3.10, windows) ✅ PASSED
test (3.11, ubuntu) ✅ PASSED
test (3.11, windows) ✅ PASSED
test (3.12, ubuntu) ✅ PASSED
test (3.12, windows) ❌ FAILED
关键配置:
fail-fast: false:一个 job 挂了不取消其他 job。默认是true,一个失败全部终止------这在 Matrix 场景下很蠢,因为你希望看到所有环境的完整结果。- Matrix 变量在 steps 里用
${{ matrix.xxx }}引用,setup-python 会根据矩阵变量自动选择版本。 - 可以 Matrix 更多维度 :比如
db: [postgres, mysql],适合测不同数据库兼容性。但注意 job 数量是指数级增长的------4 个维度 × 3 个值 = 81 个 job,免费额度可能不够。
如果你的项目只支持一个 Python 版本,至少加上
os: [ubuntu-latest, windows-latest]。Windows 路径分隔符、换行符、文件权限问题,是跨平台 bug 的第一来源。
3. Cache 策略:把 CI 时间从 5 分钟压到 30 秒
每次 CI 都从零安装依赖是最常见的性能浪费。GitHub Actions 提供了 actions/cache@v4,原理很简单:把指定目录打个快照,下次 key 不变就直接恢复。
yaml
- name: Cache pip packages
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Cache virtual environment
uses: actions/cache@v4
with:
path: .venv
key: ${{ runner.os }}-venv-${{ hashFiles('requirements.txt') }}
- name: Install dependencies
run: pip install -r requirements.txt
缓存策略解析:
| 缓存层 | 路径 | 作用 |
|---|---|---|
| pip cache | ~/.cache/pip |
缓存下载的 .whl 包,避免重复下载 |
| venv cache | .venv |
缓存已安装的虚拟环境,跳过安装步骤 |
两级缓存叠加,requirements.txt 不变时 pip install 直接跳过------CI 时间从 5 分钟压到 30 秒。
Key 设计原则:
- 用
hashFiles('requirements.txt')做 key 的一部分:依赖文件变了自动刷新缓存。 restore-keys做降级匹配:精确 key 没命中时(比如新增了一个依赖),用前缀匹配恢复最近一次缓存,只增量安装新包。- 跨平台注意 :pip cache 在 Windows 上是
~\AppData\Local\pip\Cache,在path里写成~/.cache/pip,actions/cache 会自动处理路径映射。但如果缓存一直 miss,检查一下路径是否正确。
缓存总大小限制 10GB(GitHub 免费计划),超过后旧的缓存会被自动驱逐。如果你用 Mono-repo 多语言项目,注意控制缓存体积------可以给每种语言单独设一个 cache step。
4. Artifacts + Environments:测试→构建→部署的完整链路
测试通过了,下一步是部署。GitHub Actions 的 job 之间是隔离的------每个 job 跑在独立的虚拟机里,文件不共享。传递产物的机制是 Artifacts ;控制部署流程的机制是 Environments。
4.1 Artifacts:job 间传文件
yaml
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install -r requirements.txt
- run: pytest --junitxml=report.xml
- name: Upload test report
uses: actions/upload-artifact@v4
with:
name: test-report
path: report.xml
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- name: Download test report
uses: actions/download-artifact@v4
with:
name: test-report
- run: cat report.xml
needs: test是关键:部署 job 必须等测试 job 全部通过才会执行。测试挂了,部署根本不会触发。- Artifacts 保留 90 天(默认),可以在 Actions 页面下载。
- v4 版本相比 v3 性能提升明显,大文件上传不再超时。
4.2 Environments:分级部署 + 审批门禁
dev(自动) → staging(自动) → production(需要手动审批)
yaml
deploy-staging:
needs: test
runs-on: ubuntu-latest
environment: staging
steps:
- run: echo "Deploying to staging..."
deploy-prod:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production
steps:
- run: echo "Deploying to production..."
在仓库 Settings → Environments 中配置:
| 环境 | 审批 | 保护分支 | 适用场景 |
|---|---|---|---|
staging |
不需要 | 无 | 自动部署,快速验证 |
production |
需要手动 Approve | 仅 main 分支 |
生产发布有人审核 |
还可以给 Environment 绑定独立的 Secrets------staging 和 production 用不同的数据库密码、API 密钥,互不污染。
5. Reusable Workflow:一套配置全团队复用
当一个组织有 5 个、10 个、20 个微服务仓库时,每个仓库复制粘贴一份 CI 配置是维护噩梦。GitHub Actions 支持 Reusable Workflow------定义一个公共 workflow,其他仓库直接引用。
定义公共 workflow(.github/workflows/_python-ci.yml):
yaml
name: Reusable Python CI
on:
workflow_call:
inputs:
python-version:
required: false
type: string
default: "3.12"
secrets:
WECOM_WEBHOOK:
required: false
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
- run: pip install -r requirements.txt
- run: pytest
各服务引用(service-a/.github/workflows/ci.yml):
yaml
name: Service A CI
on: [push]
jobs:
ci:
uses: ./.github/workflows/_python-ci.yml
with:
python-version: "3.12"
secrets:
WECOM_WEBHOOK: ${{ secrets.WECOM_WEBHOOK }}
最佳实践:
- 文件名以下划线开头(
_python-ci.yml),约定俗成表示"内部 workflow,不直接触发"。 - 通过
inputs暴露可配置参数(Python 版本、Node 版本等),各服务按需覆盖。 - Secrets 不会自动传递,需要在调用方显式声明
secrets: XXX: ${{ secrets.XXX }}------这是一个安全设计。 - Reusable workflow 必须放在
.github/workflows/目录下,且调用方仓库需要actions: read权限。
完整流水线
上面 5 个模式拼在一起,就是一条可以直接上生产的 CI/CD pipeline:
yaml
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
- run: pip install -r requirements.txt
- run: pytest --junitxml=report.xml
- uses: actions/upload-artifact@v4
with:
name: report-${{ matrix.python-version }}
path: report.xml
deploy-staging:
needs: test
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v4
- run: |
scp -r dist/* user@staging-server:/app/
ssh user@staging-server 'systemctl restart myapp'
deploy-prod:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- run: |
scp -r dist/* user@prod-server:/app/
ssh user@prod-server 'systemctl restart myapp'
执行流程:push main → 9 个测试 job 并行 → 全部通过 → 自动部署 staging → 手动 Approve → 部署 production。
总结
| 配置 | 核心概念 | 解决的问题 |
|---|---|---|
| 自动测试 + 通知 | on: [push, pull_request] + webhook |
每次 push 自动验证,失败即时通知 |
| Matrix | strategy.matrix |
多版本/多系统兼容性,一个配置覆盖 |
| Cache | actions/cache@v4 + hashFiles |
重复构建加速,依赖变更自动刷新 |
| Artifacts + Environments | needs + environment |
job 间传产物,环境分级 + 审批门禁 |
| Reusable Workflow | workflow_call |
消除重复配置,团队级 CI 标准化 |
这套配置在我们团队跑了半年。发布频率从"两周憋一个大版本"变成"一天发三次",回归测试从 40 分钟压到 6 分钟。
如果你在搭建 CI/CD 过程中遇到坑,欢迎在评论区交流。
参考链接:
本文发表于 2026 年 6 月,文中配置基于 GitHub Actions 当前最新版本。如果本文对你有帮助,欢迎点赞、收藏、关注。