GitHub Actions CI/CD 配置教程:自动化构建、测试与部署
GitHub Actions 是 GitHub 自带的 CI/CD 平台。它真正的价值不是“自动跑一次测试”,而是把构建、验证、发布和回滚变成仓库的一部分,让团队不再依赖人工记忆来完成重复动作。
一、先理解 CI/CD
CI:代码一变更就自动构建和测试
CD:测试通过后自动部署
对中小团队来说,CI/CD 的意义通常是三件事:更早发现问题、更稳定地发版、把部署步骤写成可审计的配置。
1.1 先决定你的流水线目标
不同仓库的目标并不一样。
| 场景 | 主要目标 |
|---|---|
| Web 前端 | 快速验证、自动发布 |
| Node.js API | 测试、构建、镜像发布 |
| 文档仓库 | 质量检查、预览生成 |
| 基础设施代码 | 计划、审批、部署 |
二、核心概念
| 术语 | 含义 |
|---|---|
| Workflow | 自动化流程定义 |
| Job | 工作流中的执行单元 |
| Step | Job 内部的单个动作 |
| Action | 可复用组件 |
| Runner | 运行任务的机器 |
2.1 何时拆 Job
如果某一步失败后不需要重跑整个流程,就应该拆成独立 Job。这样日志更清晰,也更容易并行。
三、推荐的 Node.js 工作流
name: Node.js CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build-test:
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 run lint
- run: npm test
- run: npm run build
3.1 带部署的版本
name: Node.js CI/CD
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
lint:
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 run lint
test:
needs: lint
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
deploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
- name: Deploy to VPS
uses: appleboy/[email protected]
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: 'dist/'
target: '/var/www/app/'
四、Secrets 和服务器准备
在仓库 Settings → Secrets and variables → Actions 中配置:
SERVER_HOST
SERVER_USER
SSH_PRIVATE_KEY
服务器侧通常至少要准备一个稳定的发布目录,以及可重复执行的容器或进程管理方式。
version: '3.8'
services:
app:
build: .
ports:
- '3000:3000'
restart: always
4.1 权限建议
尽量只给 Actions 必要的权限。
| 项目 | 建议 |
|---|---|
contents |
read |
packages |
仅在需要时开启 |
actions |
保持最小化 |
五、最佳实践
- 把 lint、test 和 deploy 拆成独立 Job。
- 缓存依赖,减少重复安装时间。
- 只让 main 分支触发部署,PR 只做验证。
- 对敏感权限使用最小授权原则。
- 文档变更较多的仓库可以对特定路径做条件跳过。
5.1 常见增强项
| 增强项 | 价值 |
|---|---|
| 依赖缓存 | 减少构建时间 |
| 路径过滤 | 只在需要时跑重任务 |
| 环境保护 | 部署前加审批 |
| 并行 Job | 提高吞吐量 |
六、排障建议
git status
先检查本地工作区,再看 Actions 日志,通常能快速判断失败来自代码、依赖还是 Secrets 配置。
6.1 调试顺序
- 看触发条件是否匹配。
- 看 checkout 是否成功。
- 看依赖安装是否失败。
- 看测试是否失败。
- 看部署密钥和目标路径是否正确。
参考:GitHub Actions 官方文档、actions/checkout、actions/setup-node 的说明页。
七、总结
GitHub Actions 让 CI/CD 变得前所未有的简单。与 GitHub 仓库的深度整合意味着无需额外的 CI 服务器,配置都在代码仓库中。从简单的 Lint + Test 开始,逐步增加部署步骤,最终实现完整的自动化 DevOps 流水线。记住:自动化不是目的,目的是让开发流程更可靠、更高效。
7.1 环境和回滚
如果项目已经有 staging 和 production,建议把环境保护也接进来。这样一来,PR 只验证,合并后先经过 staging,再进入 production,回滚也更容易追踪。
| 环境 | 用途 |
|---|---|
| Preview | 预览和评审 |
| Staging | 集成测试和验收 |
| Production | 正式发布 |
回滚最好不是临时手工操作,而是通过固定脚本或容器版本回退来完成。这样你在事故里能先恢复服务,再慢慢查原因。
7.2 矩阵构建和版本发布
如果项目要同时支持多个 Node.js 版本或不同操作系统,可以用 matrix 让测试一次跑多组环境。这样可以提前发现兼容性问题,而不是等用户反馈。
strategy:
matrix:
node: [18, 20]
os: [ubuntu-latest, windows-latest]
发布时还可以把 tag 和 release 挂钩,确保“代码版本”和“上线版本”是一一对应的。对团队来说,这比口头说“这次发的是哪个版本”要可靠得多。
如果团队需要更强的可见性,还可以在部署结束后发通知到 Slack、邮件或群机器人。只要把结果留在仓库里,后续追查发布历史会轻松很多。
另外建议给构建产物设置保留期限,比如保留最近几次成功发布的包。这样一旦回滚或审计,你能直接拿到可验证的二进制,而不是临时再去重新构建一次。
这一步看似细,但在事故恢复时很省时间。
尤其适合高频发版团队。
7.3 维护和排查习惯
建议每隔一段时间检查一次 Secrets、缓存和第三方 Action 版本。CI 不是写完就结束,长期维护同样重要。
| 项目 | 处理建议 |
|---|---|
| Secrets | 定期轮换 |
| 缓存 | 必要时清理 |
| Action | 锁定版本 |
7.4 一个最小可用的发布模板
如果你的团队刚开始做自动化,建议先从“验证 + 部署”两步跑通,而不是一开始就把通知、矩阵和多环境都塞进去。最小可用的目标,是让每次代码合并后都能自动验证,并且在主分支上自动发布一次。
name: Minimal Deploy
on:
push:
branches: [main]
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
deploy:
needs: verify
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
7.5 上线时的最小检查
| 项目 | 检查点 | 说明 |
|---|---|---|
| 触发条件 | 只在 main 上发布 | 避免草稿分支误发 |
| 依赖安装 | npm ci 是否稳定 |
锁定依赖版本 |
| 构建产物 | 是否真的生成成功 | 先验证再部署 |
| 发布路径 | 目标目录是否正确 | 避免覆盖错误目录 |
| 回滚方式 | 是否能快速回退 | 故障时先恢复服务 |
7.6 一个常见故障场景
有些仓库的流程在本地能跑,到了 Actions 上就失败,通常不是“GitHub Actions 不稳定”,而是环境不一致。最常见的差异包括 Node 版本、缺失环境变量、权限不够和脚本依赖本地文件。遇到这种情况,先把日志里的第一条失败命令单独拿出来复现,再逐项缩小范围。
- 先确认运行环境版本。
- 再确认依赖安装是否锁定。
- 然后确认 Secrets 是否齐全。
- 最后确认发布路径和权限。
把这四步固定成团队习惯后,CI/CD 才会从“偶尔能用”变成“可以依赖”。