你的团队在 Codemagic 上把 iOS 流水线跑顺了,却在发版周被分钟账单、并发槽位排队与缓存不可审计反复打断——财务问「为什么比上月贵 40%」,研发却说不清哪条 workflow 吃了 wall-clock。本文面向平台工程与移动端负责人:用一张迁出决策矩阵对照 Codemagic 全托管、独占远程 Mac(SSH) 与混合编排,并给出可落地的六步 Runbook 与 codemagic.yaml 映射示例。请与站内 Xcode Cloud 与独占 Mac 签名队列成本、自托管 Runner 标签与缓存、可复现 Xcode 指纹 连读;接入与验收见 帮助中心。
Codemagic 擅长把 Flutter / iOS 发版做成产品化体验,但当团队把多 scheme archive、UI 测试与 TestFlight 上传叠在同一工作流里,分钟计费会把基础设施问题伪装成「某次提交变慢」。下面清单用于迁出评审会前的红队演练 📋。
把 PR 校验与发版 archive 混在同一 workflow: 前者本应分钟级,后者动辄二三十分钟;合并统计后财务只能看到总分钟数飙升。
并发槽位默认档位不够: 发版周多条 release 分支同时打 tag,队列等待时间仍计入账单语境下的「团队焦躁成本」,却难写进 RFC。
缓存键未按仓库 / 分支命名: CocoaPods 与 DerivedData 热缓存让 PR 虚假变绿,冷启动 Job 才暴露真实编译时间——与 指纹验收 目标相悖。
签名材料在托管侧轮换: 证书更新与 xcodebuild 版本跳跃不同步,失败像「Codemagic 抽风」而非合同缺口。
未拆分 macOS 与 Linux Job: Android / Web 在 Linux 分钟池,iOS 在 Mac 池;合并看板会低估 Darwin 构建的真实占比。
迁出计划只谈价格不谈槽位: 采购对比「包月 Mac」与「Codemagic 分钟」,却未把并发 archive 上限写进 SLA,迁出后仍在共享池排队。
混合流水线没有 SSH 验收: 编排留在 Codemagic、构建落到自购 Mac,却缺少 Runner 标签、磁盘水位与睡眠策略的书面清单。
这些痛点的共同根因是:算力边界不清晰。当 Darwin 构建需要可预测墙钟与可审计缓存时,独占硬件或混合模型才能把分钟焦虑变成合同语言。
2026 年常见三种形态:继续全托管 Codemagic、把 macOS 构建迁到像租 VPS 一样的独占远程 Mac,或保留 Codemagic 触发与密钥、通过 SSH / 自托管 Runner 执行 xcodebuild。下表用于对齐计费心智、并发与迁出成本。
| 维度 | Codemagic 全托管 | 独占远程 Mac(SSH) | 混合(Codemagic + 自托管 Mac) |
|---|---|---|---|
| 计费模型 | 按构建分钟 + 套餐并发档位;超额按阶梯单价 | 固定月租 / 合同并发槽位;墙钟主要由自有 Job 决定 | Codemagic 编排分钟 + Mac 固定成本;需拆分账单科目 |
| 并发槽位 | 套餐内并行构建数;高峰需升级 tier | 合同写明 archive 并行上限与 CPU 争抢策略 | 托管侧限 PR;发版 archive 走独占标签 |
| 工具链控制 | 镜像由平台维护,升级需协调 | 可钉住 xcode-select 与验收脚本 | yaml 映射 instance_type / 自定义 VM |
| 缓存与签名 | 集成 App Store Connect;缓存策略偏产品化 | DerivedData / 钥匙串路径可写进合同 | 密钥留在 Codemagic,制品回传托管 |
| 迁出难度 | 低(已在上) | 中:需 Runner、监控与运维 Runbook | 中低:渐进迁移,保留现有 webhook |
| 典型失败模式 | 分钟超标、队列、镜像漂移 | 磁盘满、睡眠、人工升级遗漏 | 标签漂移导致 Job 落错主机 |
「选 CI 不是选 UI,而是选谁为 Darwin 墙钟与并发槽位负责——分钟计费适合探索期,发版稳态往往要向独占边界迁。」
若你已在评估 Xcode Cloud 与独占 Mac 的签名队列,可把 Codemagic 视作第三条托管曲线:产品化程度更高,但分钟与槽位的组合仍会在发版周放大成本波动。
迁出不应「一刀切关 Codemagic」,而应先把账单、槽位与缓存拆开,再逐步把重 Job 映射到 SSH 主机。顺序错误会把发版周变成双份运维债。
导出 30 天分钟明细: 按 workflow / branch 聚合,标出 PR、nightly、archive、上传四类;找出 wall-clock 最长的 20% Job。
冻结并发合同: 写明同时运行的 Mac 构建数、是否允许 UI 测试与 archive 并行;与采购对齐「槽位」而非仅「核数」。
拆分 workflow: PR 留在托管池或轻量 Mac;发版 archive 与 TestFlight 上传迁到独占标签。
映射 codemagic.yaml: 用 instance_type、环境变量与 SSH 脚本把 xcodebuild 落到自托管;缓存路径与 Runner 缓存挂载 一致。
跑一周双轨对照: 同一 tag 在托管与独占各构建一次,对比 IPA 哈希、工具链日志与墙钟;差异写入迁出清单。
切主路径并保留回滚: 默认走独占;Codemagic 保留为灾难回滚与 PR 快检,避免「迁出完成」后无人会修旧流水线。
# codemagic.yaml — PR 走托管,发版 archive 走独占 Mac(SSH)
workflows:
ios-pr-check:
name: iOS PR (hosted)
instance_type: mac_mini_m2
max_build_duration: 30
scripts:
- name: Toolchain fingerprint
script: |
xcodebuild -version
xcrun swift --version
- name: Build & test
script: xcodebuild -scheme App -destination 'platform=iOS Simulator,name=iPhone 16' test
ios-release-archive:
name: iOS Release (self-hosted via SSH)
# 在 Codemagic 控制台绑定 SSH 密钥 / 自定义 Mac
# 或使用 triggering + 外部 webhook 调用独占节点脚本
instance_type: mac_mini_m2 # 占位;实际 xcodebuild 在 NODE_MINI_HOST 执行
environment:
vars:
NODE_MINI_HOST: "build-mac-01.internal"
DERIVED_DATA_PATH: "/Volumes/CI/DerivedData/${CM_BRANCH}"
scripts:
- name: Remote archive on dedicated Mac
script: |
ssh -o BatchMode=yes "ci@${NODE_MINI_HOST}" \
"export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer && \
xcodebuild -scheme App -configuration Release \
-derivedDataPath '${DERIVED_DATA_PATH}' \
-archivePath /tmp/App.xcarchive archive"
提示: 独占节点上的 DEVELOPER_DIR、钥匙串与 DerivedData 根目录应在迁出前按 可复现构建清单 验收,避免 hybrid Job 仍落在漂移镜像上。
SSH 批处理模式、非交互密钥与并发 archive 上限应写进运维页:Codemagic 侧只负责触发,Darwin 墙钟由你合同里的 Mac 承担。
Codemagic 分钟通常按 Job 墙钟累计:等待依赖、拉取 Git LFS、CocoaPods install 与 xcodebuild archive 都算在同一分钟池里。并发槽位决定「同时能跑几个 Mac Job」——槽位用尽时,后续构建排队,但已运行的 Job 仍持续吃分钟,这是发版周账单陡增的常见结构原因。
注意: 官方套餐档位与单价会调整;本文不把某一数字当作长期承诺。评审时请直接打开 Codemagic 账单与定价页,把免费分钟、并发上限、超额单价三项抄进内部 RFC。
混合模型的关键是责任切分:Codemagic 保留 secrets、App Store Connect 集成与通知;独占 Mac 承担重 compile 与可预测缓存。若 SSH 脚本里仍调用托管缓存路径,你会同时支付分钟与运维复杂度,却得不到独占边界的审计收益。
与 自托管 Runner 类似,应为独占主机打标签(如 darwin-release),并在 Codemagic 或外部编排里强制 release workflow 只匹配该标签,防止金丝雀 Job 落到正在升级 Xcode 的机器。
迁出评审还应问一个财务问题:固定月租 Mac 的 Break-even 分钟数是多少? 当团队每月 Mac 构建分钟稳定超过套餐包含量,且发版周需要额外买槽位时,独占合同往往更易向管理层解释——因为成本从变量变成容量规划。
下列条目供内部 RFC 引用;具体数值请按贵司账单与合同调整,并与 租赁价格说明 对照选型。
继续全托管 Codemagic 的隐性成本,是发版周分钟波动、并发排队与缓存不可审计叠加——财务看见的是变量,研发看见的是「同一条 workflow 有时 8 分钟有时 38 分钟」。完全自建 Mac 集群则用运维带宽、睡眠策略与镜像漂移交换可预测墙钟。对需要固定 SSH、可把 xcodebuild 当成 7×24 门禁、并希望混合流水线平滑迁出的团队,NodeMini 的 Mac Mini 云端租赁通常更利于把 Codemagic 保留为编排层、把 Darwin 算力落在稳定边界上。可先阅读 租赁价格说明,再结合 帮助中心 完成 SSH 接入与验收。
建议把服务等级写清:L1 仅 Codemagic PR;L2 混合 — release archive 走独占 Mac;L3 独占为主、托管仅灾难回滚;L4 多地区独占节点与脚本化缓存隔离。采购与研发才能用同一套语言解释:分钟适合探索,槽位与磁盘才是生产稳态。