2. GitHub Actions核心概念与运行机制

要真正用好 GitHub Actions,不能只停留在“会写 YAML”的层面,而必须理解它的事件驱动执行模型:一次推送、一个 PR、一条定时规则,如何被 GitHub 转换成一次可追踪、可复现的自动化运行。本节围绕 workflow、job、step、action、runner、event 六个核心术语,讲清它们之间的层级关系与运行机制。

一、六个核心术语的层级关系

GitHub Actions 的对象模型是严格分层的,理解层级是理解运行机制的前提。

  • event(事件):触发源。例如 push、pull_request、schedule、workflow_dispatch。事件决定了“什么时候开始跑”。
  • workflow(工作流):一个 .github/workflows/*.yml 文件就是一个 workflow,是自动化流程的顶层容器,由事件触发。
  • job(作业):workflow 内的执行单元,默认并行运行,可通过 needs 建立依赖形成串行链。每个 job 分配到一个独立的 runner。
  • step(步骤):job 内的最小执行单位,按顺序执行。step 要么是 run(执行 shell 命令),要么是 uses(调用一个 action)。
  • action(动作):可复用的最小功能封装,如 actions/checkout@v4、actions/setup-node@v4,本质是一段可被 step 调用的逻辑。
  • runner(运行器):真正执行 job 的机器,GitHub 托管 runner 是临时虚拟机/容器,job 结束后即销毁。

层级关系可以概括为:event → workflow → job → step → action,而 runner 是承载 job 的执行环境。下面这张图展示了从事件触发到 runner 执行、再到结果回传的完整链路。

event push / PR / schedule workflow .github/workflows/ci.yml on: [push, pull_request] job: build runs-on: ubuntu-latest steps: checkout → build job: test needs: build steps: test → report runner GitHub 托管 ubuntu-latest 临时虚拟机 job 结束即销毁 每次全新环境 独立隔离 needs job: build 内部 step 执行顺序 step 1 uses: actions/checkout@v4 step 2 uses: actions/setup-node@v4 step 3 run: npm ci && npm run build 结果 success / failure step 按顺序执行;任一步失败,默认后续 step 不再执行,job 标记为 failure。 action 是可复用封装,step 通过 uses 调用;run 则直接执行 shell 命令。 job 之间默认并行,needs 建立依赖后变为串行,且可传递 outputs。

二、事件驱动执行模型

GitHub Actions 不是“常驻服务”,而是事件驱动的。GitHub 在仓库上持续监听各类事件,一旦匹配到某个 workflow 的 on 配置,就创建一个 workflow run。这个 run 有唯一 ID,可在 Actions 页面查看日志、耗时和状态。

常见事件类型及典型用途:

事件触发时机典型用途
push向分支推送提交构建、测试、部署
pull_requestPR 打开/更新/合并代码检查、预览环境
schedulecron 定时夜间构建、依赖扫描
workflow_dispatch手动点击触发按需发布、回滚
release发布 Release打包上传制品

事件还可以通过 branches、paths、types 做过滤。例如只在 main 分支且修改了 src/ 目录时触发:

on:
  push:
    branches: [main]
    paths:
      - 'src/**'
      - 'package.json'

这种过滤能显著减少无效运行,是工程实践中非常关键的一步。

三、工作流文件结构

一个 workflow 文件由若干顶层键组成,最常用的包括:

  • name:工作流显示名称。
  • on:触发事件及过滤条件。
  • env:全局环境变量。
  • jobs:作业集合,每个 job 有 runs-on、steps、needs、if、outputs 等。

下面是一个可直接参考的最小可用示例,包含构建与测试两个 job,并通过 needs 串行:

name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm run build

  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test

注意:test 依赖 build,因此会等 build 成功后才开始;如果 build 失败,test 默认被跳过。这是 job 依赖最直观的体现。

四、GitHub 托管运行器的工作原理

GitHub 托管 runner 的本质是按需分配的临时执行环境。当你触发一个 job,GitHub 会:

  1. 根据 runs-on 选择对应镜像(如 ubuntu-latest、windows-latest、macos-latest)。
  2. 启动一台全新的虚拟机或容器,预装常用工具链(Node、Python、Docker、Git 等)。
  3. 把仓库代码检出到工作目录,按顺序执行 steps。
  4. job 结束后销毁环境,不保留任何状态。

这意味着两件事:第一,每次运行都是干净环境,不会残留上一次的缓存或文件,因此构建结果更可复现;第二,不能依赖本地状态,任何需要跨 job 传递的数据必须通过 artifacts、cache 或 outputs 显式传递。

实践提示:如果 job 需要访问私有依赖或推送镜像,应使用 secrets 注入凭据,而不是把密钥写进 YAML。例如 ${{ secrets.NPM_TOKEN }}。

五、一次运行的完整生命周期

把上述概念串起来,一次典型的 CI 运行经历如下阶段:

  1. 事件触发:开发者向 main 推送提交,GitHub 匹配到 on.push。
  2. 创建 run:生成 workflow run,解析 YAML,确定 job 依赖图。
  3. 调度 job:build 先分配到 runner 并执行;test 等待 needs 满足。
  4. 执行 step:每个 step 依次运行,日志实时回传。
  5. 结果判定:所有 step 成功则 job 为 success;任一步失败则 job 为 failure,并影响下游 job。
  6. 环境销毁:runner 释放,run 状态归档。

理解这条链路后,排查问题就有了方向:如果 workflow 根本没触发,先查 on 过滤条件;如果 job 一直排队,查 runner 配额或 runs-on 标签;如果 step 失败,看具体命令退出码和日志。把“事件—workflow—job—step—runner”这条链作为诊断路径,绝大多数 CI 问题都能快速定位。

本节要点回顾:event 决定何时触发,workflow 是顶层容器,job 是并行/串行执行单元,step 是最小步骤,action 是可复用封装,runner 是临时执行环境。六者构成 GitHub Actions 的完整运行模型,也是后续编写复杂流水线的基础。