2026 Codemagic 托管 iOS CI vs 独占远程 Mac:分钟计费、并发槽位与「像租 VPS 一样」迁出决策矩阵 混合流水线 · SSH 自托管 · 迁出清单

你的团队在 Codemagic 上把 iOS 流水线跑顺了,却在发版周被分钟账单、并发槽位排队与缓存不可审计反复打断——财务问「为什么比上月贵 40%」,研发却说不清哪条 workflow 吃了 wall-clock。本文面向平台工程与移动端负责人:用一张迁出决策矩阵对照 Codemagic 全托管、独占远程 Mac(SSH)混合编排,并给出可落地的六步 Runbook 与 codemagic.yaml 映射示例。请与站内 Xcode Cloud 与独占 Mac 签名队列成本自托管 Runner 标签与缓存可复现 Xcode 指纹 连读;接入与验收见 帮助中心

01

预算评审前:七条让 Codemagic 账单变成「黑盒」的隐性痛点

Codemagic 擅长把 Flutter / iOS 发版做成产品化体验,但当团队把多 scheme archive、UI 测试与 TestFlight 上传叠在同一工作流里,分钟计费会把基础设施问题伪装成「某次提交变慢」。下面清单用于迁出评审会前的红队演练 📋。

  1. 01

    把 PR 校验与发版 archive 混在同一 workflow: 前者本应分钟级,后者动辄二三十分钟;合并统计后财务只能看到总分钟数飙升。

  2. 02

    并发槽位默认档位不够: 发版周多条 release 分支同时打 tag,队列等待时间仍计入账单语境下的「团队焦躁成本」,却难写进 RFC。

  3. 03

    缓存键未按仓库 / 分支命名: CocoaPods 与 DerivedData 热缓存让 PR 虚假变绿,冷启动 Job 才暴露真实编译时间——与 指纹验收 目标相悖。

  4. 04

    签名材料在托管侧轮换: 证书更新与 xcodebuild 版本跳跃不同步,失败像「Codemagic 抽风」而非合同缺口。

  5. 05

    未拆分 macOS 与 Linux Job: Android / Web 在 Linux 分钟池,iOS 在 Mac 池;合并看板会低估 Darwin 构建的真实占比。

  6. 06

    迁出计划只谈价格不谈槽位: 采购对比「包月 Mac」与「Codemagic 分钟」,却未把并发 archive 上限写进 SLA,迁出后仍在共享池排队。

  7. 07

    混合流水线没有 SSH 验收: 编排留在 Codemagic、构建落到自购 Mac,却缺少 Runner 标签、磁盘水位与睡眠策略的书面清单。

这些痛点的共同根因是:算力边界不清晰。当 Darwin 构建需要可预测墙钟与可审计缓存时,独占硬件或混合模型才能把分钟焦虑变成合同语言。

02

Codemagic 全托管 vs 独占远程 Mac vs 混合流水线:决策矩阵

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 视作第三条托管曲线:产品化程度更高,但分钟与槽位的组合仍会在发版周放大成本波动。

03

六步 Runbook:从账单拆分到 codemagic.yaml 映射独占 Mac

迁出不应「一刀切关 Codemagic」,而应先把账单、槽位与缓存拆开,再逐步把重 Job 映射到 SSH 主机。顺序错误会把发版周变成双份运维债。

  1. 01

    导出 30 天分钟明细: 按 workflow / branch 聚合,标出 PR、nightly、archive、上传四类;找出 wall-clock 最长的 20% Job。

  2. 02

    冻结并发合同: 写明同时运行的 Mac 构建数、是否允许 UI 测试与 archive 并行;与采购对齐「槽位」而非仅「核数」。

  3. 03

    拆分 workflow: PR 留在托管池或轻量 Mac;发版 archive 与 TestFlight 上传迁到独占标签。

  4. 04

    映射 codemagic.yaml:instance_type、环境变量与 SSH 脚本把 xcodebuild 落到自托管;缓存路径与 Runner 缓存挂载 一致。

  5. 05

    跑一周双轨对照: 同一 tag 在托管与独占各构建一次,对比 IPA 哈希、工具链日志与墙钟;差异写入迁出清单。

  6. 06

    切主路径并保留回滚: 默认走独占;Codemagic 保留为灾难回滚与 PR 快检,避免「迁出完成」后无人会修旧流水线。

yaml · 混合流水线映射(示例)
# 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"
tips_and_updates

