症状:PR 高峰时 Mac Runner 排队,但你又不敢把生产签名节点交给一套仍在 Public Preview 的弹性控制面。
最快解法:值得试点,但不要全量替换固定 Mac 池;先把可重建的临时构建任务接入弹性池,生产签名与低延迟任务保留在预热或专用 Mac 节点。
SECTION 01谁应该看这篇
如果你管理多个仓库的 GitHub Actions Mac Runner,正在处理发布高峰排队,本文可以帮助你判断是否值得引入 Runner Scale Set Client。
如果你负责安全隔离、JIT Runner、Apple Silicon 节点或企业基础设施预算,下面的指标也能帮助你避免把“Runner 自动注销”误判为“Mac 主机已经彻底清理”。
注意:截至 2026 年 9 月 20 日,GitHub 仍将 Runner Scale Set Client 标记为 Public Preview。本文状态与接口信息核实自 GitHub Changelog 的公开预览说明、官方 actions/scaleset 仓库 及相关文档。
SECTION 02先用判断矩阵决定是否试点
GitHub Actions Runner Scale Set Client 的价值,不在于替你“购买或创建 Mac”,而在于把 GitHub 的任务需求信号接入你自己的节点供应系统。官方实现支持 macOS,但主机的创建、初始化、清理和销毁仍由企业负责。官方自托管 Runner 参考 已明确区分了客户端控制面与基础设施供应责任。
| 选项 | 适用条件 | 主要收益 | 首要风险 | 决策 |
|---|---|---|---|---|
| 固定 Mac 池 | 任务量稳定、签名任务多、需要低延迟和长期缓存 | 启动路径短,环境可控,排障边界清晰 | 峰值时排队,低峰期存在闲置容量 | 生产签名和关键发布优先保留 |
| 弹性 Scale Set 池 | 有主机自动交付、任务后擦除、外部日志和故障降级能力 | 峰值时按需增加容量,减少长期闲置 | 冷启动、供应失败和清理不彻底会抵消收益 | 先接入可重建任务 |
| 混合节点池 | 同时存在 PR 高峰、模拟器回归、归档发布和生产签名 | 按信任等级与延迟要求分流 | 需要维护两套节点策略和监控 | 大多数企业的默认选择 |
你可以直接按下面的否决条件执行:
- 没有自动创建、初始化和回收真实 Mac 的能力:暂不引入弹性池。
- 不能在节点销毁前保存诊断日志:暂不把它用于关键流水线。
- 生产签名凭证与普通分支任务共用同一台可复用主机:禁止接入弹性池。
- 团队没有处理 API 权限、消息确认、重复投递和节点失联的值班能力:先继续使用固定池。
- 只有 PR 构建和可重建测试存在明显峰值:适合启动有限试点,而不是重做全部 CI 架构。
SECTION 03GitHub Actions Runner Scale Set Client 的弹性收益如何验证?
Scale Set Client 返回的关键不是“来了多少条事件消息”,而是当前 Scale Set 需要多少在线 Runner。官方仓库使用 statistics.TotalAssignedJobs 表示已分配给该 Scale Set 的任务总量,其中同时包含等待 Runner 的任务和正在运行的任务;它不等于新增 Mac 数量。actions/scaleset 的扩缩容说明 对这一点有明确描述。
因此,你需要同时记录三类数据:
TotalAssignedJobs的变化;TotalRunningJobs与实际空闲 Runner 数量;- 从“收到扩容信号”到“Mac 可接单”的完整耗时。
完全按需创建的策略,适合任务到达分布不稳定、低峰期容量浪费明显的团队,但它会把主机启动、系统解锁、Runner 注册和工具链准备都放进用户可感知的等待时间。保持最小预热容量,可以承接第一波任务,再由按需节点吸收后续峰值。固定基础池则牺牲部分弹性,换取更稳定的排队时间。
这里不要预设“每个事件扩一个节点”或“每个项目保留一个 Mac”。正确做法是使用企业自己的队列记录,观察任务到达是否集中在发布窗口、工作日开始时段或某几个大型仓库,然后比较:
- 峰值排队时间是否下降;
- 冷启动任务的失败率是否上升;
- 预热节点的空闲时长是否可接受;
- 扩容后的节点是否真的有任务可接;
- 供应失败时,任务能否自动回到固定池。
如果你还没有这些记录,当前阶段只能证明“有扩容信号”,不能证明“弹性容量带来收益”。
SECTION 04JIT Runner 隔离了什么,没隔离什么?
JIT Runner 的核心作用是生成一次性的 Runner 配置。GitHub 文档说明,JIT Runner 最多执行一个任务,完成后会从仓库、组织或企业中自动移除。GitHub Secure use reference 同时提醒:如果复用承载 JIT Runner 的硬件,仍需要自动化保证环境干净。
你需要把生命周期拆成四层,而不是只看 Runner 是否注销:
- Runner 注册生命周期:Runner 是否只注册一次任务,完成后是否从 GitHub 移除。
- macOS 主机生命周期:主机是否重建、恢复快照、擦除磁盘或仅重启服务。
- 工作区生命周期:源码、
DerivedData、模拟器数据、依赖缓存和临时文件是否清除。 - Keychain 生命周期:签名证书、Provisioning Profile、临时令牌和登录凭证是否销毁。
这四层中,只有第一层可以由 JIT 配置直接覆盖。其余三层需要你自己的 Mac 供应和清理逻辑。
对于普通私有仓库的 PR 构建,可以使用一次性 Runner 加上主机重建或强制清理。对于生产签名,建议单独划分 Runner group,并使用专用 Mac、专用用户、专用 Keychain 和最小权限的发布流程。Runner group 的访问控制文档 支持按仓库限制哪些工作流可以使用指定 Runner 组。
SECTION 05启动时延与环境交付要分段测量
“Mac 已经开机”不等于“Mac 已经可以运行 iOS CI”。建议把启动链路拆成至少 5 个阶段:
- 主机由供应系统创建或唤醒;
- macOS 完成解锁、网络和后台服务初始化;
- Runner 进程使用 JIT 配置注册;
- Xcode、模拟器、依赖缓存和证书环境完成准备;
- GitHub Actions 接收到 Runner,并开始第一个 Job。
每一阶段都要记录开始和结束时间,不能只看整个 Job 的墙钟时间。GitHub 的 JIT API 会生成供 Runner 在启动时使用的配置,但它不会替你安装 Xcode、解锁系统、准备模拟器或恢复缓存。自托管 Runner REST API 文档 还列出了生成 JIT 配置所需的权限边界,这些权限应纳入企业审计。
你可以按三种策略做对照:
- 完全按需:低峰成本最低,但首个任务承担全部启动时延。
- 最小预热:保留有限数量的 Apple Silicon Mac,峰值时再扩容。
- 固定基础池:关键任务始终进入固定节点,弹性池只处理可延迟或可重建任务。
如果 Xcode 初始化、模拟器准备或依赖下载占据主要时间,单纯增加扩容速度不会解决排队问题。此时更应该优化镜像、缓存和节点预热,而不是继续扩大 Scale Set 数量。
SECTION 06控制面、日志和故障恢复怎么验收?
客户端能正常运行,只能说明控制面进程没有崩溃;企业真正要验收的是故障后能否继续交付任务。
建议至少完成以下 6 步:
- 使用 GitHub App 优先配置认证,并限制到所需组织或企业范围;PAT 只作为受控的备用方案。官方 actions/scaleset 认证说明 将 GitHub App 列为推荐方式。
- 为每个节点生成唯一名称和唯一任务关联 ID,避免供应失败后重复使用旧配置。
- 记录扩容信号、JIT 配置生成、主机交付、Runner 上线、Job 开始和节点销毁事件。
- 在销毁 Mac 前,将 Runner 日志、Job 日志和供应系统日志转存到外部存储。GitHub 明确要求临时 Runner 的诊断日志转存并保留。监控与故障排查文档 可作为验收依据。
- 模拟 Runner 进程崩溃、Mac 供应失败、网络中断、JIT 配置过期和节点执行完任务后无法回收。
- 为每种失败设置降级路线:回到固定 Mac 池、切换备用远程 Mac,或让工作流明确失败并通知值班人员。
不要把“客户端自动重启”当作完整恢复方案。真正的恢复标准是:任务不会永久卡在等待状态,残留节点不会继续接收不该接收的任务,生产签名不会因为弹性池故障而失去可用节点。
SECTION 07FAQ:四个容易误判的架构问题
客户端能否独立完成 Mac 构建机的供应?
不能。它负责连接 Scale Set API、取得任务需求、生成 JIT 配置并管理消息会话;真实 Mac 的创建、开机、系统初始化、Runner 启动、任务后擦除和节点销毁仍由你的供应系统或基础设施团队实现。它是控制面组件,不是 Mac 资源供应商。
GitHub Actions 弹性 Mac Runner 是否必须依赖 Kubernetes?
不必须。官方客户端是独立的 Go 模块,可以对接虚拟机、物理 Mac、托管 Mac 或自定义基础设施。GitHub Actions Runner Controller 文档 面向 Kubernetes 场景;如果你的 Mac 节点无法容器化,直接实现供应控制器通常更合适。
JIT Runner 能否自动隔离 Xcode 工作区和签名凭证?
不能自动完成。JIT 只约束 Runner 注册和任务次数,不能证明主机磁盘、工作区、缓存、Keychain 和签名凭证已经清理。生产签名应使用专用主机和专用凭证生命周期;普通 PR 任务也不应与生产身份共享可复用环境。
固定节点与弹性 Scale Set 在企业流水线中怎样划分职责?
普通 PR 构建、可重建测试和峰值验证适合进入弹性池;生产归档、发布签名、低延迟任务和依赖稳定缓存的流程应保留在固定或预热专用池。通过 Runner group、标签和工作流权限做分流,不要只按照仓库名称决定安全边界。
SECTION 08用 TCO 判断,而不是只看节点单价
企业 Mac 基础设施的 TCO 不应只计算“租用或购买一台 Mac 的价格”。至少需要把下面几项放进模型:
- 固定容量的长期占用成本;
- 预热节点的闲置时间;
- 按需节点的交付与回收成本;
- Xcode、模拟器、依赖和缓存维护成本;
- 认证、日志、监控和故障值班成本;
- 任务失败、重复构建和发布延迟造成的损失;
- 生产签名节点的隔离与备用容量成本。
可以用以下变量建立第一版模型:
月度 TCO = 固定节点成本 + 预热容量成本 + 按需容量成本 + 自动化维护成本 + 故障损失成本
然后按任务类型分流:
- PR 验证:弹性池;
- 模拟器回归:弹性池或预热池;
- 归档发布:固定或专用预热池;
- 生产签名:专用可信 Mac 池;
- 高峰期临时验证:弹性池;
- 需要物理接口、特殊外设或长期状态的任务:固定实体节点。
如果你的团队已经具备自动化交付、节点清理、外部日志和故障切换能力,Runner Scale Set Client 值得进行小范围试点。反过来,如果只是希望 GitHub 自动帮你“变出更多 Mac”,它不会减少基础设施责任,反而会增加供应、权限和审计工作。
截至 2026 年 9 月 20 日,建议你先用一类可重建的 PR 构建任务验证:从扩容信号到首个 Job 的时延、任务后清理是否完整、日志能否留存,以及节点失联时是否能回到固定池。GitHub 后续若修改 Public Preview 状态、macOS 支持范围、认证权限或 Scale Set 接口,应重新核对官方仓库与文档,而不要直接沿用旧实现。
如果你当前方案是全部自购 Mac,常见问题是峰值容量不足、低峰期设备闲置、硬件维护由 IT 长期承担;如果全部依赖临时云端 Mac,又可能遇到启动路径不可控、签名环境难以长期保持和故障切换边界不清。更稳妥的做法通常是保留可信固定池,再用 MACNOX 的真实远程 Mac 作为可验证的弹性容量或备用节点,先验证交付、回收与故障切换,再决定是否扩大规模。你可以先查看 MACNOX 的远程 Mac 方案,再结合 价格与租赁周期页面 评估试点范围,而不是直接把生产签名流水线全量迁移。
SECTION 09常见问题 FAQ
Runner Scale Set Client 能不能自己把 Mac 构建机创建出来?
不能。客户端负责连接 Scale Set API、获取任务需求、生成 JIT 配置并管理消息会话;真实 Mac 的创建、开机、系统初始化、Runner 启动、任务后擦除和节点销毁仍由你的供应系统或基础设施团队实现。它提供控制面能力,不是 Mac 资源供应商。
做 GitHub Actions 弹性 Mac Runner 一定要上 Kubernetes 吗?
不需要。Runner Scale Set Client 是独立的 Go 客户端,可以对接虚拟机、物理 Mac、托管 Mac 或其他自定义基础设施。Kubernetes 更适合已有容器平台和 ARC 运维能力的团队;如果你的 Mac 节点无法容器化,直接实现供应控制器通常更合理。
JIT Runner 能否同时隔离 Xcode 工作区和签名凭证?
JIT Runner 只能保证 Runner 注册层面的临时性,不能自动证明主机、磁盘、工作区和 Keychain 都是干净的。复用同一台 Mac 时,源码、DerivedData、缓存、临时文件和签名身份仍可能残留。生产签名任务应使用专用主机、专用 Keychain 和独立清理流程。
固定 Mac Runner 和弹性 Scale Set 应该怎样分工?
把任务按信任边界和延迟要求拆分:普通 PR 构建、可重建测试和峰值验证进入弹性池;生产归档、发布签名、低延迟流水线和需要稳定缓存的任务留在固定或预热专用池。两类节点通过 Runner group、标签和工作流规则隔离,不要只按项目名称分流。