01

本週先做什麼:先建立主備雙軌,再談高可用

Mac 打包伺服器高可用不應從「把唯一節點保持在線」開始,而應從主用節點加可驗證備用節點開始。本週建議先挑一條真實發布流水線,停止主節點接單,讓備用節點完成一次編譯、測試、簽名與產物驗證;未完成這次演練前,不要把單台 Mac 宣稱為具備業務連續性。

這套方法適合管理單台或少量 Mac 構建節點、需要確保 iOS CI/CD 可用性的企業 IT 與研發效能團隊,也適合正在審核災備預算、SLA 和 Mac 算力採購方案的技術總監或 CTO。

02

單機在線 vs 主備可切換:先定義真正的故障邊界

發布窗口中,唯一 Mac 節點突然離線。流水線仍然存在,工作也仍然排隊,但沒有可接工作的構建資源。這說明「節點在線」不等於「發布流程可恢復」。

我們會先分開三個變數:

  • 恢復時間目標:從停止主節點接單,到備用節點能產出可驗證構建物,允許經過多久。
  • 可接受的構建狀態損失:故障前已完成的工作、快取或中間產物,哪些可以重跑,哪些不能遺失。
  • 發布阻斷範圍:只影響單一專案、整個團隊,還是所有需要 iOS 簽名的生產流程。

單節點適合低風險、可人工重跑的工作。冷備適合成本敏感、可以接受較多人工介入的團隊。溫備則要求備用機已完成 Runner、工具鏈和憑證恢復測試。雙活能分散隊列,但也會增加環境漂移、簽名治理和容量管理的複雜度。

多數企業不需要一開始就做雙活。先把「主用線穩定運行、備用線可真實接管」做成可重複演練的雙軌方案,通常更容易驗收。

架構選項 適用情境 主要風險 驗收重點
單節點 非生產構建、可完全重跑 主機故障即停止發布 是否有人工重建流程
冷備 低頻發布、預算受限 備用環境容易過時 臨時啟動後能否完成全流程
溫備 生產發布、需要可預測切換 需要持續維護版本基線 Runner、Xcode、簽名和依賴均可用
雙活 高並發、跨團隊共享 環境差異與路由更複雜 任務分流、產物一致性和憑證隔離
03

發布中斷:備用節點不是「有一台空機」就夠

Mac 打包伺服器宕機後,切換順序應固定,不能由值班人員臨場猜測。

第一步:停止主節點接單

先在 CI 平台暫停或隔離主節點,避免新任務繼續送入故障主機。已經執行中的工作要標記為可重試、需人工判定或不可重試,不能把所有失敗都直接重跑。

以 GitHub Actions 為例,自託管 Runner 會根據 runs-on 的標籤和群組選擇符合條件的在線節點;找不到在線且閒置的匹配節點時,工作會維持排隊,超過官方規則的保留時間後可能失敗。(docs.github.com)

使用 GitLab 時,則要檢查 Runner 標籤、保護分支和工作是否仍處於 pending。工作只有在找到匹配標籤的 Runner 後才會執行;標籤配置不一致,備用機在線也可能接不到任務。(docs.gitlab.com)

第二步:確認備用節點的可接管狀態

至少核對以下項目:

  • Runner 服務已啟動,且出現在 CI 平台的在線清單。
  • 備用節點具備正確的 Apple Silicon 架構標籤或平台標籤。
  • Xcode、SDK、命令列工具和專案建置腳本已安裝。
  • 私有套件、私有 Git 儲存庫和快取來源可連線。
  • Keychain、Provisioning Profile 和簽名私鑰能被流水線使用。
  • 構建產物能上傳到原本的儲存位置。

第三步:只用真實專案驗證

不要以 xcodebuild -version 或 Runner 心跳作為完整驗收。這些只能證明工具存在,不能證明專案能簽名、依賴能取得或產物能發布。

我們會以一條生產相同的分支或發布候選版本執行:

  1. 取得指定 commit。
  2. 使用鎖定的 Swift Package 依賴。
  3. 執行測試與 Archive。
  4. 驗證簽名與 entitlements。
  5. 上傳構建產物。
  6. 保存完整日誌和產物雜湊。