提示: 独占节点上的 DEVELOPER_DIR、钥匙串与 DerivedData 根目录应在迁出前按 可复现构建清单 验收,避免 hybrid Job 仍落在漂移镜像上。

SSH 批处理模式、非交互密钥与并发 archive 上限应写进运维页:Codemagic 侧只负责触发,Darwin 墙钟由你合同里的 Mac 承担。

04

技术要点:分钟计费、并发槽位与混合编排如何相互作用

Codemagic 分钟通常按 Job 墙钟累计:等待依赖、拉取 Git LFS、CocoaPods install 与 xcodebuild archive 都算在同一分钟池里。并发槽位决定「同时能跑几个 Mac Job」——槽位用尽时,后续构建排队,但已运行的 Job 仍持续吃分钟,这是发版周账单陡增的常见结构原因。

policy

注意: 官方套餐档位与单价会调整;本文不把某一数字当作长期承诺。评审时请直接打开 Codemagic 账单与定价页,把免费分钟、并发上限、超额单价三项抄进内部 RFC。

混合模型的关键是责任切分:Codemagic 保留 secrets、App Store Connect 集成与通知;独占 Mac 承担重 compile 与可预测缓存。若 SSH 脚本里仍调用托管缓存路径,你会同时支付分钟与运维复杂度,却得不到独占边界的审计收益。

自托管 Runner 类似,应为独占主机打标签(如 darwin-release),并在 Codemagic 或外部编排里强制 release workflow 只匹配该标签,防止金丝雀 Job 落到正在升级 Xcode 的机器。

迁出评审还应问一个财务问题:固定月租 Mac 的 Break-even 分钟数是多少? 当团队每月 Mac 构建分钟稳定超过套餐包含量,且发版周需要额外买槽位时,独占合同往往更易向管理层解释——因为成本从变量变成容量规划。

05

写进评审材料的参考口径与落地结论

下列条目供内部 RFC 引用;具体数值请按贵司账单与合同调整,并与 租赁价格说明 对照选型。

  • 分钟计费档位(参考口径): 按 Codemagic 公开定价逻辑,团队应分别记录免费池用尽后的超额分钟单价升级 tier 后的包含分钟与并发,以及「仅发版周升级一月」的临时成本;勿把年度套餐摊销到单次 PR。
  • 并发构建槽位: 发版前明确「同时运行的 Mac 构建数」上限;建议 PR 与 archive 分池——例如 PR 最多 2 并行、release 保留 1 个独占 archive 槽,避免 UI 测试与 archive 互抢导致队列虚高。
  • 磁盘水位: 独占节点承载 DerivedData、Pods 与 IPA 中间产物时,系统卷建议长期保留 ≥20% 可用空间;Codemagic 托管侧亦应在迁出前导出典型 Job 的峰值磁盘日志,作为容量规划输入。

继续全托管 Codemagic 的隐性成本,是发版周分钟波动、并发排队与缓存不可审计叠加——财务看见的是变量,研发看见的是「同一条 workflow 有时 8 分钟有时 38 分钟」。完全自建 Mac 集群则用运维带宽、睡眠策略与镜像漂移交换可预测墙钟。对需要固定 SSH、可把 xcodebuild 当成 7×24 门禁、并希望混合流水线平滑迁出的团队,NodeMini 的 Mac Mini 云端租赁通常更利于把 Codemagic 保留为编排层、把 Darwin 算力落在稳定边界上。可先阅读 租赁价格说明,再结合 帮助中心 完成 SSH 接入与验收。

建议把服务等级写清:L1 仅 Codemagic PR;L2 混合 — release archive 走独占 Mac;L3 独占为主、托管仅灾难回滚;L4 多地区独占节点与脚本化缓存隔离。采购与研发才能用同一套语言解释:分钟适合探索,槽位与磁盘才是生产稳态。

FAQ

常见问题

并发槽位与 wall-clock 分钟叠加:多 scheme archive、TestFlight 上传与 UI 测试会拉长单次构建;免费档用尽后按阶梯计费。应对照账单拆分 Job,并为独占节点对照 租赁价格说明 估算固定月费是否更划算。

可以:用混合模型保留 webhook、密钥与通知,通过 SSH 或 Runner 标签执行 xcodebuild。请在 codemagic.yaml 中映射缓存路径与标签,并参照 帮助中心 完成独占机验收。

并发 archive 槽位、磁盘水位告警与 Xcode 工具链指纹。验收请链到 可复现构建文,避免迁出后仍在共享池付隐性排队税。