Runner 自动注销,不等于 Mac 已经恢复干净。最快的判断是:公共仓库、不可信代码或任务间必须强隔离时,优先使用临时 Runner;需要稳定签名环境、外设或高命中缓存时,使用权限受限的常驻 Runner。多数生产团队应采用“临时执行池+少量受控常驻节点”的双轨方案。

这篇文章适合三类人:需要为拉取请求和普通测试任务提供干净环境的平台团队;维护代码签名、真机或固定网络依赖的移动研发团队;正在计算 Mac Mini M6 Runner 数量、队列容量和扩缩容方式的技术负责人。

先按任务风险划分 Runner,而不是先按设备数量采购

GitHub Actions 临时 Runner 和常驻 Runner 的核心差异,不只是“任务结束后是否注销”。真正需要比较的是:工作目录、派生进程、钥匙串、缓存、网络配置和本地凭据,能否在任务完成后恢复到可验证状态。

GitHub 官方建议,自动扩缩容场景优先采用临时自托管 Runner,不建议用常驻 Runner承担自动扩缩容。临时 Runner只保证 GitHub 服务端向该 Runner 分配一个任务,任务完成后自动注销;擦除磁盘、删除用户、重置系统和重新注册设备,仍然需要你自己的自动化负责。(GitHub 官方自托管 Runner 文档)

这会带来至少四个容易被低估的限制:

  • 隔离限制:注销 Runner 不会自动终止所有由构建脚本启动的子进程,也不会自动清除用户目录、系统钥匙串或外接磁盘中的文件。
  • 缓存代价:常驻节点可以保留 Swift Package、CocoaPods、DerivedData 和模拟器运行时,但缓存越多,任务串扰和环境漂移的排查成本越高。
  • 凭据风险:签名证书、临时密钥、发布账号和 GITHUB_TOKEN 可能被构建脚本、第三方依赖或错误日志间接接触。
  • 恢复成本:Mac 是物理设备。它不像 Linux 容器那样天然具备快速销毁和重建能力,系统更新、磁盘重置、重新注册和故障替换都需要平台团队编排。

GitHub 文档还明确提醒,自托管 Runner 不保证每个任务都在干净的临时虚拟机中运行;公共仓库或可接收外部贡献的仓库尤其容易让不可信代码进入 Runner 权限范围。(GitHub Actions 安全使用说明)

注意: 不要把 --ephemeral 当作“设备自动擦除”开关。它是 GitHub 任务生命周期设置,不是 Mac 硬件生命周期方案。

个人项目与可信私有仓库:常驻节点通常更容易维护

如果你维护的是个人项目,或者团队内部使用、任务来源相对可控的私有仓库,常驻 Runner 可以减少工具链重复安装和缓存下载。对低并发 iOS 构建来说,固定的 Xcode、模拟器运行时和依赖缓存,往往比每次重新准备环境更容易操作。

但“私有”不等于“所有代码都可信”。拥有读取权限的人可能创建分支或拉取请求,工作流也可能执行来自依赖安装脚本、构建插件和代码生成器的命令。因此,常驻 Mac Mini M6 不应同时承担所有仓库和所有分支的任务。

建议你至少做这几件事:

  • 每个任务开始前删除工作区,而不是只执行 git clean。
  • 每个任务结束后清除临时密钥、导出的归档包、日志中的敏感变量和用户缓存。
  • 将常驻 Runner 放入专用 Runner group,只允许明确的仓库使用。
  • 用自定义标签区分普通编译、模拟器测试、真机测试和发布任务。
  • 禁止普通拉取请求工作流接触发布证书和生产环境账号。

GitHub 的标签是累积匹配规则,工作流指定的标签必须同时满足;组织级 Runner group 还可以进一步限制哪些仓库有资格使用节点。(GitHub Actions 工作流中的自托管 Runner 配置)

如果你只是想把一个可信私有仓库迁移到 macOS 自托管 Runner,可以先参考 kvmsync 的 GitHub Actions 与 Mac 节点资料,但不要因为节点是租用的就跳过清理和权限设计。

接收外部贡献的开源团队:优先一次任务一次身份

开源团队最不适合把长期保存凭据的常驻 Mac 直接暴露给拉取请求。外部贡献者提交的代码可能修改构建脚本、依赖版本、测试命令甚至工作流调用方式。只要任务能访问 Runner 本地环境,就可能读取残留文件或利用系统权限。