04

維護升級:穩定主線 vs 真實驗證備線

系統更新、Xcode 升級和依賴調整不應只靠安排維護時段解決。升級後即使能成功編譯,也可能在簽名、測試裝置、私有套件或發布上傳階段失敗。

我們建議使用雙軌方法:

  • 主用線:維持目前已通過發布驗證的 macOS、Xcode、SDK 和依賴版本。
  • 備用線:先安裝候選版本,使用真實專案完成編譯、測試、Archive 和發布前驗證。
  • 切換條件:只有當備用線通過基線檢查,才允許它接收生產發布任務。
  • 回退條件:任何簽名、私有依賴或產物上傳異常,都回退到主用線,不在發布窗口臨時修環境。

Xcode 會把 Swift Package 的確切版本寫入 Package.resolved。Apple 官方建議將該檔案提交到 Git 儲存庫,並在直接使用 xcodebuild 時考慮停用自動解析,避免備用節點自行取得不同依賴版本。私有套件則需要配置 SSH 憑證及 known_hosts。(developer.apple.com)

環境基線不應只寫在 Wiki。建議放入儲存庫或可審計的配置目錄:

基線項目 主用線 備用線 驗證證據
macOS 已核准版本 候選或同版本 系統版本輸出
Xcode 生產版本 已完成實測的版本 xcodebuild -version 與構建日誌
SDK 專案要求 與主用線一致或已核准 Archive 日誌
Swift Package Package.resolved 同一提交內容 依賴解析紀錄
建置設定 .xcconfig、腳本 同一版本 Git commit 或版本標籤
Apple Silicon 已確認架構 相同或明確標記差異 Runner 標籤與構建輸出
簽名資產 憑證、私鑰、Profile 受控恢復 Archive、簽名和 entitlements 證據

Xcode 的 .xcconfig 可將建置設定以純文字管理,適合把 Debug、Release、架構和平台差異放入版本控制,而不是依賴某台 Mac 的圖形介面狀態。(developer.apple.com)

如需進一步管理兩套 Xcode 工具鏈,可參考這份​Xcode 雙版本構建環境管理方案,重點不是安裝兩個版本,而是明確記錄每條流水線允許使用哪一套工具鏈。

05

主機無回應:遠程重啟不等於恢復完成

掉電、系統無回應、磁碟加密等待解鎖和遠程連線中斷,處置方式不同。

Apple 支援透過 SSH 對遠程 Mac 執行重啟命令,也支援設定電源故障後自動開機;但這只解決「主機重新啟動」問題,不能直接證明 Runner、Keychain 和 CI 工作已恢復。(support.apple.com)

我們會在備用節點預先完成以下測試:

  • 透過 SSH 或既定遠程管理通道登入。
  • 執行重啟,確認主機可回到可管理狀態。
  • 確認 Runner 服務在啟動後自動恢復。
  • 確認磁碟加密的解鎖路徑由責任人掌握。
  • 確認重啟後 Keychain 可在受控流程中使用。
  • 執行一個不涉及生產發布的測試構建。
  • 記錄需要人工輸入、人工批准或人工確認的步驟。

FileVault 使磁碟解鎖成為災備流程的一部分。Apple 文件指出,Apple Silicon Mac 的 FileVault 金鑰處理與 Secure Enclave 有關;在受管理環境中,組織可使用個人復原金鑰並交由裝置管理服務託管。Apple 亦說明,在 Apple Silicon Mac 搭配 macOS 26 或更新版本的條件下,若已啟用遠程存取且網路可用,存在透過 SSH 解鎖 FileVault 的恢復能力,但企業仍應逐台核對版本與管理條件,不能把它當作所有 Mac 的通用保證。(support.apple.com)

驗收證據至少包括:

