Xcode 託管建置與自管雲端 Mac 如何選
團隊已經有一條可正常運作的 iOS 流水線,但每次新增相依套件、切換 Xcode 或調整簽章設定後,都會再次爭論同一個問題:應該繼續使用託管建置,還是將工作放到自管雲端 Mac 上執行。不要先比較單次建置快了多少秒。真正影響長期成本的,是環境能否重現、快取是否可控、失敗現場能否保留,以及工程師需要承擔多少維運工作。
先將工作負載分成三類
先統計最近兩週的工作,而不是憑印象選擇平台。建議依合併檢查、封存發布與臨時診斷三類記錄。合併檢查通常生命週期短、輸入明確,失敗後可以重新執行;封存發布涉及簽章資料、產物保留與嚴格的版本固定;臨時診斷則要求工程師進入相同環境重現問題。
至少記錄以下資料:
| 項目 | 需要記錄的內容 | 判斷目的 |
|---|---|---|
| 工具鏈 | macOS、Xcode、Ruby、套件管理器版本 | 判斷固定環境的難度 |
| 輸入 | 提交編號、鎖定檔、建置參數 | 判斷工作能否重現 |
| 狀態 | 佇列、執行、上傳、清理耗時 | 找出真正的瓶頸 |
| 現場 | 日誌、result bundle、封存產物 | 判斷故障鑑識能力 |
| 快取 | 路徑、大小、命中條件、失效方式 | 判斷長期效益 |
單次成功不代表流程穩定。至少以同一個提交連續執行三次,再使用一個只修改業務原始碼、不變更相依套件的提交,重新測試快取行為。
建立統一的環境指紋
兩種方式都應使用同一份環境檢查指令碼。不要只輸出 xcodebuild -version,還要記錄系統版本、目前的開發者目錄、SDK、Ruby 與套件管理器狀態。環境指紋檔應作為每次工作的普通產物保存;發生失敗時,先比較該檔案,再檢查業務程式碼。
#!/bin/zsh
set -euo pipefail
mkdir -p artifacts
{
sw_vers
uname -m
xcodebuild -version
xcode-select -p
xcrun --sdk iphoneos --show-sdk-version
ruby --version
git --version
} > artifacts/environment.txt
export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
xcodebuild \
-workspace App.xcworkspace \
-scheme App \
-configuration Release \
-derivedDataPath "$PWD/.build/DerivedData" \
-resultBundlePath "$PWD/artifacts/App.xcresult" \
build
DEVELOPER_DIR 不應指向尚未核對的路徑。自管環境可以保留多個 Xcode 版本,但流水線必須明確選擇;託管環境則應在工作開始時驗證實際版本,不相符就儘早結束。如此可避免工作一直執行到封存階段,才暴露 SDK 差異。
分別驗證快取、簽章與並行執行
不要搬移整個目錄作為快取
快取鍵至少應包含 Xcode 主要版本、架構與相依套件鎖定檔摘要。SwiftPM、CocoaPods 與建置中間目錄應分開管理,因為它們的失效條件不同。不要封裝並還原整個使用者目錄,否則舊權限、暫存檔與不可見的設定也會一併進入新工作。
自管雲端 Mac 適合需要長期保留大型相依套件快取的流水線,但必須為每個儲存庫配置獨立工作目錄,並定期驗證刪除快取後仍可完成完整建置。託管建置的快取生命週期通常由平台控制;在工程設計上,應將快取視為最佳化手段,而不是成功執行的必要條件。
簽章資料只在工作期間可見
簽章資料應在工作開始時由受控儲存空間注入,完成後立即移除暫存副本。日誌不得輸出密碼、金鑰內容或完整檔案路徑。無論採用哪種方式,都必須驗證失敗分支同樣會執行清理,而不只是成功分支。
並行測試應從兩個工作開始,觀察它們是否共用 DerivedData、模擬器、Keychain 或固定連接埠。只要存在共用的可寫入狀態,提高並行數就可能放大偶發故障。
透過故障演練測試可復原性
不要等到真正的發布失敗後,才驗證復原流程。可以設計四種非破壞性演練:刻意指定不存在的 scheme、刪除一個相依套件快取、讓測試案例回傳失敗,以及在封存前終止工作。每次都要檢查結束代碼、日誌末尾、result bundle、臨時簽章資料與工作目錄狀態。
託管建置應著重確認日誌是否足以說明失敗原因、環境是否仍可重現,以及重新執行時輸入是否完全一致。自管雲端 Mac 還要確認殘留程序、掛載目錄與連接埠不會汙染下一個工作。建議每個工作使用唯一目錄,並透過退出掛鉤回收子程序。
workdir="$(mktemp -d "$PWD/.job.XXXXXX")"
cleanup() {
jobs -p | xargs -r kill 2>/dev/null || true
rm -rf "$workdir"
}
trap cleanup EXIT INT TERM
清理指令碼必須先在測試目錄中驗證,避免過於寬泛的萬用字元影響其他工作。需要保留的日誌與建置產物應先複製到獨立的 artifacts 目錄,再執行回收。
依控制權而非口號做決定
如果專案使用一般相依套件、工作時間短、失敗後允許直接重新執行,而且團隊不希望維護機器狀態,託管建置通常更合適。如果需要固定多個 Xcode 版本、長期重複使用快取、執行特殊工具、進入現場診斷,或讓長時間工作持續執行,自管雲端 Mac 更容易建立清楚的邊界。
兩者也可以拆分使用:合併請求執行輕量測試,穩定分支則在自管環境中完成封存與深度診斷。重點是兩邊共用同一套環境指紋、鎖定檔、建置進入點與產物命名,避免形成兩條互不相容的流水線。
最終驗收不應只看最快的一次,而要檢視多次執行的成功率、環境差異數量、刪除快取後的可復原性、失敗證據的完整程度,以及需要人工介入的步驟。將這些結果寫入儲存庫中的決策記錄,並約定在 Xcode 主要版本、相依套件體系或工作規模發生變化後重新評估,選型才不會變成永久不變的假設。
常見問題
託管建置一定比自管雲端 Mac 省事嗎?
不一定。標準化專案通常較省維護;若要固定 Xcode、保留長期快取或深入調查失敗現場,自管環境通常更直接。
團隊能同時使用兩種建置方式嗎?
可以。可由託管建置執行合併檢查,再將需要穩定快取、複雜簽署或完整日誌的封存任務交給自管雲端 Mac。
選型前最重要的驗證是什麼?
用相同提交、鎖定檔與建置命令重複執行,比較成功率、環境差異、快取命中、日誌完整度及失敗後的復原時間。
需要一台由單一訂單獨享的實體 Mac mini?
核對 M4 與 M4 Pro 兩種配置、四種租用週期及 5 個可選節點,再依工作流程選擇裝置。