2026-05-06 iOS 模拟器运行时 磁盘预算、选择性安装 与 CI 清理(租用 Apple Silicon 云 Mac,香港 / 东京 / 首尔 / 新加坡 / 美国)
在香港、东京、首尔、新加坡或美国租用 Mac mini M4 跑 xcodebuild test 的团队,很快会遇到第二张账单:Simulator 运行时并不免费——它们在 Library/Developer/CoreSimulator 下占据数 GB 到十几 GB,与 DerivedData 争抢 NVMe 带宽;一旦 watchOS 伴侣矩阵加入,体积还会倍增。本 2026-05-06 指南回答三个运维问题:如何清点已装内容、如何只选 destinations 真正需要的 OS 家族、如何裁剪而不删掉夜间 UI 测试仍要启动的运行时。延续 无头模拟器测试,与 磁盘清理与 janitor 配套,并在同主机多车道时引用 DerivedData 隔离 与 并行 xcodebuild 的队列策略。
为何 2026 的 CI 仍把「装了 Xcode」当成「模拟器就绪」
Xcode.app 带的是工具链,而运行时是可按需下载的版本化载荷。三类高频失误:
- destination 漂移——YAML 仍写
iPhone 15,主机 Xcode 升级后只预置了iPhone 16镜像。 - 静默 watch 配对——本地 Xcode 自动拉了 watch 运行时,CI 从未拉取。
- 清扫越权——定时任务删掉 QA 仍要用来复现 App Store 崩溃的 iOS 17.6 运行时。
体积:GB 藏在哪里
Apple Silicon 主机会存放设备数据、dyld 共享缓存与按运行时切分的镜像。粗略预期:每对主要 iOS 运行时(手机 + 年度 watch 镜像)7–14 GB;若 UI 截图车道装了多语言包,再加 3–6 GB。关键不是精确字节,而是导数——五名工程师在同一共享机构建机上各自“顺手装最新 beta 运行时”时的斜率。
把运行时增长与队列延迟关联:空闲低于 12% 时,首个症状往往是 xctest fixture 复制变慢而非立刻失败,因为 APFS 需要更努力找连续块。
采纳新 Xcode 大版本时,把运行时下载当成容量迁移而非单选框:Xcode 可能提示多平台包、CoreSimulator 缓存重建,首个绿构建常伴随 24–48 小时 的隐式“暖机”膨胀。为租用主机预留显式维护窗口,避免 PR 流量与首次批量下载重叠——忽视这一点的团队常见“无代码原因”的间歇性红构建,第二天又自行消失。该窗口内按小时记录 df,与上季度稳态曲线对比;若斜率高于历史 2×,多半在同一车道叠了 beta 与 GA 两套重叠切片。
最后把谁有权安装运行时写进制度:工程师临时 sudo 是共享密钥上出现“神秘 6 GB”的主因。变更应走基建工单并绑定 CI 镜像标签,使 ssh 会话可审计——尤其在数据驻留已约束你选择新加坡还是美东保存签名材料的监管场景。
车道矩阵:哪台主机保留哪些运行时
显式拆分职责,不要假装每台 runner 可互换。
| 车道标签 | 运行时策略 | 谁负责清理? |
|---|---|---|
ios-current |
最新 GA iOS + 一条 N-1 以对齐 App Store | 每周裁剪 + 工单 |
watch-heavy |
watchOS 镜像 + 仅配对手机 | 月度;无 QA 签字不删 N-1 |
archive-only |
最少模拟器;偏好真机 Archive | 对模拟器 aggressive、对密钥 gentle |
运维应粘贴进 runbook 的清点命令
先非破坏探测,再升级动作。
xcrun simctl list runtimes
df -h /
du -sh ~/Library/Developer/CoreSimulator/* 2>/dev/null | sort -h | tail -n 20
若数字与 Finder 不一致,以 CI 用户执行的 du 为准——launchd 作业以构建账号运行。若使用独立卷,对 /Volumes/builds 重复上述步骤。
选择性安装(理想路径)
- 冻结队列或排空绑定到该主机的标签。
- 下载下一 sprint destination 矩阵真正需要的运行时包。
- 每类运行时做一次
xcrun simctl boot冒烟,并确认sysctl hw.model仍报告 Apple Silicon。 - 提升 CI YAML 的镜像版本标签后重新开放队列。
- 在 infra 仓库记录已装集合,而不是孤立 wiki。
在步骤二与三之间,把 校验和 或 Apple 版本字符串记在工单里,若镜像损坏可明确回滚。
裁剪策略:什么可以删
好的 janitor 对衍生产物 aggressive,对运行时视作半静态基础设施。两阶段策略:
| 产物 | 安全节奏 | 过度裁剪风险 |
|---|---|---|
| 未启动的模拟器设备 | 每日 | 低——可从模板重建 |
旧 .xcresult 包 |
上传对象存储后 | 中——合规可能要求离机保留 30–90 天 |
| 运行时包本体 | 季度 + QA 列表 | 高——破坏崩溃复现的可重复性 |
并行车道与统一内存压力
并行 xcodebuild 会放大模拟器启动抖动。用队列标签限制每主机并发启动数——见 并行作业指南。内存尖峰时优先减少并发 destination而不是依赖交换;统一内存下 XCTest 对 swap 极其敏感。
sysdiagnose 切片——磁盘压力常以 SpringBoard watchdog 形式先出现。
Xcode 升级窗口:把运行时拉取与 Archive 错峰
除非有第二台热备节点,否则不要把运行时大下载与 TestFlight 提交冻结夜排在同一天。MacXCode 主机上最安全的模式是蓝绿构建机:候选镜像上 xcodebuild test 与轻量 xcodebuild archive -archivePath /tmp/Smoke.xcarchive 均绿后再提升镜像标签。若买不起双节点,就缩小范围:维护窗口每小时只增装一个额外运行时,而不是一次五个。记录每次下载的墙钟分钟数,便于财务比较“再租一台 1 TB 构建机”与“烧掉一个发布周末”。
升级后重新校验 YAML 里的 destination 字符串,Apple 偶尔会改模拟器硬件 profile 名称。错配表现为“destination not found”,而 simctl list 看起来仍有设备——通常是因为作业指向了裁剪时删掉的硬件字符串。把 simctl list devices available 的机器可读导出纳入 infra 仓库做 diff。
可写进 Grafana 的数值目标
- 持续磁盘利用率不超过 85%再谈分页运维。
- 16 GB 机型默认最多 4 个已启动模拟器,除非 profiling 证明仍有裕量。
- “安装运行时 + 启动 + 单条 XCTest”冷路径上限 22 分钟;升级后超时告警。
删「那个大目录」前的九步清单
- 确认没有 Archive 任务在飞。
- 把当前
simctl list快照进 GitOps。 - 标出过去 30 天 零作业命中的运行时。
- 向 QA 发出带明确移除日期的通知。
- 一次只排空一条车道。
- 仅通过受支持的 UI/CLI 路径删除运行时。
- 对剩余 destination 重跑冒烟。
- 对比删除前后
df,把差值附在工单。 - 仅在健康主机上前滚标签。
常见问题:beta、Apple Silicon 与跨区域主机
| 问题 | 实操答案(2026-05-06) |
|---|---|
| beta 运行时应放在生产 CI 吗? | 隔离到带 canary 标签的主机;永远不要与 App Store 提交车道混跑。 |
| 新加坡与美国主机要完全一致吗? | 对齐最小公共集合;区域特有附加包可以,但 YAML 必须编码。 |
为何 1–2 TB 的 Mac mini M4 仍适合模拟器密集型 CI
模拟器负载偏随机读;MacXCode 节点上裸金属 Mac mini M4 NVMe 让四条车道为同一 PR 矩阵启动不同 OS 代际时启动时间仍可预期——可预期性才能把数字预算变成工程纪律,而不是买不知底细的“大云盘”却与吵闹邻居共享。向容量规划解释为何需要第二台 JP canary 时用 区域定价;安全团队要审计谁删了运行时时用 SSH/VNC 接入说明。