短週期「突發」建置最怕兩件事:佇列把釋出視窗擠掉、快取把環境悄悄弄髒。把 GitLab Runner 註冊到雲端 Mac 並選用 shell 執行器,可直接複用你在機器上已驗證過的 Xcode、Ruby/CocoaPods 與簽章鑰匙圈,省去 Docker on Mac 或 SSH 遠端腳本多一層抽象;代價是同一使用者家目錄下的全域狀態,得靠標籤與快取鍵自己管住。以下依我們線上常用參數撰寫,可直接改倉庫裡的 .gitlab-ci.yml 試跑;若還在評估「第二條 macOS 流水線或把 Job 拆到 Linux」,可先讀 2026年短週期衝刺:加開第二條 macOS CI 流水線還是把 Job 拆到 Linux 代理?排隊成本與金鑰隔離決策矩陣與 FAQ。
Shell Executor:何時值得接雲 Mac
當 Job 主要是 xcodebuild、Archive、notary 或依賴本機鑰匙圈的腳本時,shell 比容器執行器省事:路徑、權限與(若需要的)GUI 工作階段都和人工登入除錯一致。建議為 Runner 另建系統使用者或至少獨立 Home,避免與人工桌面共用 DerivedData;並發大於 1 時務必評估磁碟 IO 與 codesign 鎖競爭,否則 wall time 會被尾延遲拖長。Controller 與 Agent 分層的 Jenkins 場景可對照 2026年Jenkins混合拓撲:Controller駐輕量VPS與雲Mac Agent的JNLP回連及企業資源池落地清單,概念可平移到 GitLab 與雲端 Runner 池。
gitlab-runner 固定 concurrent、為 shell executor 以 environment 注入 CI_DERIVED_DATA_PATH、FASTLANE_SKIP_UPDATE_CHECK 等,讓 YAML 只描述階段,環境差異集中在 Runner 設定,突發擴容時多半只需換 Runner、少改倉庫。
快取鍵:讓「快」不犧牲「準」
GitLab 的 cache:key:files 建議至少納入 Gemfile.lock、Podfile.lock、Package.resolved 等與編譯相關的鎖檔;Xcode 大版本升級時另拼一段 MACOS_CI_IMAGE_ID 變數,避免舊 DerivedData 混進新工具鏈。policy 用 pull-push 適合主幹高頻分支,僅對發布分支或 nightly 開啟全量 push,可減輕物件儲存寫放大。
cache: key: files: - Gemfile.lock - Podfile.lock - YourApp.xcworkspace/xcshareddata/swiftpm/Package.resolved prefix: "${CI_COMMIT_REF_SLUG}-xcode${XCODE_VERSION}" paths: - .cocoapods/ - ~/Library/Developer/Xcode/DerivedData/ policy: pull-push
標籤策略:burst、steady 與「只跑雲 Mac」
以 tags 把 Runner 分成 mac-burst(彈性雲節點,允許搶占與較短逾時)與 mac-steady(合約內固定配額,跑簽章與上架)。預設流水線只打 burst;需鑰匙圈解鎖或人工值守的步驟另開 job 並打 steady,避免突發任務擠占關鍵路徑。機型維度可選 mac-m4 等標籤,與企業資源池買租與地域策略一併看:2026年企業遠端 Mac Runner 資源池買還是租:M4 與 M4 Pro、六地域延遲與併發標籤維運決策矩陣。
| 標籤組合 | 典型 Job | 逾時與重試建議 |
|---|---|---|
mac-burst(Runner 為 shell 執行器) |
單元測試、靜態分析、無簽章 Archive | timeout: 25m,retry: 1 僅網路類 |
mac-steady(同上) |
notary、上傳 TestFlight | 長逾時+禁止與 burst 共用並發槽 |
mac-m4(可選機型) |
大型專案連結峰值 | 與 Runner 池容量、快取路徑一併盤點 |
與 GitHub Actions 混用:決策矩陣(簡版)
雙平台常見動機是:開源側仍在 GitHub,私有制品與內網依賴在 GitLab。原則是「誰離程式碼與金鑰最近,誰跑重 Job」。若 GitHub 已有成熟的 macOS workflow,可把輕量檢查留在 Actions,把需要內網快取或 GitLab Registry 的步驟遷到自託管 Runner;反之亦然。兩邊都開快取時,請用不同 bucket 前綴與 key,避免同名互相覆寫。
| 情境 | 優先放 GitLab(雲 Mac shell) | 優先放 GitHub Actions |
|---|---|---|
| 倉庫主託管在 GitLab | 是,減少映像與 submodule 雙拉 | 僅保留社群貢獻 PR 的快速檢查 |
| 依賴 GitHub Packages/OIDC | 以 id_tokens 或 PAT 鏡像到內網後再跑重活 |
原生整合較單純 |
| 突發 PR 風暴 | 加 burst Runner 與佇列上限 | larger runner 計費與配額另評估 |
tags 是否為空,並關閉未打標 Runner 的「Run untagged」。Q:快取命中仍全量編譯? 多半是 Xcode 小版本變了卻沒進 key,把 xcodebuild -version 寫入 artifact 對照。Q:與 Actions 雙跑重複? 以 rules:changes 或路徑過濾縮小觸發面,並只綁定一側為「權威 green」,避免雙紅雙綠扯皮。
ios_burst: stage: build tags: [mac-burst] rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' variables: GIT_STRATEGY: fetch FASTLANE_OPT_OUT_USAGE: "1" script: - xcodebuild -version - bundle exec fastlane ci_unit
在雲端 Mac mini 上,這一切更順暢
自託管 GitLab Runner 要穩,底層機器比 YAML 技巧更關鍵:Apple Silicon 統一記憶體讓 Xcode 連結與 Swift 編譯峰值較平滑;macOS 上 Homebrew、鑰匙圈與 codesign 鏈路開箱即用,省掉跨系統模擬的排障時間。雲端 Mac mini M4 待機功耗僅約 4W,適合長期在線的 shell Runner;Gatekeeper 與 SIP 疊加,惡意軟體面遠小於把同等負載攤在雜牌 Windows 組裝機上。
從總持有成本看,小團隊不必先買整機:依專案彈性開 burst 節點、用標籤隔離 steady 任務,就能把短週期建置的排隊與憑證風險一併壓住——與本文快取鍵、標籤策略是同一套思路在不同維度的延伸。
若你正把 GitLab 與 GitHub 的混合流水線落到可值守、可擴縮的硬體上,VPSSpark 雲端 Mac mini M4 是目前性價比很高的起點——立即獲取方案,讓 Runner 註冊完就能專心寫流水線,而不是和宿主機較勁。