故障動作 必須保存的證據 不合格訊號
停止主節點接單 CI 平台狀態、時間戳記 新工作仍送入主節點
啟用備用節點 Runner 狀態、標籤、服務日誌 節點在線但無法接任務
重啟主機 SSH、系統和 Runner 日誌 必須現場登入才能恢復
測試構建 測試結果、Archive 和簽名輸出 只顯示成功編譯
恢復發布 產物、雜湊、上傳紀錄 產物留在本機,沒有可追溯紀錄
演練結束 人工介入點、失敗原因 沒有人知道下一次如何重做
06

發布高峰:隊列變長不一定代表要升級硬體

容量規劃不能靠一次跑分。應觀察一段時間內的:

  • 隊列等待時間趨勢。
  • 同時執行的任務數。
  • 每類工作實際構建時間。
  • 測試、Archive、簽名和上傳各階段耗時。
  • 重試率及因資源不足造成的失敗。
  • 發布窗口與日常開發工作的重疊程度。

如果只有隊列等待增加,而單一任務耗時穩定,問題可能是節點數量不足。如果單一任務本身持續變慢,才需要檢查磁碟空間、記憶體壓力、依賴下載、測試並發或工具鏈變更。

固定基礎負載可以使用長期保留的 Mac 節點。短期發布高峰、Xcode 升級窗口或臨時專案,則可考慮按周或按月增加遠程 Mac 容量。成本模型只需要先列出:

總成本 = 基礎容量成本 + 峰值容量成本 + 運維工時成本 + 故障造成的重跑與延誤成本

不要先填入未核實的價格或節省比例。先把每種方案的使用週期、峰值頻率、需要維護的節點數和可接受人工介入次數列出,再由實際演練結果決定冷備、溫備或按需擴容。

若團隊正在處理隊列等待和節點數量問題,可先閱讀企業 iOS CI/CD 容量規劃方法,把需求拆成基礎容量與峰值容量,而不是按開發者人數直接購買 Mac。

不同 CI 平台的任務路由不能互相套用。GitHub Actions 依賴 Runner 標籤和群組;GitLab 則以 Runner 標籤、工作設定及保護條件匹配。GitLab Runner 的 concurrentlimit 等設定還會影響同一 Runner 可處理的工作數,因此容量測試必須連同平台路由設定一起記錄。(docs.github.com)

07

簽名與依賴異常:能編譯不代表災備成功

最容易被忽略的情況,是備用節點能完成編譯,卻不能完成發布。

常見原因包括:

  • 憑證只有公鑰,私鑰沒有進入正確 Keychain。
  • Provisioning Profile 已過期或不匹配 App ID。
  • Apple 帳戶權限未恢復。
  • 私有 Git 儲存庫需要 SSH 憑證。
  • known_hosts 不存在,依賴取得被拒絕。
  • CI 使用的使用者與手動測試使用者不同。
  • Keychain 在非互動工作階段中沒有解鎖。
  • 依賴快取只存在主節點本地磁碟。

Apple 官方文件指出,使用外部建置系統時,需要自行管理程式碼簽名身份;簽名設定中的憑證、Team ID 和 Provisioning Profile 必須在構建環境中有效,缺少或無效的簽名憑證會導致構建錯誤。(developer.apple.com)

我們會建立一份責任矩陣:

  • 憑證與私鑰:安全或 Apple 開發者帳戶管理人。
  • Provisioning Profile:發布工程師或指定 CI 管理人。
  • Apple 帳戶權限:最小權限原則下的帳戶管理人。
  • SSH 憑證:儲存庫管理人或平台工程團隊。
  • Keychain:Mac 節點管理人。
  • 撤銷與輪換:安全負責人批准,值班工程師執行。

不要用複製整個使用者目錄的方式同步主備。這會把瀏覽器資料、快取、歷史憑證和不必要的個人資料一起帶入備用機,也很難審計。應只分發流水線需要的資產,記錄版本、接收者、用途、失效時間和撤銷路徑。

08

第一次演練:用一條真實發布線完成七個驗收動作

我們建議將演練安排在非發布窗口,但使用與生產相同的程式碼、簽名模式和構建腳本。