Mac Mini M6 可以承担一次性 macOS Runner,但“能注册”不等于“任务结束后自动干净”。更准确的设计是:

  1. 为任务创建专用 macOS 用户或一次性系统环境。
  2. 使用短时注册凭据完成 Runner 注册,不在磁盘脚本中长期保存令牌。
  3. 为 Runner 设置临时任务属性,使 GitHub 在完成一个任务后自动注销它。
  4. 任务结束后等待子进程退出,停止构建服务和模拟器。
  5. 删除工作区、用户缓存、临时钥匙串与构建产物。
  6. 通过系统快照、磁盘重建或人工验收确认环境达到可重复状态。
  7. 清理失败时,将设备标记为不可调度,不允许它接收下一个任务。

GitHub 提供 REST API 管理 Runner 的注册、删除和标签,这意味着你可以把“注册—执行—注销—清理—重新注册”串成控制器流程,而不是靠人工登录设备处理。相关接口需要相应的仓库、组织或企业权限。(GitHub REST API 自托管 Runner 接口)

另外,临时 Runner 的日志必须转存到外部存储,否则一旦设备被重置,排查失败任务所需的信息可能一并消失。GitHub 官方也建议在生产部署临时 Runner 前,先确保日志被外部保存。(GitHub 官方自托管 Runner 文档)

高频构建的小型移动团队:把缓存收益与串扰风险分开算

小型移动研发团队通常会遇到一个矛盾:常驻 Runner 的缓存可以缩短构建准备时间,但多项目共用同一节点后,环境漂移和任务互相污染会吞掉这部分收益。

例如,项目 A 更新了 Swift Package,项目 B 随后复用本地缓存;某个测试任务留下模拟器进程,下一次任务启动时出现端口占用;某个脚本修改了系统工具链路径,失败重跑却在另一套环境中通过。这些问题不一定每天发生,却会让 CI 结果变得难以复现。

因此,普通编译和敏感发布任务应分开路由:

任务类型 推荐 Runner 主要原因 需要保留的资产
拉取请求编译 临时 Runner 或可验证重置节点 降低任务残留影响 最少量依赖缓存
普通单元测试 临时 Runner 便于失败后重新创建环境 测试报告与外部日志
模拟器回归 受控常驻或专用临时池 运行时和设备状态较复杂 指定模拟器运行时
真机测试 受控常驻 Runner 需要物理设备、线缆和配对状态 设备配对信息
App 签名与发布 少量受限常驻 Runner 凭据与审批边界更重要 受控钥匙串和证书

Apple 已公布的 Mac mini M6 规格包括 12 核 CPU、最高 32GB 统一内存、最高 170GB/s 内存带宽,并提供 2.5Gb Ethernet 与 3 个 Thunderbolt 4 接口;这些参数说明它适合做单一职责的 macOS 构建节点,但不能直接推导出并发 Runner 数量。(Apple Mac mini 官方规格)

截至 2026 年 9 月 7 日,Mac mini M6 已发布,但首批设备预计从 2026 年 9 月 22 日开始送达,因此实际重置耗时、缓存命中收益和并发容量仍应以同一工作流实测为准。(Apple 发布 Mac mini M6 的官方公告)

如何降低不同任务之间的状态残留?
不要只依赖工作区清理。你还需要清理派生进程、用户目录、临时钥匙串、模拟器状态、包管理器缓存和网络代理配置;对无法验证清理结果的节点,下一任务不应继续调度。

需要签名与发布的团队:常驻可以,但必须缩小权限

iOS 签名任务是否放进临时 Runner,取决于凭据注入和销毁能否被审计。对于普通开发签名、短期测试证书或不涉及生产发布的任务,临时 Runner可以降低残留风险;对于生产发布,单纯注册 --ephemeral 并不足够。

更稳妥的做法是保留少量受控常驻发布节点,并同时限制:

  • 可使用节点的仓库范围;
  • 允许执行发布任务的分支;
  • 工作流来源和审批环境;
  • 证书导入、使用和销毁的日志;
  • 发布账号的最小权限;
  • 节点故障后的接管与证书撤销流程。

Apple Silicon 原生构建需要确认工具链和依赖是否支持 arm64;Apple 的开发者文档说明,Xcode 支持将 arm64 纳入通用二进制构建,旧的 x86_64 工具则可能通过 Rosetta 运行。(Apple Silicon 应用迁移文档) 这意味着迁移到 Mac Mini M6 时,不仅要验证签名,还要验证插件、命令行工具、脚本和二进制依赖的架构兼容性。

