先看结论:本周先完成一次主备切换演练
GitHub 官方文档明确说明:匹配不到可用的 self-hosted runner 时,任务会持续排队,超过 24 小时仍未运行就会失败。查看 GitHub Runner 路由与排队规则
因此,Mac 打包服务器高可用不能建立在“唯一节点一直在线”上。企业生产发布应采用“主用节点+可验证备用节点”的双轨方案,并把代码、依赖、签名凭证和构建产物从主机状态中解耦。固定基础负载使用长期节点,发布高峰、Xcode 升级和灾备演练再按需增加远程 Mac 容量。
本周建议动作只有一件:选一条真实发布流水线,停止主节点接单,让备用节点完成一次可验证构建。没有日志、Runner 状态、签名结果和构建产物的演练,不算完成灾备建设。
这篇文章适合:
- 管理单台或少量 Mac 构建节点,担心发布故障无法切换的企业 IT 负责人。
- 负责 iOS CI/CD 可用性、构建队列和签名安全的研发效能负责人。
- 需要审核灾备预算、SLA 与 Mac 算力采购方案的技术总监或 CTO。
节点在线不等于发布连续:先划清故障影响范围
发布窗口中,唯一 Mac 节点可能因为掉电、系统无响应、磁盘加密未解锁或远程连接中断而停止接单。此时“机器还能通电”并不等于 Runner 可用,也不等于流水线能继续完成签名、归档和产物上传。
我们建议先定义三个变量,而不是直接拍一个恢复目标:
- 恢复时间目标:从主节点停止接单,到备用节点可以接受有效构建任务之间允许经过多久。
- 可接受的构建状态损失:故障发生时,哪些排队任务可以重跑,哪些已经生成的归档、测试报告和签名产物必须保留。
- 发布阻断范围:故障影响单个项目、一个组织,还是所有需要 Apple Silicon、特定 Xcode 或特定签名资产的流水线。
单节点适合开发验证,不适合承担唯一生产发布路径。冷备可以降低长期持有成本,但切换前必须完成环境安装和凭证准备。温备让备用节点持续接受健康检查和真实项目验证。双活则要求任务路由、并发控制、签名资产和产物去重都经过更严格测试。
多数企业不必一开始就做双活。先把主备双轨做成可重复、可审计的切换流程,通常更容易发现真正的故障点。
⚠️ 经验提醒:备用节点如果只安装了 macOS 和 Xcode,却没有跑过真实归档、签名、依赖下载和产物上传,它仍然只是“可开机的机器”,不是灾备节点。
发布中断场景:主节点离线时,备用节点如何接管
切换的第一步不是立刻启动备用节点,而是先阻止主节点继续接收新任务。否则旧任务可能继续写入缓存、占用签名资产,导致备用节点接管后出现重复构建或状态不一致。
推荐动作如下:
- 在 CI 平台上暂停主 Runner,或移除主节点对应的生产标签。
- 保留已开始任务的日志,标记它们是“运行中”“已失败”还是“等待重试”。
- 检查备用节点在线状态、Runner 标签、工具链版本和磁盘可用空间。
- 将一条低风险但真实的发布流水线路由到备用节点。
- 完成编译、测试、归档、签名和产物校验后,再恢复生产任务。
GitHub Actions 通过 runs-on 标签和 Runner group 选择匹配节点;如果没有在线且空闲的匹配节点,任务会继续排队。查看 GitHub self-hosted runner 路由机制 GitLab 则使用 Runner tags 控制任务匹配,并可限制 Runner 只运行受保护分支或受保护标签的任务。查看 GitLab Runner 标签与保护规则
企业不应把“切换”理解成修改一处 IP 地址。真正的切换包括任务路由、权限边界、凭证可用性、依赖访问和产物上传。
维护升级场景:主线稳定,备用线先验证
系统更新、Xcode 升级和 Swift Package 依赖变化,都可能让原本通过的构建失败。把维护安排在夜间,只能降低人为冲突,不能消除工具链兼容性风险。
我们建议采用双轨方法:
- 主用线:保持当前已验证的 macOS、Xcode、SDK、依赖和流水线脚本,不在发布窗口临时升级。
- 备用线:提前安装候选版本,先运行真实项目的编译、单元测试、归档和签名。
- 切换条件:备用线必须产出与主用线格式一致的构建物,并完成上传或分发链路验证。
- 回退条件:任一关键步骤失败,生产任务回到主用线,备用线进入问题排查,不强行上线。
Xcode 支持将构建设置保存为明文配置文件,并纳入版本控制;官方文档也说明,目标级设置、配置文件、项目设置和系统默认值存在优先级关系。查看 Xcode 构建配置文件说明 查看 Xcode 构建设置优先级
建议为两台 Mac 建立同一份环境基线:
| 决策维度 | 主用节点 | 备用节点 | 验收证据 |
|---|---|---|---|
| macOS | 生产确认版本 | 已验证兼容版本 | 系统版本输出、更新记录 |
| Xcode | 当前发布工具链 | 候选或同版本工具链 | xcodebuild -version、真实归档 |
| SDK 与架构 | 项目要求的 SDK、Apple Silicon 条件 | 与主用线一致 | 构建日志、架构检查 |
| Swift Package | 锁定解析结果 | 使用同一锁定文件 | 依赖解析日志 |
| 证书与 Profile | 生产签名资产 | 受控恢复后的资产 | 签名、导出和上传结果 |
| CI 脚本 | 版本控制中的脚本 | 从仓库重新拉取 | 提交版本、运行日志 |
不要只比较 Xcode 界面中的版本号。还要检查 SDK、命令行工具、Ruby 或 Python 运行时、私有仓库访问、缓存策略和脚本依赖。
如果企业正在整理 Xcode 双版本构建环境管理 的方案,建议把“升级验证”作为独立流水线,而不是直接在生产 Runner 上改环境。
主机故障场景:远程重启必须提前验收
掉电、系统无响应、FileVault 磁盘未解锁和 VNC 连接中断,不是同一种故障。
- 掉电:重点是主机能否自动启动、网络能否恢复、Runner 服务能否重新上线。
- 系统无响应:重点是远程重启是否真的执行,而不是控制台返回了一个成功提示。
- 磁盘加密未解锁:重点是启动后是否需要人工输入密码或恢复密钥。
- 远程连接中断:重点是 CI 服务是否仍然运行,以及任务日志是否完整。
Apple 文档说明,启用 FileVault 后,启动磁盘需要通过登录密码、Apple Account 或恢复密钥解锁;恢复密钥必须保存在加密启动盘之外。查看 Apple FileVault 恢复选项
因此,远程 Mac 的重启验收至少包括:
- ✅ 发送重启指令后,记录开始时间、结束时间和系统启动日志。
- ✅ 确认 Runner 服务自动恢复,并显示为在线、空闲、可接单。
- ✅ 用一条真实 iOS CI/CD 任务验证编译、测试和归档。
- ✅ 验证磁盘解锁路径,明确哪些步骤必须人工介入。
- ✅ 保存失败时的最后日志、人工操作和回退动作。
⚠️ 不要把复制整个用户目录当成环境同步方案。用户目录可能包含过期证书、缓存凭证、个人配置和无法审计的状态,故障时反而增加恢复范围。
发布高峰场景:容量不足还是节点故障
队列变长,不一定意味着 Mac 性能不足。需要同时看等待时间、并发任务数、单任务构建时长和失败重试数量。
如果单任务时长稳定,但等待任务持续增加,问题更接近节点数量不足。如果单节点上的构建时长持续上升,则要检查并发争用、磁盘空间、依赖下载和缓存失效。单次跑分不能代替容量规划。
节点数量也不应简单按开发者人数决定。企业应先回答:
- 同一发布窗口最多需要多少条并行流水线?
- 哪些任务必须使用 Apple Silicon?
- 哪些项目需要特定 Xcode 或 SDK?
- 峰值持续多久,是否会周期性出现?
- 失败重试是否会进一步放大队列?
常驻备用节点适合持续发布、严格恢复要求和固定负载。按需增加远程 Mac,适合版本升级、短期发布高峰和灾备演练。成本模型只需要先列出基础容量、峰值容量、使用周期和运维工时,不要在没有真实使用曲线前承诺节省比例。
GitHub 文档还说明,self-hosted Runner 若超过 30 天没有完成软件更新,服务可能不再向其排队任务;这意味着备用节点不能长期闲置后再临时接管。查看 GitHub Runner 更新要求
凭证异常场景:能编译但不能签名,仍然算灾备失败
备用节点可以完成编译,却无法导出可发布的归档,通常是签名链路没有被纳入灾备设计。
需要单独登记以下对象:
- Apple Developer 账号权限与责任人。
- 分发证书及其私钥。
- Provisioning Profile 与对应 App ID。
- Keychain 的导入、解锁和访问控制。
- 私有 Git 仓库的 SSH 凭证。
- 私有依赖仓库、二进制仓库和缓存服务的访问令牌。
- 凭证轮换、撤销和紧急替换路径。
Apple 官方说明,签名证书、私钥和 Keychain 中的相关证书必须匹配;如果证书或私钥缺失,构建会失败。查看 Apple 证书与私钥要求 Provisioning Profile 也可以在 Apple Developer 账户中重新生成和下载,但这不等于企业可以临时把账号密码交给值班人员。查看 Apple Provisioning Profile 管理说明
推荐的迁移方式是:
- 由指定责任人从受控凭证系统取出必要资产。
- 在备用节点创建专用 Keychain 或隔离的构建用户。
- 导入证书、私钥和 Profile,并限制 CI 进程访问范围。
- 使用不发布到生产环境的测试任务验证签名。
- 记录导入时间、操作者、资产版本和撤销方式。
- 演练结束后清理临时凭证,并确认轮换记录完整。
不要通过复制整个用户目录、共享 Apple Account 密码或把私钥写入流水线仓库来“快速同步”。
灾备演练:用证据决定冷备、温备还是按需扩容
一次合格的演练,应从“停止主节点接单”开始,而不是从“备用节点已经在线”开始。
演练操作清单
- [ ] 记录主节点当前 Runner 状态和未完成任务。
- [ ] 暂停主节点接单,保留任务日志与队列截图。
- [ ] 启用备用节点的生产标签或 Runner 路由。
- [ ] 确认 Xcode、SDK、依赖锁定文件和脚本版本。
- [ ] 验证私有仓库、依赖缓存和 SSH 凭证访问。
- [ ] 执行真实项目的编译、测试、归档和签名。
- [ ] 检查构建物哈希、上传结果和发布平台回执。
- [ ] 记录人工介入点、失败原因和回退动作。
- [ ] 恢复主节点,确认任务不会重复消费。
- [ ] 形成演练报告,并给出下一步容量决策。
GitLab 可以通过 protected Runner 限制敏感任务只运行在受保护分支或标签上。查看 GitLab Runner 保护配置 这类权限规则必须纳入备用节点测试,否则“任务成功切换”可能只是把普通测试任务切过去,生产发布仍然无法执行。
演练结果可以按以下方式决策:
- 备用节点未安装完成或无法签名:继续冷备建设,不进入生产切换。
- 环境可用但需要较多人工操作:升级为温备,补齐自动恢复和凭证流程。
- 备用节点通过切换,但高峰队列仍然增长:增加按需节点或调整任务路由。
- 主备均可用,但产物、日志或权限无法审计:先修复证据链,再讨论扩容。
如果现有机房无法长期保留备用 Mac,远程 Mac 可以作为临时 CI/CD 灾备节点,但前提是提前完成真实项目验证。可以先通过 MESHLAUNCH 的远程 Mac 方案 评估按周或按月交付,再用同一份环境基线和演练清单验证节点接入、任务切换与峰值容量。它不应被直接当作未经测试的“备用服务器”。
当前方案与 Mac 远程方案:按真实故障成本做选择
继续依赖唯一的本地 Mac,缺点通常不是购买价格本身,而是故障时没有第二条可验证路径;升级期间也很难同时保留稳定工具链;发布高峰还可能因为临时采购和部署周期无法及时扩容。
如果企业当前只有一台 Mac 打包服务器,我们建议先保留它作为主用节点,再引入可按周期交付的远程 Mac,完成真实流水线切换和灾备演练。通过 按周或按月租用 Mac 节点,可以先验证恢复流程、签名隔离和峰值承载,再决定是否长期采购第二台或更多实体设备。
先用本文清单完成一次切换。只有当备用节点能够产出可验证构建物、保留完整日志,并明确人工介入点,Mac 打包服务器高可用才算从架构图变成了可执行的业务连续性能力。