act 本地运行 GitHub Actions 全解:工作原理、实战命令与源码构建
本文基于 act 仓库根目录的 README.md 展开,讲清楚三件事:为什么要用 act 在本地执行 .github/workflows/ 中的工作流、act 是如何借助 Docker API 解析并执行这些工作流的,以及如何从源码构建、测试并安装 act。读完后,你将能够独立完成工作流的本地运行、常用命令行参数的配置,以及基于 Makefile 的完整开发工作流。
为什么要在本地跑 GitHub Actions
act 的核心定位可以浓缩成一句话:"Think globally, act locally"——用本地环境模拟 GitHub Actions 的完整行为。README 给出了两个动机,二者覆盖了 CI 调试与日常开发两类场景:
- 快速反馈(Fast Feedback):修改
.github/workflows/下的文件或内嵌的 GitHub Actions 时,不必每次改动都 commit/push 到远端等待 GitHub Runner 排队执行。act在本地直接运行这些 action,并且环境变量与文件系统都配置为与 GitHub 提供的运行环境一致,因此本地通过的结果与远端行为高度对齐。 - 本地任务运行器(Local Task Runner):作者对 Makefile 的态度是"爱 make,但讨厌重复"。借助
act,你可以把.github/workflows/中定义的 GitHub Actions 当作本地Makefile的替代品——用同一份 YAML 声明构建、测试、发布等任务,本地和云端共用一份定义。
README 同时推荐了 VS Code 扩展(GitHub Local Actions),可以直接在编辑器内调用
act的能力运行和测试本地工作流。
act 是如何工作的:从工作流到容器
README 的 "How Does It Work?" 一节描述了 act 的完整链路,结合源码可以逐段印证:
- 读取工作流:运行
act时,它会读取.github/workflows/下的文件并确定需要执行的 action 集合。对应实现位于 pkg/model/planner.go:NewWorkflowPlanner支持传入单个工作流文件,或一个目录(可递归扫描子目录),把每个.yml/.yaml解析为工作流模型; - 准备镜像:使用 Docker API 按工作流文件中的定义拉取或构建所需镜像(例如
docker://node:16-buster-slim这类 Docker action 需要拉取镜像,本地 Dockerfile action 需要构建); - 推导执行路径:根据
needs等依赖关系计算执行计划。从源码结构看,pkg/model/planner.go 中的Plan由若干Stage(串行阶段)组成,每个Stage内含一批可并行执行的Run(即工作流中的 job); - 逐 action 运行容器:拿到执行路径后,再次通过 Docker API 为每个 action 启动容器,并注入与 GitHub 一致的环境变量和文件系统布局。
在 pkg/runner/runner.go 中可以看到计划如何变成执行链:NewPlanExecutor 把每个 Stage 包装为一个串行节点,Stage 内部的 job 用 NewParallelExecutor 并行执行,整体再套上 NewPipelineExecutor——即"阶段串行、阶段内并行",与 GitHub Actions 的调度语义一致。此外,job 的 strategy.matrix 会在这里展开为多个带编号的并行实例(maxParallel 受工作流中 max-parallel 控制,默认 4),needs 依赖失败则通过 handleFailure 以 Job '%s' failed 报错。
一个最小工作流示例
仓库测试目录中的 pkg/runner/testdata/basic/push.yml 是一个可以直接读懂的最小示例,涵盖了 act 支持的主要 step 类型:
name: basic
on: push
env:
TEST: value
jobs:
check:
runs-on: ubuntu-latest
steps:
- run: '[[ "$(pwd)" == "${GITHUB_WORKSPACE}" ]]' # 工作目录与 GitHub 一致
- run: echo ${{ env.TEST }} | grep value # 表达式与上下文
- uses: docker://node:16-buster-slim # Docker action(对应 README 第 2 步"pull")
with:
somekey: ${{ env.TEST }}
args: echo ${INPUT_SOMEKEY} | grep somevalue
- run: ls # 普通 shell step
build:
runs-on: ubuntu-latest
needs: [check] # 依赖关系,决定执行路径
steps:
- uses: actions/checkout@v2 # 远程 action
- uses: ./actions/action1 # 本地 action
with:
args: echo 'build'
在任意包含该文件的仓库中执行 act(不带参数时默认按 on: push 事件过滤,若工作流只处理单一事件则自动使用它),check 会先运行,build 在 check 成功后进入下一 Stage 执行。act -l(list)可先查看工作流与 job 清单,act -g(graph)可将执行路径绘制为图形。
常用命令行参数速览
act 的 CLI 基于 Cobra 构建,全部参数在 cmd/root.go 中注册,act --help 可直接查看。以下是从源码中摘录的高频参数及默认值:
| 参数 | 默认值 | 说明 |
|---|---|---|
act [event] |
push |
位置参数指定要触发的事件名;工作流只含一个事件时可省略 |
-l / --list |
- | 列出所有工作流及其 job |
-g / --graph |
- | 以图形方式绘制工作流依赖 |
-j / --job |
- | 只运行指定 job ID |
-P / --platform |
- | 为各平台指定镜像,如 -P ubuntu-latest=catthehacker/ubuntu:act-latest |
-s / --secret |
- | 传入 secret,支持 -s mysecret=foo 或只给名字从环境中取 |
--var / --env / --input |
- | 向工作流注入 vars / 环境变量 / workflow_dispatch 输入 |
-r / --reuse |
false | 工作流成功后保留容器,便于在多次运行间保持状态调试 |
-b / --bind |
false | 将工作目录 bind 进容器而非拷贝,加快文件变更同步 |
-p / --pull |
true | 镜像已存在时也强制拉取 |
-e / --eventpath |
- | 指定事件 JSON 文件(模拟 github.event 数据) |
-a / --actor |
nektos/act |
触发事件的"用户"名,影响 github.actor 上下文 |
-C / --directory |
. |
工作目录 |
-W / --workflows |
./.github/workflows/ |
工作流文件路径,可指向单个或多个文件 |
-n / --dryrun |
false | 不创建容器,仅校验工作流正确性 |
-v / --verbose |
false | 输出调试级日志 |
--json |
false | 日志以 JSON 格式输出 |
--matrix |
- | 筛选矩阵配置,如 --matrix java:13 |
--rm |
false | 工作流失败后自动清理容器与卷 |
--container-architecture |
主机架构 | 指定容器架构(如 linux/amd64),需要 Docker Engine API 1.41+ |
--network |
host |
容器使用的 Docker 网络名 |
--concurrent-jobs |
CPU 核数 | 最大并发 job 数(见 pkg/runner/runner.go 中 GetConcurrentJobs 的实现) |
几个值得注意的实现细节:
.actrc配置文件:act会依次从 XDG 配置目录(act/actrc)、$HOME/.actrc、当前目录.actrc三个位置读取参数文件,命令行参数优先级更高(见 cmd/root.go 的configLocations与args)。每行一条参数,支持环境变量展开;- 首次运行的镜像选择:若未指定
--platform且不存在任何.actrc,act会交互式询问使用 Large / Medium / Micro 三档预置镜像(分别对应catthehacker/ubuntu:full-*、catthehacker/ubuntu:act-*、node:16-*-slim),并把结果写入全局配置,避免重复打扰。可镜像列表的详细说明见仓库根目录的 IMAGES.md; - Apple Silicon 提示:在 M 系列芯片的 Mac 上未指定
--container-architecture时,cmd/root.go 会打印警告,建议尝试--container-architecture linux/amd64。
本地 secret 与变量文件
除 -s 直接传值外,act 还支持批量文件:--secret-file(默认 .secrets)、--var-file(默认 .vars)、--env-file(默认 .env)、--input-file(默认 .input)。文件格式为 KEY=VALUE,也支持 .yml/.yaml(见 cmd/root.go 中 readEnvsEx)。注意 secret 文件按"大写不敏感"方式读取,且当未显式提供 GITHUB_TOKEN 时,act 会尝试从 gh 工具链获取 token 注入。
从源码构建与安装
README 的 "Manually building from source" 一节给出了最简流程,结合仓库实际文件可以补全如下(适用前提:Linux/macOS/类 Unix shell 环境):
- 安装 Go 工具链:README 声明需要 Go 1.20+;但当前主线 go.mod 声明
go 1.25.0,因此构建当前master分支实际需要一个能自动下载/切换到 1.25+ 工具链的 Go 环境; - 克隆仓库:
git clone仓库地址(官方源地址为 nektos/act 的 Git 仓库); - 运行单元测试:
make test——它先执行go test ./...,再运行一次go run main.go做冒烟检查(见 Makefile 的test目标); - 构建并安装:
make install——其内部先build(go build -ldflags "-X main.version=..." -o dist/local/act main.go,版本号由git describe --tags推导),再把二进制复制到$(PREFIX)/bin/act(PREFIX默认/usr/local)并执行act --version验证。
入口逻辑非常薄:main.go 将仓库根目录的 VERSION 文件通过 go:embed 编入二进制,创建可优雅取消的 context 后调用 cmd 的 Execute。当前版本号记录在根目录的 VERSION 文件中(本仓库快照为 0.2.88)。
除手动构建外,仓库还提供 install.sh 安装脚本(由 godownloader 生成),支持 -b 指定安装目录(默认 ./bin)、-f 强制安装、传入 tag 安装指定版本,安装前会做 SHA256 校验。
开发者的完整检查清单
Makefile 中还定义了面向贡献者的更多目标,配合 CONTRIBUTING.md 中的贡献流程使用:
| 目标 | 作用 |
|---|---|
make pr |
PR 前完整检查:tidy → format-all → lint → test |
make lint-go |
运行 golangci-lint(规则配置见 .golangci.yml) |
make lint-md |
用 markdownlint 检查 Markdown |
make tidy |
go mod tidy |
make format |
go fmt ./... |
make snapshot |
用 goreleaser 构建快照版二进制 |
make security-check |
用 govulncheck 扫描依赖漏洞 |
代码仓库自身的工程约束也值得参考:.golangci.yml 强制使用标准库 errors、logrus(别名 log)、testify,循环复杂度上限 20。
测试即文档:testdata 目录
act 的功能面很大,pkg/runner/testdata/ 下数百个样例工作流是最好的"活文档":matrix/、composite-fail-with-output/、uses-workflow/、services/、job-container/ 等目录分别对应矩阵展开、composite action、可复用工作流、服务容器、job 容器等能力,每个目录下的 push.yml(或 main.yaml)都是可直接运行的最小复现。调试本地工作流问题时,先在该目录找同构样例是高效的排障路径。
获取帮助
按 README 的建议,遇到问题可以先到项目的 discussions 区提问;更深入的使用文档(安装、.actrc 配置、平台镜像选择等)维护在 act 的官方用户指南站点 nektosact.com 上(README 中的外链)。在仓库内查阅材料时,建议的阅读顺序是:README.md → IMAGES.md → CONTRIBUTING.md → 对应功能的 pkg/ 源码与 testdata/ 样例。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00