GitHub Actions 工作流配置详解

详解 GitHub Actions 工作流 YAML 语法,覆盖 on 触发器与事件、jobs/steps、actions、表达式与上下文、内置环境变量、secrets 与输入,配合 act 本地实测回显说明如何编写与调试 workflow 文件

GitHub ActionsGitHub ActionsDevOpsCICD2026/10/10

GitHub Actions 工作流配置详解

目标:系统讲解 GitHub Actions 工作流(workflow)文件(.github/workflows/*.yml)的 YAML 语法,覆盖 on 触发器、jobs/steps、复用 actions、表达式与上下文、内置环境变量、secrets/inputs,并用 act 本地实测回显演示一个可运行示例。本文已在 Ubuntu 22.04 真实环境实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS
  • 工作流存放目录:.github/workflows/
  • 示例仓库:/opt/data/github-actions/myapp(git 远程指向 quzuo-ops/demo-app)
  • 本地运行工具:act 0.2.89(本地运行 GitHub Actions 工作流的 CLI)
  • 示例工作流文件:.github/workflows/ci.yml
  • Runner 版本:2.338.0(自托管 Runner,见《Ubuntu 22.04 安装 GitHub Actions Runner 指南》)

二、前置条件

  • 代码仓库含 .github/workflows/ 目录,目录内每个 .yml/.yaml 即一个工作流
  • 已安装 GitHub Actions Runner 或可联网访问 GitHub 托管 Runner
  • 本地调试可选装 act(详见《GitHub Actions 常用 CLI 命令详解》)
  • 编辑与校验:可用 act -n(dry-run)在本地校验工作流语法正确性

三、工作流文件总览(示例 ci.yml)

一段被实际运行(见"八、实测")的最小示例,完整展示语法骨架:

name: CI
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout 代码
        uses: actions/checkout@v4
      - name: 打印工作区
        run: |
          echo "仓库名: ${{ github.repository }}"
          echo "分支: ${{ github.ref_name }}"
          echo "工作目录文件列表:"
          ls -la
      - name: 输出信息
        run: echo "Hello GitHub Actions from act"

工作流由四层结构组成:

  1. name:工作流名称,显示在 Actions 页;
  2. on:触发条件(事件/调度);
  3. jobs:一个或多个 job(任务),可并行、可依赖;
  4. 每个 job 内的 runs-on(运行环境)与 steps(步骤列表,每步用 uses 复用 action 或用 run 执行 shell 命令)。

四、on 触发器(事件)

on 决定工作流何时触发,可写单个事件、数组,或带过滤条件的地图形式。

4.1 单个事件 / 事件数组

on: push            # 任意 push 触发
on: [push, pull_request]   # push 或 PR 触发

4.2 带过滤的 push / pull_request

on:
  push:
    branches: [main, "release/*"]   # 仅这些分支的 push
    paths:
      - "src/**"                     # 仅这些路径变更时触发
  pull_request:
    types: [opened, synchronize]     # 仅响应 PR 的这两种状态

4.3 定时与手动触发

on:
  schedule:
    - cron: "0 2 * * *"          # 每天 02:00 UTC 触发
  workflow_dispatch:             # 手动触发,可带输入
    inputs:
      environment:
        description: 部署环境
        required: true
        default: staging
      version:
        description: 版本号

4.4 复用其它工作流(workflow_call / workflow_run)

on:
  workflow_call:                 # 供其它工作流调用,可声明 inputs/secrets
    inputs:
      tag:
        type: string
        required: true
  workflow_run:
    workflows: ["CI"]            # 上游 CI 工作流完成后触发
    branches: [main]
    types: [completed]

💡 说明:workflow_dispatch 触发的 job 才能用 act 在本地以手动事件模拟;schedule 的 cron 语法与 Linux 一致(5 段),但时区固定为 UTC。

五、jobs 与 runs-on

5.1 多 job 与依赖关系

jobs:
  build:
    runs-on: ubuntu-latest
    steps: []
  test:
    runs-on: ubuntu-latest
    needs: build          # 依赖 build 成功后执行
    steps: []
  release:
    runs-on: [self-hosted, Linux, X64]   # 指定自托管 Runner(通过 label)
    needs: [build, test]                 # 依赖多个 job
    steps: []

5.2 矩阵(matrix)策略与并发控制

jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: [16, 18, 20]
        os: [ubuntu-latest]        # 维度自由组合
      fail-fast: false
    concurrency:
      group: build-{{ github.ref }}
      cancel-in-progress: true
    steps:
      - run: node --version        # 同一套步骤会在各组合上各跑一次

💡 说明:needs 建立 DAG 依赖,未声明依赖的 job 并行执行;strategy.matrix 将同一 job 打散为多组合并行,fail-fast=false 时某组合失败不终止其它组合。

5.3 运行环境(runs-on 取值)

runs-on 取值说明
ubuntu-latest / ubuntu-22.04GitHub 托管 Ubuntu(由 GitHub 配额运行)
windows-latest、macos-latestGitHub 托管 Windows/macOS
[self-hosted, Linux, X64]自托管 Runner,按 label 匹配
[self-hosted, linux, arm64]自托管 ARM64 Runner

六、steps 与 actions(uses/run)

一个 step 只能有一个主要关键字:uses(复用 action)或 run(执行命令)。可给 step 起 name 便于日志定位。

6.1 run 步骤(执行 shell 命令)

steps:
  - name: 安装依赖
    run: npm ci
  - name: 多行命令
    run: |
      set -euxo pipefail
      echo "step 1"
      echo "step 2"
  - name: 指定 shell
    shell: bash
    run: echo "使用 bash"

6.2 uses 步骤(复用 action)

uses: owner/repo@ref 三要素:仓库名 + 标签/分支/SHA。常用官方 action:

steps:
  - uses: actions/checkout@v4          # 检出代码到工作区
    with:
      submodules: true
  - uses: actions/setup-node@v4        # 安装 Node.js
    with:
      node-version: '20'
      cache: 'npm'
  - uses: actions/setup-java@v4
    with:
      distribution: temurin
      java-version: '21'
  - uses: actions/cache@v4             # 缓存依赖
    with:
      path: ~/.npm
      key: npm-${{ hashFiles('package-lock.json') }}

💡 说明:with 传 action 的输入参数;宁可固定到 SHA(@<40位sha>)保证安全可复现,也可固定到 tag(@v4)便于升级。

6.3 条件执行与输出

steps:
  - name: 仅 main 分支执行
    if: github.ref == 'refs/heads/main'
    run: echo "在主分支"
  - name: 输出传给下一步
    id: ver
    run: echo "value=v1.0.0" >> "$GITHUB_OUTPUT"
  - name: 读取上一步输出
    run: echo "版本是 ${{ steps.ver.outputs.value }}"

七、表达式、上下文、环境变量与 secrets

7.1 表达式与上下文(contexts)

${{ 表达式 }} 内是表达式,可引用上下文对象。常用上下文:

上下文用途示例值(实测 act 下)
github事件与仓库信息github.repository → quzuo-ops/demo-app
github.ref_name分支/Tag 名master
steps.<id>.outputs.<k>上一步输出见 6.3
matrix.<k>矩阵当前组合matrix.node
env工作流/Job/Step 环境变量env.MY_VAR
secrets加密机密secrets.API_TOKEN
inputsworkflow_dispatch 输入inputs.version
runnerrunner 信息runner.os、runner.arch

7.2 内置环境变量

系统内置一批默认环境变量,可直接以 $GITHUB_* 形式引用:

变量说明
$GITHUB_WORKSPACE默认工作区目录
$GITHUB_SHA当前提交 SHA
$GITHUB_REPOSITORYowner/repo
$GITHUB_REF触发引用的 ref
$GITHUB_RUN_NUMBER运行序号
$GITHUB_ACTOR触发用户
$GITHUB_OUTPUT写 step 输出的文件路径
$GITHUB_ENV写环境变量的文件路径
$GITHUB_PATH追加 PATH 的文件路径
steps:
  - name: 写环境变量
    run: echo "MY_VAR=hello" >> "$GITHUB_ENV"
  - name: 读环境变量
    run: echo "$MY_VAR"

7.3 secrets(机密)与 inputs(输入)

name: Deploy
on:
  workflow_dispatch:
    inputs:
      target: { type: choice, options: [staging, prod], default: staging }
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - run: echo "目标环境 ${{ inputs.target }}"
      - run: |
          # secrets 全量传入环境变量(名称均为大写)
          echo "${{ secrets.API_TOKEN }}" > /dev/null
        env:
          API_TOKEN: ${{ secrets.API_TOKEN }}

⚠️ 安全提示:不要在 run 里用 echo ${{ secrets.X }} 直接打印,避免机密进入日志;应通过 env 传入再使用。secrets 取自仓库或组织 Settings,且不可在 if: 条件中直接比较(存在泄漏风险)。

八、act 本地实测(真实回显)

8.1 编写示例工作流

mkdir -p /opt/data/github-actions/myapp/.github/workflows
cd /opt/data/github-actions/myapp
cat > .github/workflows/ci.yml <<'EOF'
name: CI
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout 代码
        uses: actions/checkout@v4
      - name: 打印工作区
        run: |
          echo "仓库名: ${{ github.repository }}"
          echo "分支: ${{ github.ref_name }}"
          echo "工作目录文件列表:"
          ls -la
      - name: 输出信息
        run: echo "Hello GitHub Actions from act"
EOF
git init && git add -A && git commit -qm init

8.2 用 act 校验与列出 job

act list -W .github/workflows

实测回显:

Stage  Job ID  Job name  Workflow name  Workflow file  Events
0      build   build     CI             ci.yml         push

8.3 用 act 本地运行 push 事件

act push -j build -W .github/workflows

实测回显:

[CI/build] ⭐ Run Set up job
[CI/build] 🚀  Start image=node:20-bookworm-slim
[CI/build]   🐳  docker pull image=node:20-bookworm-slim platform= username= forcePull=true
[CI/build]   🐳  docker run image=node:20-bookworm-slim platform= entrypoint=["tail" "-f" "/dev/null"] cmd=[] network="host"
[CI/build]   ✅  Success - Set up job
[CI/build] ⭐ Run Main Checkout 代码
[CI/build]   🐳  docker cp src=/opt/data/github-actions/myapp/. dst=/opt/data/github-actions/myapp
[CI/build]   ✅  Success - Main Checkout 代码 [25.273241ms]
[CI/build] ⭐ Run Main 打印工作区
[CI/build]   🐳  docker exec cmd=[bash -e /var/run/act/workflow/1] user= workdir=
[CI/build]   | 仓库名: quzuo-ops/demo-app
[CI/build]   | 分支: master
[CI/build]   | 工作目录文件列表:
[CI/build]   | total 20
[CI/build]   | drwxr-xr-x 4 root root 4096 Oct 10 00:30 .
[CI/build]   | drwxr-xr-x 3 root root 4096 Oct 10 00:30 ..
[CI/build]   | drwxr-xr-x 7 root root 4096 Oct 10 00:30 .git
[CI/build]   | drwxr-xr-x 3 root root 4096 Oct 10 00:30 .github
[CI/build]   | -rw-r--r-- 1 root root    8 Oct 10 00:24 README.md
[CI/build]   ✅  Success - Main 打印工作区 [101.480655ms]
[CI/build] ⭐ Run Main 输出信息
[CI/build]   🐳  docker exec cmd=[bash -e /var/run/act/workflow/2] user= workdir=
[CI/build]   | Hello GitHub Actions from act
[CI/build]   ✅  Success - Complete job
[CI/build] 🏁  Job succeeded

💡 说明:上面「仓库名: quzuo-ops/demo-app」来自 github.repository 上下文,act 依据仓库的 git 远程地址推导;//workflow/1 表明这是工作流的第 1 个 run 步骤的桶文件,逐行按步骤回放。实际在真实 GitHub 推送后由托管 Runner 执行,输出格式一致但以真实 history 为准。

8.4 dry-run 校验语法(仅预检,不实际执行)

act -n -j build -W .github/workflows

实测回显(节选):

*DRYRUN* [CI/build] ⭐ Run Set up job
*DRYRUN* [CI/build] 🚀  Start image=node:20-bookworm-slim
*DRYRUN* [CI/build]   ✅  Success - Set up job
*DRYRUN* [CI/build] ⭐ Run Main Checkout 代码
*DRYRUN* [CI/build]   ✅  Success - Main Checkout 代码
*DRYRUN* [CI/build] ⭐ Run Main 打印工作区
*DRYRUN* [CI/build]   ✅  Success - Main 打印工作区 [46.867046ms]
*DRYRUN* [CI/build] ⭐ Run Main 输出信息
*DRYRUN* [CI/build]   ✅  Success - Main 输出信息 [39.015654ms]
*DRYRUN* [CI/build] 🏁  Job succeeded

九、常见问题

Q1:本地 act 运行报 Could not find any stages to run?

-W 传的路径未含工作流的『目录』(应传 .github/workflows 目录而非单个文件路径写法不当),或用 -W .github/workflows 指定目录、-j <job> 指定 job 即可。

Q2:${{ github.ref_name }} 与 ${{ github.ref }} 有何区别?

github.ref 是完整 ref(如 refs/heads/main);github.ref_name 是去掉前缀的名字(如 main)。比较分支常 github.ref == 'refs/heads/main',打印用 ref_name。

Q3:workflow_dispatch 输入在 act 里如何提供?

act 用 --input key=value 提供(见《常用 CLI 命令详解》),例如 act workflow_dispatch -j deploy --input target=prod。

Q4:secrets 在 env: 里没生效?

在真实 Runner 上 secrets 需在仓库 /Settings → Secrets and variables → Actions 预先定义;名称引用时用 secrets.名称,且放在 env: 下传进程(命名大写仅为约定,不强制)。

十、参考链接