维度 临时签名节点 受控常驻签名节点
凭据暴露面 可缩短凭据存在时间 需要严格限制访问范围
环境复现 每次准备成本较高 工具链和钥匙串更稳定
真机与外设 不适合频繁重配 更适合固定设备
审计重点 注入、使用、销毁 使用范围、访问记录、定期重置
故障接管 需要备用镜像或备用设备 需要第二台同权限节点

如果你的签名流程还不能证明证书和账号能在任务结束后可靠销毁,就不要把它包装成“临时隔离”。先降低常驻节点权限,再逐步补齐重置和审计能力。

大规模平台工程:把扩缩容拆成五个控制面

大规模团队不能只看“当前有几台 Mac”。Mac Runner 的扩缩容至少要持续记录排队时长、任务执行时长、并发峰值、失败重跑次数和节点恢复时间。

GitHub 的 workflow_job Webhook 会提供任务排队、执行中和完成等生命周期事件,你可以据此触发注册、路由和回收流程;但 Webhook 到达延迟会影响扩容决策,不能把它当作绝对实时的容量信号。相关生命周期和临时 Runner要求可参考 GitHub 官方 Runner 管理说明。

建议将控制面拆为五部分:

  1. 容量判断:按队列长度、P95 等待时间和发布高峰记录决定是否增加节点。
  2. 注册与路由:新设备上线后自动注册,并写入用途、架构、Xcode 版本和权限标签。
  3. 日志转存:任务日志、系统日志和清理结果发送到外部存储。
  4. 环境管理:维护 macOS、Xcode、模拟器运行时和依赖工具的可复现镜像或基线。
  5. 失败回收:清理失败、更新失败或任务异常退出时,立即摘除节点,等待人工或自动重置。

不要把 Linux 容器的扩缩容经验直接套在 Mac 硬件上。GitHub 文档明确指出,Docker 容器 action 或服务容器要求 Linux Runner;macOS 节点的外设、系统权限和物理重启能力需要单独设计。

Runner 软件本身默认会自动更新;如果你关闭自动更新,就必须自行维护版本,并在新版本发布后 30 天内完成更新,否则新的 GitHub Actions 功能可能无法正常处理。(GitHub Runner 更新要求)

当某类标签没有可用节点时,任务不会立刻失败,而是会持续排队,直到 24 小时超时。因此,容量告警不能只看设备在线状态,还要看“有标签但无空闲节点”的任务数量。

最终落地:用双轨架构替代“全临时”或“全常驻”

你可以按下面的顺序完成一次试点:

  1. 先挑选一类不接触签名凭据的普通测试工作流。
  2. 为它创建独立 Runner group 和专用标签,不与发布节点混用。
  3. 记录任务排队、执行、清理和失败重跑数据。
  4. 在任务结束后验证工作区、进程、缓存、钥匙串和日志是否完成回收。
  5. 连续观察多个高峰周期,再决定是否增加临时节点。
  6. 将签名、真机和固定网络依赖迁移到受控常驻池。
  7. 为两类节点分别制定更新、清理、故障接管和权限复核标准。
决策条件 选择方案
公共仓库、外部拉取请求或依赖来源不可完全控制 临时 Runner,任务后必须验证重置
任务低频、仓库范围小、缓存收益明显 受限常驻 Runner
需要生产签名、真机或固定外设 少量受控常驻节点
普通测试和发布任务同时存在 双轨架构,按标签与 Runner group 路由
还没有稳定的自动重置流程 暂不扩大临时池,先减少常驻权限
队列等待集中出现在发布高峰 增加短期发布容量,不扩大所有 Runner 权限

你还可以在 kvmsync 的帮助中心确认远程 Mac 节点的连接、交付和故障处理边界;如果需要核对短期节点的可用方式,再查看 kvmsync 的方案页面。

如果你当前使用的是一台长期在线的 Mac,常见缺点是缓存和凭据长期共存、任务之间容易残留状态,发布高峰还会被单节点队列拖慢;直接购买多台 Mac,则会增加闲置设备、系统更新和故障替换成本。更实际的做法是先把普通测试工作流迁移到临时 Mac 执行节点,用相同镜像和权限边界验证队列与清理效果,发布高峰再按需增加短期容量。对需要临时算力、短期 CI 扩容或新 Runner 验证的团队,租赁 kvmsync 的 Mac 节点通常比立即建设一整套长期硬件池更容易控制试错范围。

延伸阅读

kvmsync M4 远程节点

用 kvmsync 灵活部署 Mac Runner

按项目需求租用远程 Mac,临时任务用完即停,常驻构建也能稳定运行。

立即租用 Mac mini M4 对比 M4 套餐