CI 跑一次要等几分钟,改个错还得 push 到远端触发重新构建,这是每个开发者的日常。Preloop 想改变这件事:它把 GitHub Actions 的整个执行引擎搬到本地,让你在提交代码之前,就能用真实的 GitHub Actions 工作流在自己的机器上跑完整个 CI,而且每个 Job 跑在硬件隔离的微虚拟机里,启动只要 300 毫秒。
它的核心思路是:不重新发明一套 CI 语法,而是直接兼容 GitHub Actions 的协议。你的 `.github/workflows` 目录下的文件原封不动就能跑,`${{ }}` 表达式、矩阵构建、可复用工作流、并发组、OIDC(开放身份连接,用于安全地获取云服务凭证)这些特性全都支持。这意味着你本地跑的结果和 GitHub 上跑的结果,理论上应该完全一致。
为什么能做到?因为它用的是官方 `actions/runner` 的通信协议,而不是自己模拟一套行为。官方 runner 二进制可以直接连到 Preloop 的本地服务上,注册、轮询、执行、上报,全流程走通。这就像你写了一个兼容 MySQL 协议的数据库,任何 MySQL 客户端都能直接连上来用。
最让我意外的是它的微虚拟机方案。每个 Job 不是跑在普通的进程或容器里,而是跑在一个硬件隔离的微虚拟机里,基于一个叫 SmolVM 的运行时。这个微虚拟机从“黄金镜像”(预先打好基础环境的虚拟机模板)fork 出来,只要 300 毫秒。而且内存是弹性的,用多少占多少,控制平面空闲时只占 25MB 内存。官方 GitHub 的 runner 镜像压缩后约 9GB,解压后接近 50GB,所以本地跑至少建议留 80GB 磁盘。
另一个亮点是调试能力。它支持 DAP(调试适配协议,一种让调试器与运行环境通信的标准协议),你可以让 Job 在入口处暂停,等调试器 attach 上来,然后实时查看 GitHub 上下文、环境变量、矩阵值、生成的 secrets 等。当工作流 YAML 看起来没问题但运行时事件载荷不对时,这个功能能救命。你还可以在 Job 中途暂停、继续,甚至对单个步骤做重试。
它还带了一个用 Rust 从零重写的 runner 替代品 `preloop-runner`,和官方 runner 说同样的协议,但安装体积只有 11.9MB(官方是 434MB),峰值内存占用只有 11MB(官方是 206MB)。官方 runner 把 node20 和 node24 打包进每个安装里,而 Preloop 的 runner 是单个二进制,把共享的只读依赖挂载到每个虚拟机里。
Preloop 不依赖 GitHub Webhook 来更新 CI 状态,它跑了一个 Webhook 看门狗,检测状态漂移,然后通过 GitHub API 对齐你的提交和收到的 Webhook。你可以在本地跑完工作流后,用 `--push` 或 `--create-pr` 参数直接推送或创建 PR,并且检查状态会正确更新。这在 GitHub Webhook 服务出问题时特别有用。
安装很简单,macOS 和 Linux 上可以用 Homebrew 或 npm 装,然后 `preloop init` 会引导你完成凭据配置、选择黄金镜像、运行模式等步骤。`preloop serve` 启动引擎,`preloop run` 在仓库里跑工作流。
这个项目能直接用在哪些场景?首先是本地快速验证 CI 配置,不用反复 push 等结果;其次是调试复杂的矩阵构建或事件载荷问题;再就是给那些需要频繁跑 CI 的开发者省下 GitHub 托管的分钟数。要注意的坑是:Apple Silicon 上跑 x86_64 的镜像会走 Rosetta 2 转译,性能稍慢;Docker actions 在这条路径上还不支持,会报一个让人摸不着头脑的 `rosetta-wrapper` 错误。另外,控制平面用的是 FSL-1.1-MIT 许可证,源码可见但你不能拿它去做托管的 CI 服务来和 Preloop 竞争,其余部分都是 MIT。
如果你受够了“push 等 CI”的循环,或者想深入理解 GitHub Actions 的执行机制,Preloop 值得一试。
内容与图片版权归原作者所有 · 原文: https://github.com/preloopdev/preloop