GitHub Actions CI/CD:从零开始构建、测试和部署工作流
学习如何为持续集成和部署配置 GitHub Actions。涵盖触发器、作业、矩阵、密钥、缓存、Docker 以及真实世界的工作流示例。
GitHub Actions 将每次推送、拉取请求和合并都转化为自动化流水线——运行测试、构建产物、扫描漏洞并部署到生产环境。这是一个直接内置于代码仓库中的 CI/CD 平台,无需管理任何基础设施。
GitHub Actions 的工作原理
每个工作流都是 .github/workflows/ 目录下的一个 YAML 文件。当触发事件发生时,GitHub 会启动一台全新的虚拟机,运行你的作业并报告结果——整个过程在几秒内完成。
推送到 main
↓
工作流触发
↓
作业:构建与测试(ubuntu-latest)
├── 步骤 1:检出代码
├── 步骤 2:安装 Node.js
├── 步骤 3:npm ci
├── 步骤 4:npm test
└── 步骤 5:npm run build
↓
✅ 所有检查通过
你的第一个工作流
创建 .github/workflows/ci.yml:
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm test
- run: npm run build
就这些。现在每次推送到 main 以及每个 PR 都会自动运行你的测试套件。
触发器:工作流的运行时机
代码事件
on:
push:
branches: [main, develop]
paths: ['src/**', 'package.json'] # 仅在这些文件变更时运行
pull_request:
types: [opened, synchronize]
定时执行(cron)
on:
schedule:
- cron: '0 6 * * 1' # 每周一 UTC 时间 6:00
手动触发
on:
workflow_dispatch:
inputs:
environment:
description: '部署目标'
required: true
type: choice
options: [staging, production]
这会在 GitHub UI 中添加一个"运行工作流"按钮,供你选择参数。
可复用工作流
on:
workflow_call:
inputs:
node-version:
type: string
default: '20'
在另一个工作流中使用 uses: ./.github/workflows/reusable.yml 调用它。
作业与步骤
并行作业
作业默认并行运行:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
build:
runs-on: ubuntu-latest
needs: [lint, test] # 等待两者均通过
steps:
- uses: actions/checkout@v4
- run: npm run build
矩阵策略——跨版本测试
在多种配置下运行相同的作业:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
这将创建 6 个并行作业(3 个版本 × 2 个操作系统)。
密钥与环境变量
使用密钥
在 Settings → Secrets and variables → Actions 中存储敏感值:
steps:
- name: 部署
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: ./deploy.sh
密钥在日志中会被屏蔽,且不会暴露给 fork 仓库。
环境变量
# 工作流级别
env:
NODE_ENV: production
jobs:
build:
# 作业级别
env:
CI: true
steps:
- name: 构建
# 步骤级别
env:
VITE_API_URL: https://api.example.com
run: npm run build
缓存以加快构建速度
不使用缓存时,每次运行都需要从头下载所有依赖。使用缓存可将构建时间缩短 50-80%:
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm # 内置 npm 缓存
# 或手动为其他工具配置缓存
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
产物:在作业之间共享数据
从一个作业上传构建输出,在另一个作业中下载:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: dist
- run: ./deploy.sh
真实世界工作流示例
Docker 构建与推送
name: Docker
on:
push:
tags: ['v*']
permissions:
packages: write
jobs:
docker:
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@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
cache-from: type=gha
cache-to: type=gha,mode=max
部署到 Cloudflare Pages
name: 部署
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci && npm run build
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
command: pages deploy dist --project-name=my-site
发布版本并生成更新日志
name: 发布
on:
push:
tags: ['v*.*.*']
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 生成更新日志
run: |
git log $(git describe --tags --abbrev=0 HEAD^)..HEAD \
--pretty=format:"- %s" > CHANGELOG.md
- uses: softprops/action-gh-release@v2
with:
body_path: CHANGELOG.md
generate_release_notes: true
条件执行
控制步骤和作业的运行时机:
steps:
- name: 部署到生产环境
if: github.ref == 'refs/heads/main'
run: ./deploy-prod.sh
- name: 部署到预发布环境
if: github.event_name == 'pull_request'
run: ./deploy-staging.sh
- name: 失败时发送通知
if: failure()
run: curl -X POST ${{ secrets.SLACK_WEBHOOK }} -d '{"text":"构建失败!"}'
安全最佳实践
1. 将 Action 版本固定到 SHA
# ❌ 可变标签——可能被篡改
- uses: actions/checkout@v4
# ✅ 固定到精确的提交 SHA
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
2. 使用最小权限原则
permissions:
contents: read # 只授予必要的权限
packages: write
3. 切勿输出密钥
# ❌ 绝对不要这样做
- run: echo ${{ secrets.API_KEY }}
# ✅ 使用环境变量
- env:
API_KEY: ${{ secrets.API_KEY }}
run: ./script-that-uses-api-key.sh
4. 限制来自 fork 的 PR 权限
on:
pull_request_target: # 在基础分支的上下文中运行
types: [opened, synchronize]
调试失败的工作流
- 查看日志 — 点击任何失败的步骤查看完整输出
- 添加调试日志 — 将密钥
ACTIONS_STEP_DEBUG设置为true - 使用
act本地运行 — 通过 nektos/act 在本机运行工作流 - SSH 连接到运行器 — 使用
mxschmitt/action-tmate进行交互式调试
可视化构建工作流
不想手写 YAML?使用我们的 GitHub Actions 生成器 通过可视化界面构建工作流,提供 Node.js、Python、Docker、部署等模板,并可下载生产就绪的 YAML 文件。
总结
GitHub Actions 为你提供了直接内置于代码仓库的 CI/CD 能力:
- 从简单开始 — 一个包含构建和测试的工作流文件
- 添加缓存 — 使用
actions/cache或内置语言缓存缩短构建时间 - 使用矩阵 — 跨版本和操作系统进行测试
- 保护密钥 — 永远不要硬编码,始终使用加密密钥
- 自动化一切 — 发布、部署、安全扫描、定时任务
最好的 CI/CD 流水线,是那种每次提交都能自动运行、无需你费心的那种。配置一次,剩下的交给 GitHub 处理。