第一步:建立演練基線

記錄主用節點與備用節點的 macOS、Xcode、SDK、架構、依賴提交版本、Runner 標籤和簽名資產狀態。

第二步:封鎖主節點新任務

暫停主節點接單,保留現有工作紀錄。確認 CI 平台沒有把新任務錯誤地送到主節點。

第三步:啟用備用節點

確認 Runner 在線、標籤匹配、服務已啟動,並檢查工作目錄與快取策略。

第四步:執行依賴恢復

使用專案鎖定的依賴版本。驗證私有套件、SSH、代理和憑證存取。

第五步:執行測試與 Archive

不要只跑最短的單元測試。至少選擇一條接近生產發布的測試、Archive 和簽名流程。

第六步:核對構建物

保存 .xcarchive、IPA 或其他實際產物,以及簽名檢查、版本號、commit 和雜湊紀錄。

第七步:回切並整理證據

恢復主節點接單,停止備用節點的生產路由,記錄每一步耗時、失敗原因和人工介入。下一次演練應能按照這份紀錄重做,而不是依賴某位工程師記憶。

准入前清單:

  • [ ] 主節點停止接單後,沒有新工作遺漏。
  • [ ] 備用節點能被 CI 平台正確匹配。
  • [ ] Xcode 和 SDK 與發布基線一致。
  • [ ] Package.resolved 或等效依賴鎖定檔已提交。
  • [ ] 私有套件能在非互動工作階段取得。
  • [ ] 簽名憑證、私鑰和 Profile 均能使用。
  • [ ] FileVault 和重啟後恢復路徑已測試。
  • [ ] 真實專案能產出可驗證構建物。
  • [ ] 所有人工介入點有責任人。
  • [ ] 演練紀錄可供審計及下次重做。
09

企業 FAQ:把長尾問題變成准入條件

備用節點需要準備幾台?

沒有固定台數。生產發布不能接受單點故障時,至少要有一台主用節點和一台已驗證可接管的備用節點;當隊列和並發持續增加,再按工作負載增加容量。

兩台 Mac 怎樣保持環境一致?

把 Xcode、SDK、建置設定、腳本和 Swift Package 鎖定檔納入版本控制。不要只依靠磁碟複製或人工記憶;備用節點必須定期執行真實專案驗證。

簽名憑證應由誰保管?

由指定安全或平台負責人管理。憑證、私鑰、Profile、Apple 權限和撤銷流程要分開記錄,並限制能接觸簽名資產的帳戶與工作。

遠程重啟成功後,是否代表節點已恢復?

不是。重啟只代表作業系統重新啟動。還要檢查遠程連線、Runner、Keychain、依賴取得、測試、Archive 和產物上傳。

SLA 應該寫什麼?

不要只寫「節點在線」。SLA 應區分可用性、切換責任、支援範圍、人工介入和產物恢復條件,並以演練結果核對,而不是先假設某個恢復時間。

高峰期應增加常駐節點還是臨時容量?

先看高峰發生頻率與持續時間。固定、持續的基礎負載適合長期節點;短期發布高峰或升級窗口,按需增加遠程 Mac 通常更容易控制容量與運維負擔。

10

最後的採購判斷:先演練,再決定買多少台

如果現有方案是單台機房 Mac,真正的缺點通常不是「算力一定不夠」,而是故障時沒有第二條發布路徑、升級時只能停機等待,而且簽名與依賴狀態容易綁定在某一台主機上。若再加上硬體採購週期、閒置容量和現場維護,企業很難只靠增加單機規格解決業務連續性。

對於無法長期保留備用 Mac 的團隊,MESHLAUNCH 的遠程 Mac 可作為按周或按月交付的臨時災備節點。更穩妥的做法不是先承諾它一定適合,而是用一條真實 iOS CI/CD 流水線驗證環境交付、Runner 接管、簽名恢復、重啟後服務和峰值構建;驗證結果合格,再決定長期採購、溫備保留或按需擴容。相關節點資訊可先從遠程 Mac 企業方案開始核對。