Runner Scale Set Client 适合已经具备 Mac 节点自动交付、初始化、回收和外部日志能力的平台团队试点;如果这些环节还依赖人工,就不要把它当成安装后自动扩容的成品。你本周应先用一组可丢弃的远程 Mac 节点验证“接收扩缩容信号 → 创建节点 → 注册 JIT Runner → 执行任务 → 转存日志 → 销毁重建”的完整链路,失败时保留固定 Runner 池,并采用预热节点加人工扩容的双轨方案。
谁应该在本周启动评估?
这篇文章适合维护多个 GitHub Actions Mac Runner、希望按构建队列动态增减节点的 DevOps 工程师。
如果你需要隔离代码签名任务、避免不同工作流复用同一工作区,或者正在比较固定远程 Mac 节点、预热池与按任务创建节点,这套判断框架可以直接用于评审。
截至 2026 年 9 月 6 日,GitHub 官方仓库仍将 Runner Scale Set Client 标为 Public Preview。它可以用于包括 macOS 在内的自定义 Runner 扩缩容方案,但客户端本身只负责编排 Scale Set API、扩缩容信号、消息会话和 JIT 配置,Mac 主机的供给与生命周期仍由你实现。官方仓库状态与能力说明
⚠️ 注意:Scale Set Client 与 ARC 不是同一个东西。没有 Kubernetes 也可以使用 Client,但你必须自己承担节点创建、系统初始化、Runner 启动、失败回滚和销毁清理。
第一项指标:Scale Set Client 的 Mac 节点供给能力
先不要从 runs-on 或安装脚本开始。真正的判断点是:你的平台是否能在收到扩缩容需求后,自动申请一台真实 macOS 主机,并让它在可控时间内完成初始化。
Runner Scale Set Client 提供的是控制接口,不是 Mac 资源池。官方说明中,客户端会持续获取扩缩容信号,并通过 JIT 配置让外部创建的 Runner 加入 Scale Set;具体的进程、虚拟机或物理机供给由集成方负责。Runner Scale Set Client 工作流程
你需要检查以下证据,而不是只看 API 是否返回成功:
- 节点是否能自动申请或从可用租赁池中分配;
- macOS 是否完成账户、SSH、网络、Xcode 和依赖初始化;
- Runner 是否能以目标名称和标签注册;
- 初始化失败时是否自动释放节点;
- 节点创建成功但 Runner 启动失败时,是否有重试和回滚记录;
- 节点被销毁后,GitHub Actions 中是否不会留下长期在线的失效 Runner。
如果无法提供这些交付日志,结论应是“固定池调度”,而不是“已实现弹性扩容”。你可以先在 VMSPIN 的远程 Mac 方案页面 中准备一组可独立重建的测试节点,再把自动化交付链路接入 Client。
第二项指标:Runner 生命周期与隔离强度
Mac Runner 的生命周期会直接影响工作区残留、证书暴露和任务串扰。GitHub 官方建议自动扩容场景优先使用临时自托管 Runner,因为每个临时 Runner 最多处理一个任务,完成后自动注销;长期在线 Runner 则可能在停止或维护期间仍被错误分配任务。自托管 Runner 生命周期建议
| 方案 | 队列响应 | 工作区隔离 | 证书与密钥风险 | 适合场景 |
|---|---|---|---|---|
| 长期在线 Runner | 通常无需启动 | ❌ 需要人工清理 | 高,容易残留 | 稳定、低敏感度的开发构建 |
| 单任务临时 Runner | 需要完整交付 | ✅ 任务后注销并重建 | 较低,但依赖清理自动化 | 普通构建、测试和隔离任务 |
| 预热临时节点 | ✅ 可缩短首个任务等待 | ✅ 每个任务仍应独立 | 较低 | 队列波动明显的团队 |
| 固定节点加人工扩容 | 取决于值班响应 | ⚠️ 需严格分池 | 中等 | 自动化尚未完整的过渡阶段 |
JIT Runner 的安全边界也要单独验证。GitHub 的 REST API 可以生成一次性配置,Runner 启动时读取 JIT 配置,任务完成后自动移除;官方安全文档同时提醒,重复使用硬件时仍需确保环境被清理,否则可能暴露前一任务的信息。JIT Runner 安全使用说明
代码签名和发布任务不应与普通开发构建共用节点池。你可以让普通构建先进入试点,但将签名证书、临时钥匙串和发布权限放到独立的 Runner Group,并把节点回收作为发布流程的硬性门槛。
第三项指标:非 Kubernetes 架构下的扩缩容路径
可以,但不要把“无需 Kubernetes”理解成“无需控制器”。
官方仓库明确说明,Runner Scale Set Client 是从 ARC 项目中拆出的独立 Go 客户端,可以在不采用完整 ARC 和 Kubernetes 的情况下构建自定义扩缩容方案。Client 与 ARC 的关系说明
没有 Kubernetes 时,你可以把控制面放在现有的 CI 基础设施、任务调度器或常驻服务中,核心链路如下:
- 创建或更新 Runner Scale Set;
- 监听 GitHub Actions 返回的需求信号;
- 根据需求数量调用 Mac 节点交付接口;
- 为新节点生成 JIT Runner 配置;
- 在 Mac 上启动 Runner 进程;
- 任务结束后注销、清理并销毁节点;
- 将 Runner 日志和节点交付日志写入外部存储。
工作流仍然只需要把 runs-on 指向 Scale Set 名称。Scale Set 的标签和 Runner Group 负责路由,但不会替你完成 macOS 环境准备。Runner Scale Set 的官方概念说明
示例中的组织、仓库、App ID、令牌和节点名称必须使用占位符:
jobs:
ios-build:
runs-on: <MAC_SCALE_SET_NAME>
steps:
- uses: actions/checkout@v4
- name: Build
run: xcodebuild -workspace <WORKSPACE_PATH> -scheme <SCHEME_NAME>
因此,“没有 Kubernetes 能否使用”的答案是肯定的;但你需要用其他方式承担 ARC 原本负责的监听、扩容、失败重试和节点回收职责。若这些能力还没有落地,固定 Runner 池反而更容易控制故障范围。
第四项指标:冷启动时间的四段拆解
不要只观察整个工作流从排队到完成的总耗时。Mac 弹性节点至少要拆成四段:
- 队列等待:GitHub Actions 等待可匹配的 Runner;
- 节点交付:分配或启动真实 Mac;
- 环境初始化:安装或恢复 Xcode、Simulator runtime、依赖和证书;
- Runner 注册:加载 JIT 配置并接收任务。
按任务创建节点可以减少闲置,但会把节点交付与环境初始化时间放到首个任务之前。固定节点的等待时间更稳定,却要持续承担闲置、补丁、环境漂移和人工维护成本。预热临时池位于两者之间:保留少量已完成初始化的节点,同时在任务结束后销毁工作区。
| 策略 | 主要收益 | 主要代价 | 你应观察的指标 |
|---|---|---|---|
| 纯 JIT | 闲置资源少,隔离强 | 首个任务等待更长 | 节点交付失败率、首任务排队时间 |
| 最小预热池 | 高峰时更快接单 | 有预热闲置和补充成本 | 预热命中率、补充成功率 |
| 固定 Runner 池 | 路径简单,响应稳定 | 长期在线、环境漂移和清理成本 | 利用率、维护工时、任务串扰 |
这里不能套用通用的“超过多少秒就必须预热”阈值。你应在自己的 Mac 配置、租赁周期和任务类型上记录数据,再判断是否值得保留预热节点。GitHub 文档只说明:没有匹配 Runner 时,任务会持续排队,直至 24 小时超时;这个时间是服务行为边界,不是你的目标响应时间。自托管 Runner 排队说明
第五项指标:JIT Runner 的 Xcode 环境复现
Runner 注册成功,不代表真实构建能执行。对 iOS 项目而言,Xcode 版本、Simulator runtime、CocoaPods 或 Swift Package 依赖、缓存、钥匙串和签名配置任何一项缺失,都可能让弹性节点在“在线”状态下仍无法交付任务。
你至少要完成三组验证:
- 全新节点首次构建:不使用已有缓存,验证系统版本、Xcode、依赖和项目初始化;
- 第二次缓存构建:确认缓存是否能提升后续任务速度,同时检查缓存是否携带敏感文件;
- 节点销毁后重建:完全删除节点和工作区,再从自动化脚本恢复,验证配置是否可复现。
环境脚本应明确写出 Xcode 选择、依赖安装、钥匙串创建、证书导入和缓存目录。不要把这些步骤隐藏在人工登录后的桌面操作中,因为 Runner Scale Set Client 不会自动解决 macOS 镜像制作、图形会话或签名环境初始化。
GitHub REST API 生成 JIT 配置时,需要指定 Runner 名称、Runner Group、标签和工作目录;组织级接口支持 GitHub App 安装令牌、细粒度个人访问令牌等认证方式,权限要求也不同。生成组织级 JIT 配置的 REST API 文档
示例只保留占位符,避免把敏感值写入脚本:
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer <TOKEN_PLACEHOLDER>" \
-H "X-GitHub-Api-Version: <API_VERSION>" \
https://api.github.com/orgs/<ORG>/actions/runners/generate-jitconfig \
-d '{
"name": "<RUNNER_NAME>",
"runner_group_id": <RUNNER_GROUP_ID>,
"labels": ["<MAC_LABEL>"],
"work_folder": "_work"
}'
GitHub 文档列出的 JIT 配置接口成功响应为 HTTP 201,标签数组允许至少 1 个、最多 100 个标签;这些参数是接口约束,不代表你的节点已经具备可用的 Xcode 构建环境。JIT 配置接口参数与响应
第六项指标:权限和日志的生产门槛
认证方式应按管理边界选择,而不是为了快速跑通就把个人访问令牌塞进所有机器。GitHub App 更适合平台化管理,可以按组织和 Runner 资源授予权限;个人访问令牌则需要明确轮换责任、失效影响和泄露后的撤销流程。
生产前至少检查:
- GitHub App 或令牌是否只拥有创建、管理 Runner 所需权限;
- JIT 配置是否只在节点启动阶段使用;
- 令牌是否通过安全注入,不写入仓库、镜像和普通构建日志;
- 临时 Runner 日志是否转存到节点外部;
- 节点销毁后,失败任务是否仍能追踪;
- 公开仓库、非可信拉取请求和发布签名任务是否分池。
GitHub 官方明确建议,临时 Runner 的日志应转发到外部存储,因为节点销毁后本地日志可能不可用;同时,公开仓库和不可信代码不应直接获得包含敏感凭据的自托管环境。临时 Runner 日志与安全建议
你可以为每个节点保存一条关联记录:workflow_run_id、节点名、交付请求、JIT 注册结果、任务结束状态、销毁结果和外部日志位置。没有这条记录,失败时你只能看到“构建失败”,无法判断是排队、交付、初始化、签名还是回收环节出错。
三种方案的最终判断:试点、双轨还是暂缓
把前面的证据放进下面的决策表,不要只按“是否想要弹性”做决定。
| 判断结果 | 必须满足的条件 | 推荐方案 | 暂时不要做的事 |
|---|---|---|---|
| 试点 | Mac 节点可自动交付、初始化、回收;JIT 注册和外部日志均通过验证 | 非发布工作流先接入临时节点,再逐步增加并发 | 不要直接迁移签名和生产发布 |
| 双轨 | 队列波动明显,但节点交付或环境恢复仍不完整 | 保留固定 Runner,增加少量预热节点,人工处理峰值 | 不要宣称已实现全自动弹性 |
| 暂缓 | 任务量稳定、节点数量少,或每次构建都依赖人工桌面配置 | 继续使用固定远程 Mac 池,先完善自动化脚本 | 不要为低波动负载引入复杂控制面 |
成本也必须按完整生命周期核算。除了 Mac 节点租赁周期,还要加入预热闲置、环境准备、失败重建、外部日志存储、证书维护和平台工程师投入。若你只比较“任务运行了几分钟”,很容易低估弹性方案的真实运维成本。
对于固定节点、预热池和按任务节点,建议在同一批非发布工作流中记录:队列等待、节点交付、初始化恢复、构建失败、日志留存和销毁成功率。不要在没有真实队列与利用记录的情况下,直接推导“弹性一定更省钱”或“JIT 一定更快”。
本周执行时间线:先验证链路,再扩大节点池
第 1 天:定义边界。
明确哪些工作流可以使用临时 Mac Runner,哪些工作流必须留在固定签名池。为组织、仓库、Runner Group 和标签建立最小权限配置。
第 2 天:准备节点模板。
准备可丢弃的远程 Mac 节点,自动完成系统检查、Xcode 选择、依赖安装、缓存策略和日志转存。不要把人工桌面配置作为成功条件。
第 3 天:接入 Scale Set Client。
先让 Client 接收扩缩容信号,再调用节点交付接口。所有组织、仓库、令牌、路径和节点名称使用占位符,避免把真实凭据混入测试代码。
第 4 天:验证 JIT 生命周期。
执行一次普通构建,确认 Runner 注册、接单、完成任务、自动注销和节点销毁均有记录。再故意制造初始化失败,检查是否会释放失败节点并保留诊断日志。
第 5 天:验证重建能力。
销毁节点后重新创建,执行全新节点首次构建。重点检查 Xcode、Simulator runtime、依赖、缓存和签名配置是否能从脚本恢复。
第 6—7 天:做方案评审。
将固定节点、预热池和纯 JIT 的队列与恢复记录放在同一张表中。如果交付和日志证据完整,进入小范围试点;如果只有部分自动化,采用双轨;如果负载稳定且节点很少,暂缓扩缩容改造。
固定远程 Mac 池的优点是路径直接、节点可长期保留,但缺点也很明确:工作区清理依赖纪律,环境容易漂移,签名任务可能与普通构建共享机器,峰值时还会产生排队。相比之下,按任务租用可独立重建的 Mac 节点,更适合验证 JIT Runner、环境复现和任务隔离;但它并不适合所有长期稳定重负载,也不适合必须持续占用物理接口的场景。你可以先参考 VMSPIN 的方案与计费页面,按测试周期准备节点,再用真实记录决定是否扩大租用规模。
如果你本周只完成一件事,就完成一次“非发布工作流的全生命周期验收”:节点交付成功、JIT Runner 只接一个任务、Xcode 环境可重建、日志在节点外部留存、节点销毁后没有残留 Runner。证据达到这个标准,再考虑把 VMSPIN 的远程 Mac 节点接入更大的弹性池;否则,固定 Runner 加预热节点的双轨方案通常更稳妥。