GitHub Actions 使用教程:从自动测试到镜像发布
GitHub Actions 根据仓库事件运行自动化工作流。代码提交可以触发测试,标签可以触发制品发布,定时计划可以运行维护脚本,人工按钮可以执行受控任务。最短实践路径是在仓库中创建 .github/workflows/ci.yml,让 Pull Request 和默认分支的提交执行项目已有的安装、测试与构建命令。
本文依据 2026-09-17 核对的 GitHub 官方文档和官方 Action Release 编写。示例完成了结构、YAML 与权限静态检查,没有创建远程测试仓库,也没有消耗 Actions 用量、推送镜像或操作生产环境。因此验证等级为 documented,线上事件、组织策略、账单与部署结果仍需在目标仓库验收。
文中的 Action 主版本面向 GitHub.com 和 GitHub Enterprise Cloud。GitHub Enterprise Server 的内置服务和可用 Action 版本跟随实例版本,不能直接照搬本文的 upload-artifact@v7;GHES 管理员与使用者应以对应实例版本文档为准。
核心模型
一条工作流可以拆成五层:
事件 event
-> 工作流 workflow
-> 作业 job
-> 运行器 runner
-> 步骤 step- Event:
push、pull_request、workflow_dispatch、schedule、Release 等触发条件。 - Workflow:位于
.github/workflows/的 YAML 文件,一个仓库可以有多个。 - Job:一组在同一 Runner 上执行的步骤。多个 Job 默认并行,
needs可以建立依赖。 - Runner:执行 Job 的机器。GitHub 提供托管 Runner,也支持自托管 Runner。
- Step:Job 内顺序执行的命令或 Action。
run执行 Shell 命令,uses调用可复用 Action。
GitHub Actions 不会自动修复项目构建。CI 应调用本地已经稳定的测试、检查和构建命令;本地命令没有确定退出码时,工作流也无法可靠判断成败。
准备仓库
开始前确认:
- 能向目标仓库提交分支和 Pull Request。
- 项目在本地可以通过锁文件完成依赖安装。
- 测试和构建命令失败时返回非零退出码。
- 仓库没有把令牌、密码、私钥或生产配置写进源码。
- 组织或仓库策略允许使用 GitHub Actions 和所选 Action。
- 自托管 Runner 已升级到
v2.327.1或更高版本。本文使用的当前 Action 主版本采用 Node.js 24 Action Runtime;GitHub 托管 Runner 由 GitHub 维护,自托管 Runner 的版本、补丁和运行环境由使用者负责。
示例使用 Node.js 项目,要求仓库已有 package.json、package-lock.json,并定义 npm test 与 npm run build。其他语言保留相同结构,替换运行环境与命令即可。
创建第一个 CI
在仓库中新建 .github/workflows/ci.yml:
name: CI
on:
pull_request:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build
run: npm run build提交分支并创建 Pull Request 后,打开仓库 Actions 页面或 Pull Request 的 Checks 区域。成功信号包括:
- 名为
CI的工作流被触发。 testJob 使用预期提交运行。- 安装、测试和构建步骤全部显示成功。
- 失败的测试会让 Job 失败,而不是被脚本吞掉。
- 向
main合并后,push事件再次运行同一套检查。
如果默认分支不是 main,应把 branches 改成真实分支名。workflow_dispatch 文件只有进入默认分支后,才会稳定出现在手工运行入口中。
阅读工作流 YAML
name 与 on
name 是 Actions 页面中的工作流名称。on 决定触发条件,可以同时声明代码事件、人工触发和定时计划。
on:
pull_request:
paths:
- "src/**"
- "package.json"
- "package-lock.json"
push:
tags:
- "v*"路径过滤能减少无关运行,但也可能让分支保护等待一个没有被触发的必需检查。把工作流设为必需检查前,应验证文档-only PR、重命名和删除文件等分支。
jobs 与 needs
每个 Job 通常获得独立 Runner,不自动继承其他 Job 的工作目录。下面的 build 只在 test 成功后执行:
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: npm test
build:
needs: test
runs-on: ubuntu-latest
steps:
- run: npm run build真实项目中,两个 Job 都需要自行 checkout 和安装依赖,或者由上游上传构建产物供下游下载。不要假设文件会跨 Runner 保留。
run 与 uses
run 适合项目自有命令:
- name: Lint
run: npm run lintuses 会执行另一个仓库或本地目录提供的 Action:
- name: Checkout repository
uses: actions/checkout@v7第三方 Action 本质上是 Runner 上执行的代码。普通教程使用稳定主版本便于阅读;高风险生产工作流应审查源码并固定完整提交 SHA,再通过 Dependabot 跟踪升级。
常用触发方式
| 目标 | 事件 | 主要边界 |
|---|---|---|
| Pull Request 检查 | pull_request | Fork PR 通常拿不到仓库 Secret |
| 默认分支持续集成 | push | 配合 branches、tags、paths 控制范围 |
| 人工补跑或维护 | workflow_dispatch | 可以定义输入;入口通常要求工作流已在默认分支 |
| 定时任务 | schedule | 使用 POSIX Cron,在默认分支运行,繁忙时可能延迟 |
| 发布流程 | release 或 tag push | 应限制写权限、Environment 和制品来源 |
| 外部系统触发 | repository_dispatch | 调用方认证、事件数据和重放需要额外治理 |
定时任务不适合秒级调度、严格结算或必须准点执行的生产任务。可以避开整点,并保留 workflow_dispatch 作为补跑入口:
on:
schedule:
- cron: "17 */6 * * *"
timezone: "Asia/Shanghai"
workflow_dispatch:复制旧教程时要特别检查时区支持和默认分支限制。当前配置应以 GitHub 的事件文档为准。
矩阵与缓存
矩阵适合验证多个运行环境:
strategy:
fail-fast: false
matrix:
node-version: [22, 24]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node-version }}
cache: npm
- run: npm ci
- run: npm test缓存用于复用依赖下载,不是构建制品,也不能代替 npm ci。缓存键应包含锁文件哈希和影响依赖兼容性的环境信息。来自不可信分支的缓存还涉及污染风险,高权限发布 Job 不应盲目信任低权限上下文生成的缓存。
保存构建产物
Artifact 用来保留日志、测试报告、覆盖率报告或构建结果,也可以在 Job 之间传递文件:
- name: Build
run: npm run build
- name: Upload build artifact
uses: actions/upload-artifact@v7
with:
name: web-dist
path: dist/
if-no-files-found: error
retention-days: 7成功后在工作流运行详情页应能看到 web-dist。上传前确认 dist/ 只包含计划共享的文件,不包含 .env、私钥、调试转储或包管理器凭据。
actions/upload-artifact@v4+ 当前不支持 GitHub Enterprise Server,本文的 @v7 示例只用于 GitHub.com 和 GitHub Enterprise Cloud。GHES 应按照实例版本支持矩阵选择 Artifact Action,不能仅把版本号降级后假定其余权限和保留策略完全相同。
Cache 与 Artifact 的区别:
| 能力 | Cache | Artifact |
|---|---|---|
| 主要目的 | 加快后续运行 | 保存和传递本次运行结果 |
| 典型内容 | 包管理器下载缓存 | 构建目录、报告、日志 |
| 是否代表制品 | 否 | 可以,但仍需校验来源与完整性 |
| 常见使用者 | 后续工作流运行 | 人员或下游 Job |
使用 GITHUB_TOKEN
GitHub 为每个 Job 提供临时 GITHUB_TOKEN。权限受仓库、组织、事件来源和工作流 permissions 共同约束。只读 CI 可以采用:
permissions:
contents: read需要写入 GHCR 时再给对应 Job 增加 packages: write。显式设置部分权限后,未列出的权限会变成 none;遇到 403 时应检查实际 API 所需权限,不要直接改成 write-all。
工作流可以通过 ${{ secrets.GITHUB_TOKEN }} 使用临时令牌,部分官方示例也使用 ${{ github.token }}。不要把令牌拼进远程 URL、命令参数或日志。GitHub 会遮罩部分已知 Secret,但遮罩不能覆盖所有编码、拆分和外部返回值。
管理 Secrets 与环境
Secret 可以配置在仓库、Environment 或组织层级。普通参数优先使用 Variables;只有敏感值才进入 Secrets。需要部署时,可以建立 staging 或 production Environment,并配置允许分支、审批者、等待时间和环境级 Secret。
Fork Pull Request 和 Dependabot Pull Request 通常无法读取普通仓库 Secret,写权限也会收紧。PR 阶段应执行不需要秘密的构建和测试;发布 Job 放在受保护的默认分支、tag、Release 或人工触发流程中。
支持 OpenID Connect 的云平台应优先使用 id-token: write 换取短期凭据。云端信任策略仍要限制仓库、分支、环境、受众和可执行操作,不能只因为凭据是短期的就放宽权限。
发布镜像到 GHCR
下面的工作流在推送 v* tag 时构建镜像并发布到 GitHub Container Registry。仓库需要包含可构建的 Dockerfile。
代码块使用当前官方 Action 的稳定主版本,便于展示完整链路。生产发布应把每个 uses 替换成经过审阅的完整提交 SHA,并让 Dependabot 提交后续升级,而不是长期信任可移动标签。
name: Publish container
on:
push:
tags: ["v*"]
permissions:
contents: read
packages: write
jobs:
publish:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- uses: docker/setup-buildx-action@v4
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Generate image metadata
id: meta
uses: docker/metadata-action@v6
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=ref,event=tag
type=sha
- name: Build and push
uses: docker/build-push-action@v7
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}创建 tag 前先在普通 CI 中验证 Dockerfile 构建。发布后检查:
- 工作流使用预期 tag 和提交。
- Package 页面出现 tag 与提交派生标签。
- 镜像可见性符合预期。
- 使用镜像摘要拉取后能启动并通过健康检查。
- 失败发布不会覆盖已知正常版本,回滚时可以重新部署旧摘要。
若组织策略禁止创建 Package、默认 GITHUB_TOKEN 权限不足或仓库与 Package 关联异常,登录成功也不代表推送一定成功。按官方镜像发布文档核对包权限与归属。
安全基线
不执行不可信 PR 代码
pull_request_target 在基础仓库上下文运行,可能获得写权限与 Secret。不要在该事件中 checkout PR head、安装 PR 修改的依赖或执行 PR 脚本。需要评论、标签等维护操作时,把权限和步骤限制在 GitHub API 操作内。
控制第三方 Action
- 优先选择 GitHub、语言工具链或目标平台维护的官方 Action。
- 检查发布者、仓库、维护状态、许可证、权限需求与安全公告。
- 高风险工作流固定完整提交 SHA。
- 开启 Dependabot 的
github-actions更新。 - 不使用来源不明的
@main、Fork 或复制粘贴脚本。
隔离自托管 Runner
自托管 Runner 能访问更多网络、文件和凭据,也需要自行承担补丁、隔离、容量、清理与审计。不要让不可信 Fork PR 在能访问内网或生产凭据的持久化 Runner 上执行。必须使用时,优先采用短生命周期、任务后销毁的隔离 Runner。
计费与用量
公开仓库、私有仓库、标准托管 Runner、大型 Runner、Artifact 存储和缓存有不同计费与额度规则。固定分钟数、倍率和免费额度会变化,不能从旧文章推断当前账单。
落地前检查仓库或组织的 Actions 用量、预算和告警。自托管 Runner 不产生同一种托管执行分钟费用,但机器、网络、维护、安全和故障成本由使用者承担。工作流成功不代表部署目标、云服务或外部 API 不产生费用。
接入真实项目
推荐按以下顺序扩展:
- 让 CI 调用与本地一致的安装、检查、测试和构建脚本。
- 在 Pull Request 中使用只读权限,不接入部署凭据。
- 将稳定 Job 设置为分支保护的必需检查,避免随意改名。
- 保存可追溯 Artifact 或镜像,同一提交只构建一次。
- 通过 Environment 和短期凭据接入测试环境。
- 为生产环境增加审批、并发控制、超时、监控和回滚。
- 多仓库重复后,再提取 composite Action 或 reusable workflow。
复杂逻辑应进入仓库脚本,让开发者可以在本地运行和测试。YAML 负责事件、权限、Runner、Job 依赖和参数编排,不应承载难以调试的大段业务脚本。
故障排查
| 现象 | 核对顺序 |
|---|---|
| 工作流没有触发 | 文件路径、提交分支、YAML、事件过滤、默认分支、仓库/组织策略 |
| YAML 无法解析 | 缩进、列表符号、冒号、引号、表达式位置和编辑器 Schema |
npm ci 失败 | 锁文件、Node 版本、registry、原生依赖和工作目录 |
API 返回 403 | Job 的实际 permissions、事件来源和组织策略 |
| Secret 是空值 | Secret 层级、Environment、Fork/Dependabot 和 reusable workflow 传递 |
| Cache 持续 miss | key、锁文件路径、操作系统、分支范围和首次运行 |
| Artifact 不存在 | 构建输出路径、工作目录和 if-no-files-found |
| 定时任务延迟 | 默认分支、Cron、仓库活跃状态和平台拥堵 |
| 本地成功但 CI 失败 | 大小写、未提交文件、工具版本、Shell、时区、行尾和外部依赖 |
| 镜像登录成功但推送失败 | packages: write、Package 归属、组织策略和镜像名称 |
定位问题时先找到第一个失败步骤。不要用 continue-on-error: true、无限重试或扩大全部权限掩盖根因。
上线检查
- [ ] Workflow 位于
.github/workflows/。 - [ ] 本地测试、构建和退出码稳定。
- [ ] 触发分支、tag、路径与默认分支正确。
- [ ] Job 有合理超时和并发策略。
- [ ] 使用锁文件和可重复安装命令。
- [ ]
permissions只开放当前 Job 所需范围。 - [ ] Fork PR 不执行带 Secret 的发布步骤。
- [ ]
pull_request_target不执行 PR 代码。 - [ ] 第三方 Action 已审查;高风险流程固定提交 SHA。
- [ ] 日志、Artifact 和缓存不包含凭据。
- [ ] 发布使用 Environment、短期凭据或等价保护。
- [ ] 失败通知、回滚版本和业务验收明确。
- [ ] 已检查 Actions 用量、存储和外部服务费用。
参考资料
- Understand GitHub Actions
- Quickstart for GitHub Actions
- Workflow syntax
- Events that trigger workflows
- Use GITHUB_TOKEN for authentication
- Using secrets in GitHub Actions
- Dependency caching
- Store and share data
- Reusing workflow configurations
- Secure use reference
- Publishing Docker images
- Actions usage and billing
- actions/checkout releases
- actions/setup-node releases
- actions/upload-artifact releases
- Docker Actions releases