GitHub Actions macOS Runner 的官方标准费率按作业分钟计费,部分分钟会向上取整。 截至 2026 年 8 月 15 日,官方文档列出的标准 macOS Runner 费率为 0.062 美元 / 分钟。但这只是平台账单,不是一次成功交付的完整成本。低频构建、公开仓库或不愿维护节点的团队,优先选托管 Runner;持续构建、固定 Xcode、代码签名、缓存复用和内网依赖较多时,自托管远程 Mac 通常更有控制力。多数团队不必二选一,双轨部署往往更稳妥。参考:GitHub Actions Runner 计费说明。
这篇文章适合 3 类人:
- 独立开发者:想判断少量 iOS 构建是否值得维护专属 macOS 节点。
- 移动研发团队:需要控制 Xcode 版本、缓存、签名环境和私有依赖访问。
- DevOps 或平台负责人:需要估算多仓库并发构建的真实成本与运维责任。
最后更新于 2026 年 8 月 15 日,费率、Runner 规格与系统兼容信息核实自 GitHub Actions 官方文档、官方计费页和 Apple Developer 系统要求页。
01 先把 CI 成本从“分钟价”改成“成功交付价”
托管 Runner 的优势是弹性。任务开始时获得新的执行环境,任务结束后释放。自托管 Runner 的优势是持续存在。你可以保留工具链、缓存、钥匙串和网络配置,但也必须为节点没有任务的时间付费。
因此,建议你先用下面的公式计算,而不是直接问“多少分钟后自托管更便宜”。
托管方案月度成本:
实际计费分钟 × 对应 Runner 费率 + Actions 存储与缓存成本 + 并发等待造成的人工或交付损失
自托管方案月度成本:
节点租赁周期成本 + 空闲时间成本 + 维护工时 × 人工成本 + 故障恢复成本 + 密钥和网络管理成本
GitHub 会将每个任务使用的部分分钟向上取整。也就是说,许多短任务不能简单地用总执行秒数相加后再乘费率。私有仓库还要结合账户包含的分钟额度、Runner 类型和实际账单核对。参考:GitHub Actions Runner 计费页。
| 成本变量 | 托管 Runner 的取数方式 | 自托管远程 Mac 的取数方式 |
|---|---|---|
| 执行时间 | 从工作流运行记录导出实际计费分钟 | 从 Runner 日志统计任务执行时间 |
| 等待时间 | 统计排队到分配节点的时间 | 统计等待在线空闲节点的时间 |
| 并发 | 查看同时运行的 job 数量与失败重试 | 记录节点数量、每台并行能力和排队情况 |
| 缓存 | 统计缓存命中、恢复耗时和存储占用 | 记录依赖缓存、DerivedData 与磁盘清理耗时 |
| 运维 | 通常不由你负责主机更新 | 记录更新、重启、断网、Runner 升级和人工处理 |
| 故障损失 | 统计平台失败、重试和排队影响 | 统计节点不可用、任务中断和重建时间 |
你的第一项动作不是购买节点,而是导出最近一个完整账期的工作流数据。至少保留以下字段:
- 仓库名称和工作流名称;
- job 的实际执行时间;
- 排队时间;
- 使用的
runs-on标签; - 失败与重试次数;
- 缓存命中率;
- 每周和每月构建次数;
- 并发峰值;
- 签名、归档和发布任务所占比例。
02 费用指标:低频负载不要为固定节点买空闲时间
低频构建通常包括手动发布、每周版本打包、少量 Pull Request 检查。此时托管 Runner 的主要价值不只是“按分钟付费”,而是你不用为剩余时间承担节点成本。
自托管节点即使整天没有任务,也可能持续产生租赁费用。还要考虑节点被更新、重启或卡在钥匙串解锁状态后,下一次构建无法直接运行。
| 负载类型 | 你应重点观察的指标 | 更可能合适的方案 |
|---|---|---|
| 偶发发布 | 每月实际执行分钟、首次排队时间、失败重试 | 托管 Runner |
| 每日持续构建 | 月度占用时长、缓存收益、Xcode 固定需求 | 双轨试运行 |
| 多分支高并发 | 峰值并发、排队时间、节点扩展速度 | 托管或多节点自托管 |
| 签名与归档 | 证书驻留、钥匙串访问、归档一致性 | 自托管远程 Mac |
| 内网依赖 | 私有包仓库、内网 API、访问控制 | 按网络方案逐项验证 |
不要设置一个通用的“每月达到多少分钟就一定自托管”的结论。不同项目的 Xcode 版本、依赖安装时间、缓存命中率和人工维护成本差异很大。
更可靠的做法是计算你的有效占用率:
有效占用率 = 实际构建占用时长 ÷ 节点可用时长
如果有效占用率很低,但你又没有固定环境、签名或内网要求,托管 Runner 的弹性通常更有价值。反过来,如果节点长期有稳定任务,且每次构建都要重复安装相同工具链,自托管方案才可能形成成本优势。
GitHub 的托管 Runner 在每个 job 中使用新的执行实例。这个特性减少了环境残留,但也意味着你不能把一个 job 产生的本地状态当作下一个 job 必然存在。参考:GitHub Runner 选择说明。
03 效率指标:缓存收益必须和环境差异分开测
自托管 Runner 常被认为“因为缓存,所以一定更快”。这个判断不完整。
长期节点可以预装 Homebrew、Ruby、Node.js、Swift 工具链和 CocoaPods,也可以保留依赖缓存、编译中间产物和 DerivedData。可是,长期保留状态也可能带来旧依赖、残留配置、损坏缓存和不可复现构建。
你需要把两个因素拆开:
- 芯片与系统差异:例如 Intel 与 Apple Silicon 的执行表现不同。
- 缓存与环境差异:例如依赖已经存在,或者 Xcode 不需要重新准备。
测试缓存收益时,至少固定以下条件:
- 相同项目;
- 相同提交;
- 相同 Xcode 版本;
- 相同 macOS 大版本;
- 相同依赖锁定文件;
- 相同构建参数;
- 分别测试冷缓存与热缓存。
| 测试项目 | 托管 Runner | 自托管 Runner | 需要记录的证据 |
|---|---|---|---|
| 冷启动准备 | 新环境安装依赖与工具 | 节点已有或没有预装工具 | 准备阶段耗时 |
| 依赖恢复 | 使用 Actions 缓存 | 使用本地缓存或自建缓存 | 命中率与恢复时间 |
| Xcode 构建 | 每次从干净实例开始 | 可能保留 DerivedData | 编译、链接、归档耗时 |
| 磁盘清理 | 环境结束后释放 | 需要人工或脚本清理 | 清理耗时与失败次数 |
| 可复现性 | 环境边界更清晰 | 长期状态可能污染 | 重跑结果差异 |
如果自托管节点的热缓存明显更快,你还要计算清理成本。缓存不是越大越好。缓存长期不清理,会把磁盘空间、恢复时间和故障排查时间一起推高。
04 控制权指标:Xcode、签名和内网决定节点价值
对于普通 lint、单元测试和不涉及发布证书的检查,托管 Runner 往往已经足够。真正需要自托管的,通常是对环境身份有要求的任务。
固定 Xcode 与 macOS 组合
Xcode 与 macOS 存在版本兼容边界。Apple Developer 的系统要求页会随着 Xcode 版本更新,列出对应的最低 macOS 要求。你不能只在工作流里写一个模糊的 macos-latest,然后假设未来仍然满足项目要求。参考:Apple Developer:Xcode 系统要求。
固定版本的价值在于:
- 减少 SDK 自动变化;
- 避免依赖突然无法编译;
- 让失败构建更容易复现;
- 降低临时升级带来的回滚压力。
但自托管也不是永久冻结。macOS、Xcode、Runner 软件和依赖都需要更新。你必须建立升级窗口,而不是把节点当成永远不变的机器。
签名材料与钥匙串
代码签名任务需要考虑证书、描述文件、钥匙串解锁权限和日志暴露范围。长期节点更容易保留签名材料,操作路径更稳定,但密钥驻留时间也更长。
托管环境的隔离性更强。每个 job 使用新的环境,有利于减少上一次任务留下的状态。代价是你需要在每次任务中准备证书、配置文件和临时钥匙串。
建议把签名任务单独拆成 job,并使用独立标签。例如:
jobs:
test:
runs-on: macos-latest
archive:
needs: test
runs-on: [self-hosted, macos, signing]
GitHub 官方支持使用标签和 Runner 组选择执行节点,也支持在同一个工作流中让不同 job 运行在不同类型的 Runner 上。参考:GitHub Runner 选择文档。
内网与私有依赖
不要笼统地说托管 Runner“无法访问内网”。可用的网络能力与 Runner 类型、组织计划、网络架构和安全策略有关。GitHub 的 macOS Runner 文档也列出了不同 Runner 的网络限制,尤其是 macOS larger runner 并不具备所有 Linux 和 Windows larger runner 的网络能力。参考:GitHub larger runners 参考。
你应该逐项验证:
- 私有包仓库是否允许访问;
- 内网 API 是否需要固定出口地址;
- 防火墙是否支持当前 Runner 类型;
- 是否需要 VPN、Tailscale 或跳板机;
- 证书和访问令牌是否能在 job 中安全注入;
- 失败后是否会留下敏感日志。
如果内网访问是核心要求,自托管远程 Mac 通常更容易纳入现有网络控制体系。但这仍然需要你验证实际链路,不能仅凭“自托管”三个字下结论。
05 运维指标:Online 不等于生产可用
自托管 Runner 需要运行 Runner 应用,并持续与平台通信。没有在线且空闲的匹配节点时,job 会保持排队;如果排队超过官方规定的时间,任务会失败。参考:GitHub 自托管 Runner 参考。
因此,下面这些工作都要计入成本:
- macOS 更新与重启;
- Xcode 安装、切换和回滚;
- Runner 软件更新;
- 磁盘空间监控;
- 缓存清理;
- 网络断线恢复;
- SSH 或远程桌面登录;
- 钥匙串异常处理;
- 任务中断后的重试;
- 节点损坏后的重新部署。
GitHub 官方文档要求自托管 Runner 应保持在线、能够通信并运行 Runner 应用。这个要求说明了运行责任在你这一侧,但“显示 Online”只能证明节点当前能连接,不能证明它可以稳定完成签名、归档和恢复任务。
建议你用下面的验收清单,而不是只看控制台状态:
- [ ] 节点重启后能自动启动 Runner;
- [ ] 断网恢复后能重新连接;
- [ ] 构建中断后不会留下锁死的钥匙串;
- [ ] 磁盘空间不足时会主动告警;
- [ ] Xcode 切换后能运行一条基准构建;
- [ ] 任务失败后可以安全重试;
- [ ] 节点不可用时,普通测试会回退到托管 Runner;
- [ ] 签名任务不会被错误路由到普通节点。
06 三种部署方案的实际取舍
下面的表格不是替你做结论,而是帮助你把团队情况映射到方案。
| 方案 | 成本结构 | 控制力 | 适合任务 | 主要风险 |
|---|---|---|---|---|
| 全部托管 | 按实际 job 使用量计费 | 中等 | lint、单元测试、低频发布 | 版本、缓存和网络边界受平台约束 |
| 全部自托管 | 按节点周期与运维投入计费 | 高 | 固定 Xcode、签名、归档、内网任务 | 空闲浪费、节点故障和密钥驻留 |
| 双轨部署 | 两种成本叠加,但任务分层 | 较高 | 通用测试托管,敏感任务自托管 | 路由规则和监控更复杂 |
托管 macOS Runner 的规格、镜像标签和费率都可能变化。当前官方文档列出了标准 macOS Runner,以及 macOS larger runner 的不同架构和资源组合。你在采购或迁移前,应直接核对当日官方页面,不要引用旧文章里的配置截图。参考:GitHub-hosted Runner 参考。
07 第一步:用真实工作流做双轨试运行
不要先迁移全部流水线。选择一组能代表实际压力的工作流:
- 一个 Pull Request 检查;
- 一个每日构建;
- 一个 Xcode archive;
- 一个代码签名任务;
- 一个需要私有依赖的任务。
然后让相同提交分别运行在托管 Runner 和自托管远程 Mac 上,记录至少一个完整租赁周期或完整账期的数据。
| 指标 | 托管记录 | 自托管记录 | 判断方式 |
|---|---|---|---|
| 月度账单 | 实际 Actions 费用 | 节点周期、人工与故障费用 | 比较完整成本 |
| 排队时间 | job 排队到开始 | 等待在线空闲节点 | 看交付延迟 |
| 执行时间 | 冷环境与缓存结果 | 热缓存与清理后结果 | 分离环境和缓存收益 |
| 失败率 | 平台与脚本失败 | 节点、网络与环境失败 | 看可恢复性 |
| 维护时间 | 平台侧责任较少 | 你的工时记录 | 加入人工成本 |
| 签名可靠性 | 临时密钥流程 | 长期钥匙串流程 | 看安全与复现 |
试运行结束后,不要只看哪个方案更快。你还要问:
- 成本是否稳定;
- 失败是否容易定位;
- 节点是否需要人工值守;
- Xcode 升级是否可回滚;
- 内网任务是否能稳定完成;
- 签名材料是否更容易控制;
- 低峰期的节点空闲是否可以接受。
08 决策条件:满足什么条件就选哪种方案
选托管 Runner
若满足以下多数条件,先保留托管:
- [ ] 每周或每月才进行少量 iOS 构建;
- [ ] 任务主要是 lint、单元测试和普通检查;
- [ ] 不需要长期保存 Xcode 或 DerivedData;
- [ ] 没有固定出口、特殊内网和物理设备要求;
- [ ] 团队不想负责 macOS、Xcode 和 Runner 更新;
- [ ] 构建失败时可以接受重新准备环境。
选自托管远程 Mac
若满足以下多数条件,优先试用自托管:
- [ ] 每天持续运行 Xcode CI;
- [ ] 多个仓库需要同一套 Xcode 和依赖;
- [ ] 归档、签名或发布任务占比较高;
- [ ] 热缓存可以稳定减少准备和构建时间;
- [ ] 需要访问私有包仓库或内网 API;
- [ ] 团队能够安排节点监控、升级和恢复;
- [ ] 你能接受按周、月或季度承担节点周期成本。
维持双轨部署
若出现以下情况,双轨通常更合理:
- [ ] 通用测试数量大,但签名任务数量少;
- [ ] 普通 job 不需要内网,归档 job 需要内网;
- [ ] 公开代码检查希望保持弹性;
- [ ] 私有发布流程需要固定工具链;
- [ ] 团队希望先验证远程 Mac,再决定是否扩大迁移;
- [ ] 节点故障时,非敏感任务可以自动回退。
你可以先把低风险任务留在托管 Runner,再把签名、归档和固定环境任务迁移到自托管远程 Mac。这样不会因为一次节点故障让所有 CI 同时停摆。
09 远程 Mac 方案怎样进入成本模型
如果你的工作流已经证明固定 Xcode、缓存和签名环境有价值,下一步可以把 CALMVPS 的远程 Mac 作为自托管节点候选,先做一个租赁周期的并行验证。重点不是看宣传配置,而是核对以下结果:
- 节点交付后多久能完成 Runner 注册;
- SSH、VNC 或网页控制台是否满足日常维护;
- Xcode 与项目依赖能否稳定安装;
- 重启后 Runner 是否自动恢复;
- 归档和签名任务是否能连续运行;
- 节点空闲时段占比是多少;
- 失败后需要多少人工处理时间。
你可以先查看 CALMVPS 的远程 Mac 方案与价格信息,再根据团队所在区域选择节点。需要做实际验证时,不要直接迁移全部仓库,先挑一条签名或归档流水线进行对照测试。
10 常见问题
GitHub Actions macOS 托管 Runner 和自托管 Runner,怎样判断哪种更省?
不要只比较每分钟费率。托管方案要统计实际执行分钟、并发等待、缓存和存储费用;自托管方案则要加入整段租赁周期、空闲时长、维护工时、故障恢复和密钥管理成本。用最近一个完整账期的真实数据计算,通常比套用固定临界分钟数更可靠。
iOS 构建量达到什么程度,才适合改用自托管 Runner?
没有适用于所有团队的固定分钟数。你应该先观察队列时间、执行时间、节点月度占用率和人工维护时间。如果构建持续发生,固定 Xcode 与缓存明显缩短流水线,且托管账单和等待时间已经影响交付,就值得做一个租赁周期的自托管试运行。
远程 Mac 做 GitHub Actions Runner,需要计算哪些隐性成本?
至少包括节点租赁周期、空闲时间、磁盘清理、macOS 与 Xcode 更新、Runner 软件升级、断网重连、重启恢复、监控告警、证书和钥匙串维护,以及失败构建造成的人工排查时间。节点显示 Online,只能说明它能通信,不能证明它具备生产可用性。
托管 Runner 和自托管 Runner 能否放在同一条工作流里?
可以。你可以把 lint、单元测试和普通检查放在托管 Runner,把签名、归档、固定工具链或内网依赖任务放到带有明确标签的自托管 Runner。通过不同 job 的 runs-on 分配节点,并让依赖关系控制执行顺序,就能形成双轨流水线。
11 把当前方案和远程 Mac 放回同一张账单
如果你现在使用的是完全托管方案,真实缺点通常不是某一次构建太贵,而是环境准备重复、固定 Xcode 控制力有限、签名和内网任务需要额外适配;如果你现在用的是本地 Mac mini 或闲置工作站,则可能遇到设备采购、硬件故障、断电断网和无人值守恢复问题。CALMVPS 的远程 Mac 更适合拿来做一个可撤回的自托管验证节点:你按租赁周期计算成本,通过 SSH、VNC 或网页控制台维护,再用真实的构建耗时、排队时间和故障记录决定是否扩大规模。需要开始试运行时,可从 CALMVPS 的远程 Mac 订购入口选择合适周期;如果长期稳定重负载、需要本地物理设备或必须完全控制硬件,直接自购 Mac 仍可能更合适。