チームが大きくなると、「誰のマシンでビルドできるか」が瓶首になります。iOS プロジェクトの CI/CD 全体をKvmkit の Mac mini M4 クラウドサーバーに移行した後、ビルド待ち時間が大幅に短縮し、署名インシデントもほぼなくなりました。これはゼロからこのパイプラインを構築する際に踏んだ落とし穴と、収束したFastfileとキャッシュ戦略の記録です。クラウド Mac を評価しているチームの参考になれば幸いです。
为什么选择云端 Mac mini M4 做 CI/CD
Xcode 的构建是典型的"计算密集 + 强依赖系统版本"的任务,本机 Runner 很难长期稳定维护。选择云端 Mac 节点主要基于三点判断:
- 规格可控:镜像固定 Xcode 与命令行工具版本,不会因为某人手动升级系统而"团队里只有他能编译"。
- 随时扩容:发版前的回归测试可以临时多开几个节点并行跑,跑完即释放,不用为峰值常年预留硬件。
- 7×24 值守:M4 芯片待机功耗低,夜间构建、定时安全扫描都可以放心常驻运行,不用担心电费或噪音。
我们踩过的第一个坑:以为「云主机」等于「远程显示器」,只用它做手动打包。真正把收益吃透,是把它接入 CI 触发链之后才开始的。
CI/CD 流水线设计
阶段划分
一次完整的发版流水线,我们拆成了四个阶段:
- 代码拉取与依赖解析(SPM / CocoaPods)
- 单元测试与静态分析(并行执行)
xcodebuild archive归档与签名- 上传 TestFlight 并通知值班群
钩子与触发条件
main分支的每次合并会自动触发阶段 1-2;只有打上release/*标签才会继续跑阶段 3-4,避免每次小改动都消耗签名配额。本地调试 Fastlane 脚本时,我们习惯先用Ctrl+C中断一次完整跑批,单独重跑失败的那一步,能省下不少等待时间。
示例 Fastfile 片段
lane :ci_archive do
cocoapods
run_tests(scheme: "Kvmkit")
build_app(
scheme: "Kvmkit",
export_method: "app-store",
output_directory: "./build"
)
upload_to_testflight(skip_waiting_for_build_processing: true)
end
这段脚本本身并不复杂,关键是要让它在同一套镜像基线上重复运行都能得到一致结果——这也是我们把镜像版本号写进构建日志的原因,方便回溯某次失败是环境问题还是代码问题。
缓存与依赖管理
缓存没配好,云端构建的速度优势会被下载依赖的时间吃掉。下面是我们线上跑了三个月后总结的对照表:
| 缓存项 | 未启用缓存 | 启用镜像内缓存 |
|---|---|---|
| CocoaPods 安装 | 约 4-6 分钟 | 约 30 秒 |
| SPM 依赖解析 | 约 3 分钟 | 约 15 秒 |
| DerivedData 增量编译 | 接近全量编译 | 命中率 80% 以上 |
几个术语的口径先对齐一下:
- DerivedData
- Xcode 的增量编译产物缓存目录,跨构建复用可以显著缩短二次编译时间。
- SPM 缓存
- Swift Package Manager 拉取到本地的包源码与解析结果缓存,避免每次构建都重新拉取远端仓库。
- 镜像基线
- 云主机开机即用的系统快照,包含固定版本的 Xcode、CLT 与预热好的依赖缓存。
常见问题排查
最容易被忽略的一点:证书过期不会立刻报错,而是在上传 TestFlight 的最后一步才失败,这时候整条流水线已经空转了十几分钟。我们现在把证书有效期检查放进了阶段 1,提前失败、提前告警。
早期我们用过一种"每晚全量清空缓存重新构建一次"的笨办法来防止缓存腐化,后来改成按镜像版本号做缓存失效(版本号不变就复用,升级镜像才清空),既保住了速度,也不会让脏缓存悄悄潜伏几周才暴露问题。
"不要相信一次绿色的 CI;要相信连续十次绿色的 CI。"——这是我们值班手册里反复强调的一句话,尤其适用于刚迁移到新云节点的头两周。
常见问题
云端 Mac mini 和自建 Mac Runner 相比,安全性上有什么区别?
云端节点的系统镜像由服务商统一维护基线版本,团队仍需自行管理签名证书与 Provisioning Profile 的访问权限;建议只把证书注入到运行时环境变量,不落地到镜像里,退还节点前清空 keychain。
免费的 Xcode Cloud 额度能不能直接替代这整套流程?
小团队用 Xcode Cloud 完全够用;但当并行构建数、自定义脚本或跨项目共享缓存的需求变多之后,自建在云端 Mac 节点上的流水线会更灵活,也更容易控制成本上限。
多个项目共用同一批云端节点时,证书应该怎么隔离?
建议每个项目使用独立的 keychain 或独立的钥匙串 profile,构建脚本在拉起阶段导入、结束阶段清空,避免不同项目的证书互相污染同一把系统级 keychain。
M4 Mac mini で CI/CD を実行する — これが真の安心感
本文所有流程——Xcode、Fastlane、CocoaPods、SPM——在 macOS 上都是原生一等公民,不需要任何虚拟机或兼容层。Mac mini M4 统一内存架构让签名、归档、上传这类 I/O 与计算混合任务不再互相拖累,约 4W的待机功耗也让 7×24 值守节点的电费几乎可以忽略。
和自建 Mac Runner 相比,云端节点不用操心机房散热、系统更新窗口和硬件故障换机——这些运维负担全部转移出去,团队可以把精力放回流水线本身的质量上。
チームも「誰のマシンでコンパイルできるか」に悩んでいるなら、今こそクラウド Mac mini M4 に CI を移行する最適なタイミング——Kvmkit プランを見る— 数分で最初のビルドノードを立ち上げられます。