面向前端团队的 5 个 GitHub Actions 替代方案
比较适用于前端团队的五种 GitHub Actions 替代方案:CircleCI、Buildkite、Jenkins、Woodpecker CI 和 Dagger,并提供配置示例与选择建议。
对前端团队而言,最值得考虑的 GitHub Actions 替代方案有以下几类:需要完全托管的 CI,选 CircleCI;需要托管控制平面、同时让作业运行在托管或自托管 agent 上,选 Buildkite;需要完全自托管的 CI,选 Jenkins 或 Woodpecker CI;需要以代码定义流水线,并让它在笔记本和任意 CI 中以相同方式运行,选 Dagger。
团队开始寻找替代方案,通常是因为以下几种情况:账单上的 runner 分钟数居高不下,Pull Request 在队列里迟迟等不到执行,或者某个工作流只在 GitHub 的 runner 上失败、在本地却从不复现。本文假设你已经熟悉 GitHub Actions 工作流模型,并从三个维度对比这五种方案:各自适合哪类团队、作业运行在哪里,以及 Node 前端项目的安装、lint、测试和构建作业分别怎么写。
核心要点
- 如果每个 CI 作业都只调用
npm ci、npm run lint、npm test和npm run build,那么更换 CI 工具时只需改写几行 YAML,而无需改动流水线逻辑。 - Buildkite 负责托管编排,作业则运行在 agent 上:可以是 Buildkite 托管的 Linux、Buildkite 托管的 macOS(仅限付费套餐),也可以是团队自己维护的机器。
- CircleCI 是托管式 CI,通过
.circleci/config.yml进行配置,所有套餐(包括免费版)都支持自托管 runner。 - Jenkins 和 Woodpecker 都是自托管方案。你不再按分钟付费,转而需要承担服务器和运维成本。
- Dagger 不是 CI 服务,而是一套流水线代码,既能在本地运行,也能在你现有的任何 CI 中运行。
前端团队为什么要寻找 GitHub Actions 的替代方案?
前端团队放弃 GitHub Actions,通常出于以下四个原因之一:托管 runner 的分钟数费用过高;托管 runner 需要排队;需要在自有硬件上运行 agent;无法在本地复现 CI/CD 流水线。迁移之前,先仔细评估第二个原因:如果托管 runner 排队是你唯一的问题,那么 GitHub Actions 自托管 runner 或许无需更换工具就能解决。至于 GitLab CI/CD,主要适合打算连同代码仓库一起迁移的团队,其配置方法可参阅 GitLab CI/CD 流水线。
为了保证对比公平,请将构建逻辑放在 package.json 中,让每个 CI 工具都调用同一组脚本:
{
"scripts": {
"lint": "eslint .",
"test": "vitest run",
"build": "vite build"
}
}
请根据你所用框架替换为相应的命令。在下文的每个示例中,CI 配置只做一件事:先运行 npm ci,再依次运行这三个脚本。
Buildkite
Buildkite 适合希望使用托管编排、但又需要掌控作业运行机器的团队。Buildkite 同时支持两种模式:自行运行的 agent,以及由 Buildkite 托管的 agent。Buildkite 托管的 Linux agent 在所有套餐中均可使用,其中免费版仅限小规格机器;Buildkite 托管的 macOS agent 则需要 Pro 或 Enterprise 套餐。自托管 agent 会主动轮询 Buildkite 获取任务,因此无需开放任何入站端口。Buildkite 提供免费账户供你上手试用。
# .buildkite/pipeline.yml
steps:
- label: "Install, lint, test, build"
commands:
- npm ci
- npm run lint
- npm test
- npm run build
plugins:
- docker#v5.14.0:
image: "node:<your-node-version>"
Docker 插件会在 Node 镜像中执行这些命令,因此 agent 上只需安装 Docker。如果 agent 上已经装好了 Node,可以去掉 plugins 配置块。
**结论:**如果你希望掌控计算资源,又不想自己运维 CI 服务器,Buildkite 是最合适的选择。代价是,除非使用托管 agent,否则你需要自行管理 agent 集群。
CircleCI
CircleCI 适合希望使用完全托管服务、尽量减少基础设施投入的团队。CircleCI 以托管服务为主,同时在所有套餐中都提供自托管 runner,包括免费版。默认情况下,你的代码运行在 CircleCI 的基础设施上。根据 CircleCI 的配置入门文档,2.1 是最新的配置版本。
# .circleci/config.yml
version: 2.1
jobs:
build:
docker:
- image: cimg/node:<full.node.version>
steps:
- checkout
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
workflows:
ci:
jobs:
- build
请将 cimg/node 固定为项目所用的完整 Node 版本号。CircleCI 同样支持依赖缓存,但为了保持示例简洁,这里省略了相关配置。YAML 写错是首次推送到 CircleCI 失败的常见原因,因此建议在提交前先用 OpenReplay YAML 校验工具检查一遍,及早发现语法错误。
**结论:**CircleCI 是与 GitHub Actions 最接近的同类替代品。如果你的问题在于分钟数费用和排队,又不想自己运维服务器,CircleCI 是合理的选择。
Jenkins
Jenkins 适合有严格本地部署要求、并且有专人负责维护的团队。Jenkins 只能自托管。软件本身免费开源,但成本从按分钟计费转移到了团队需要维护的服务器、插件和版本升级上。流水线定义在 Jenkinsfile 中,采用声明式 Pipeline 语法编写:
pipeline {
agent any
stages {
stage('Install') { steps { sh 'npm ci' } }
stage('Lint') { steps { sh 'npm run lint' } }
stage('Test') { steps { sh 'npm test' } }
stage('Build') { steps { sh 'npm run build' } }
}
}
agent any 的前提是,无论哪个 agent 领取该作业,其上都已安装 Node。
**结论:**只有在自托管是硬性要求时才选择 Jenkins。对大多数前端团队而言,它带来的运维成本会超过节省下来的分钟数费用。
Woodpecker CI
Woodpecker CI 适合希望使用轻量级自托管 CI、并且偏好熟悉的 YAML 写法的小型团队。Woodpecker CI 采用自托管方式,按照其工作流语法的规定,每个步骤都会在该步骤指定的容器中执行命令。工作流可以放在 .woodpecker/ 目录下,每个文件对应一个工作流。
# .woodpecker/ci.yaml
steps:
- name: install
image: node:<your-node-version>
commands:
- npm ci
- name: lint
image: node:<your-node-version>
commands:
- npm run lint
- name: test
image: node:<your-node-version>
commands:
- npm test
- name: build
image: node:<your-node-version>
commands:
- npm run build
将工作拆分为四个步骤,并不意味着要安装四次依赖。步骤默认按顺序执行,检出的工作区会挂载到每个步骤中,因此 install 步骤生成的 node_modules 目录在 build 步骤中依然存在。只要安装了 woodpecker-cli 和受支持的后端,就可以在推送前通过 woodpecker-cli exec 在本地运行工作流。
**结论:**在自托管场景下,Woodpecker CI 比 Jenkins 更简单。缺点是服务器和 agent 都需要你自己运行和维护。
Dagger:以代码定义流水线,而非 CI 服务
Dagger 不是托管式 CI 服务,也无法取代 CI 服务。你使用 Dagger SDK 以代码形式编写流水线,同一份代码既能在笔记本上运行,也能在任何 CI 系统(包括 GitHub Actions)中运行。SDK 文档涵盖 Go、Python、TypeScript、Java、PHP 和 Elixir,以及 Dagger 自有的脚本语言 Dang。下面用 TypeScript 实现同样的作业,所用模块通过 dagger init --sdk=typescript --name=frontend-ci 创建:
import { dag, Directory, object, func } from "@dagger.io/dagger"
@object()
class FrontendCi {
@func()
async check(source: Directory, nodeVersion: string): Promise<string> {
return await dag
.container()
.from(`node:${nodeVersion}`)
.withMountedDirectory("/src", source)
.withWorkdir("/src")
.withExec(["npm", "ci"])
.withExec(["npm", "run", "lint"])
.withExec(["npm", "test"])
.withExec(["npm", "run", "build"])
.stdout()
}
}
在本地使用 dagger call check --source=. --node-version=<your-node-version> 运行。现有 CI 作业只需执行这同一条命令即可,无需其他配置。只要本地运行通过,CI 中执行的就是完全相同的容器步骤。代价是团队需要额外学习一套 SDK 和引擎。
以上命令适用于 Dagger 0.x。2026 年 10 月以 beta 形式发布的 Dagger 1.0 对这些命令进行了重命名:改用 dagger module init 创建模块,dagger call 则变为 dagger api call。TypeScript 代码本身保持不变。
如何选择 GitHub Actions 替代方案?
选择哪种 GitHub Actions 替代方案,取决于你希望作业运行在哪里:
- **如果你想要完全托管、无需任何运维的 CI,**选择 CircleCI。它的配置与你现有的配置高度对应。
- **如果你想要托管编排,并让作业运行在自有机器或供应商托管的机器上,**选择 Buildkite,尤其是在需要 macOS 构建时。
- **如果必须自托管,并且有人力负责维护,**选择 Jenkins。
- **如果必须自托管,并且希望方案尽量轻量,**选择 Woodpecker CI。
- **如果真正的问题是“本地能跑,CI 失败”,**引入 Dagger,并继续使用上述任一工具(或 GitHub Actions 本身)作为执行器。
- **如果唯一的问题是排队时间,**优先尝试 GitHub Actions 自托管 runner。
Woodpecker 的 Docker 后端和 Dagger 都需要容器运行时。如果 Docker Desktop 不适合你的机器环境,Dagger 也可以运行在 Podman 和 nerdctl 上,Woodpecker 则可以运行在 Kubernetes 上,或通过其 local 后端直接运行在宿主机上。
无论选择哪种工具,第一步都是把所有构建逻辑迁移到 npm scripts 中。然后在单个分支上试用替代方案,让它与 GitHub Actions 并行运行,对比一周的结果后再正式切换。
常见问题
GitHub Actions 的自托管 runner 是否按分钟收费?
不收费。GitHub 不对自托管 runner 的使用按分钟计费,成本仅为运行这些 runner 的机器费用。2025 年 12 月,GitHub 宣布自 2026 年 3 月 1 日起对自托管 runner 收取每分钟 0.002 美元的平台费用,随后又推迟实施,以重新评估相关方案。在基于上述任一数字进行成本对比之前,请先查阅 GitHub Actions 的计费文档。
能否在推送前于本地运行 CircleCI 作业?
可以,但每次只能运行一个作业。CircleCI CLI 可以通过 circleci local execute 在本机的 Docker 中运行单个作业。工作流无法在本地运行,machine executor 也不受支持。对于 2.1 版本的配置,需要先使用 circleci config process 导出处理后的配置,再通过 -c 参数将该文件连同作业名称一起传给 circleci local execute。
Woodpecker CI 是否支持托管在 GitHub 上的仓库?
支持。Woodpecker 支持 GitHub(包括 GitHub Enterprise),以及 GitLab、Gitea、Forgejo 和 Bitbucket Cloud。你需要在代码托管平台上注册一个 OAuth 应用,并通过 WOODPECKER_GITHUB_CLIENT 和 WOODPECKER_GITHUB_SECRET 等环境变量将其 client ID 和 secret 传给 Woodpecker 服务器。仓库仍保留在 GitHub 上,Woodpecker 会将流水线状态回报给 GitHub,只有服务器和 agent 运行在你自己的基础设施上。
如何在现有的 GitHub Actions 工作流中运行 Dagger 函数?
在 actions/checkout 之后添加一个使用官方 dagger/dagger-for-github action 的步骤。该 action 会安装 Dagger CLI,在 runner 上启动 Dagger Engine 并调用你的函数。将 verb 设置为 call,并传入与本地相同的参数,例如 check 以及源代码目录和 Node 版本。流水线逻辑保留在模块中,因此日后迁出 GitHub Actions 时,只需修改这一层很薄的封装。