某些流水線在託管 Agent 上可以編譯,換到團隊的固定工具鏈、內網依賴或簽名鑰匙圈時卻無法穩定重現。

最快的判斷是:普通專案先用託管 macOS Agent;只有在需要持久快取、固定 Xcode、內網存取或可控簽名環境時,才部署獨立帳戶運行的遠端 Mac 自託管 Agent。節點顯示 Online 只代表註冊成功,完成真實建置、重啟復原及憑據隔離後,才可考慮投入生產。

適用對象與部署邊界

這篇內容適合以 Azure Pipelines 執行 iOS 或 macOS 建置、測試任務,並需要固定工具鏈的開發者。
需要讓遠端 Mac 長期在線、接入團隊 Agent Pool 的 DevOps 工程師,也可依此驗收。
如果工作涉及證書、描述檔、發布權限及節點隔離,移動研發平台維護者應特別注意安全段落。

Microsoft 將 Agent 分為託管與自託管兩類;託管環境適合不受信任的外部程式碼,因為執行環境的生命週期與隔離由平台管理。可先閱讀 Azure Pipelines Agent 類型與使用方式,再決定是否把工作移到團隊控制的主機。

選擇遠端 Mac 自託管 Agent,通常是因為以下任一條件成立:

  • 需要在多次執行之間保留套件或建置快取,且快取內容必須由團隊控制。
  • 專案必須鎖定某個 Xcode 與 macOS 組合,不能接受託管映像檔更新造成的變化。
  • 建置測試要連到只在內網可見的 API、套件庫、測試服務或硬體相關服務。
  • 簽名操作需要受控鑰匙圈、描述檔及發布權限,並且要限制可執行任意程式碼的範圍。

反過來說,若 Pull Request 來源不可信、建置不需要固定狀態,或團隊沒有能力維護作業系統與憑證,應回退到託管 Agent。自託管節點不是單純的「更快伺服器」,而是把隔離、更新、清理和復原責任交回團隊。

注意: 遠端 Mac 擁有完整系統權限時,流水線中的腳本也可能取得相同範圍的影響力。不要因為建置節點位於資料中心,就把不受信任的程式碼直接送進含有簽名憑證的 Pool。

建立專用註冊場景

1. 先劃分 Pool 與權限

在 Azure DevOps 控制台建立專用 Agent Pool,命名應能表達用途,例如 <IOS_POOL_NAME>,不要讓簽名節點與一般測試節點共用同一個模糊名稱。專案授權只給需要排程工作的專案,管理權則限制在平台維護群組。

這一步的依據不是 Agent 是否可連線,而是流水線執行時能否按照 Pool 和需求條件找到正確節點;Microsoft 的執行與 Agent 配對說明也將 Agent 選擇視為工作排程的一部分。

2. 準備低權限系統帳戶

在遠端 Mac 建立 <AGENT_USER>,只授予建置所需的檔案、工具及內網權限。工作目錄可使用 <AGENT_WORK_DIR>,不要直接沿用管理者的桌面目錄或個人開發者帳戶,避免 SSH 登入、個人鑰匙圈與流水線工作互相污染。

帳戶準備時應檢查:

  • 能否讀寫 Agent 工作目錄及專案所需的快取目錄。
  • 是否能執行 Xcode 命令列工具,但沒有不必要的管理權限。
  • 是否能取得必要的內網資源,且沒有無限制的其他環境存取權。
  • 是否與日常人工登入帳戶分離。

3. 以控制台產生內容完成註冊

<AGENT_USER> 登入遠端 Mac,從 Azure DevOps 的 Agent Pool 介面取得當次下載與設定指令。組織名稱使用 <AZURE_ORG>,Agent 名稱使用 <AGENT_NAME>,工作路徑使用 <AGENT_WORK_DIR>;認證資訊則使用控制台當次提供的選項和暫存值,不應把任何長期令牌寫死在文章、腳本或版本庫。

Microsoft 提供多種自託管 Agent 認證方式,實際可用選項會受組織政策及控制台狀態影響,應對照官方 Agent 認證方式文件逐項確認。

4. 留存初步註冊證據

註冊完成後先不要宣布上線,至少保存以下畫面或文字記錄:

  • 控制台顯示 Agent 為 Online。
  • Agent 版本和作業系統資訊。
  • capabilities 中已出現的工具能力。
  • 工作目錄可建立、使用及清理檔案。
  • 一個不含簽名的最小流水線成功執行。

Online 只證明控制平面可以通訊;它沒有證明 Xcode、Simulator、簽名或重啟後的自動恢復正常。

常駐方式與圖形工作階段

純命令列建置通常可以由 macOS Agent 的服務方式常駐執行;Simulator、UI 測試或需要圖形登入工作階段的工作,則不能只用「SSH 斷線後程序仍在」來推斷可用。

按照macOS Agent 服務設定文件驗證服務狀態,例如使用控制台產生的 Agent 目錄執行:

cd <AGENT_WORK_DIR>
./svc.sh status

指令中的路徑只是佔位符,實際位置必須替換成節點上的工作目錄。若團隊選擇以 launchd 的 LaunchAgent 或其他常駐機制管理工作,應先確認它與登入工作階段的關係;服務能啟動,不代表 Simulator 一定能在無圖形登入狀態下完成測試。

驗收可按以下順序進行:

  1. 在 SSH 工作階段執行不含簽名的命令列建置。
  2. 關閉 SSH,確認 Agent 仍能接收新的流水線工作。
  3. 登出圖形帳戶,測試純命令列任務是否仍能完成。
  4. 以需要 Simulator 的測試驗證登入工作階段要求。
  5. 重新啟動遠端 Mac,確認 Agent 服務、工作目錄及網路連線恢復。
  6. 檢查重啟後的第一個任務沒有使用殘留的半成品或舊測試程序。

如果純命令列工作正常,但圖形測試在登出後失敗,正確做法是把兩類工作分到不同 Pool 或不同節點,而不是盲目提高帳戶權限。

Xcode 能力與建置路由

先驗證工具鏈,再寫 demands

在遠端 Mac 上檢查目前選用的開發者目錄:

xcode-select -p
xcodebuild -version
xcodebuild -showsdks

這些命令的用途與元件行為可對照 Apple 的 Xcode 命令列工具參考。版本輸出本身不是生產驗收;關鍵是它是否與專案要求、共享 Scheme、SDK 及測試目的相符。

新增或切換 Xcode 後,應重新啟動 Agent,再回到控制台核對 capabilities。否則節點可能仍以舊能力回報,導致 Azure Pipelines 將工作派到不符合工具鏈的 Agent。

用最小專案驗證完整路徑

最小驗收專案應包含共享 Scheme,並分開驗證:

  • xcodebuild 能否完成編譯。
  • 單元測試或指定 Simulator 測試能否執行。
  • 測試結果是否被流水線收集。
  • 建置產物是否在預期工作目錄產生並被發布。
  • 失敗時是否能從日誌判斷是工具鏈、權限、路由還是專案問題。

YAML 中的 Pool 與 demands 使用佔位符示意:

pool:
  name: <IOS_POOL_NAME>
  demands:
    - <REQUIRED_XCODE_CAPABILITY>

steps:
- script: |
    xcode-select -p
    xcodebuild -version
    xcodebuild -scheme <SHARED_SCHEME> \
      -destination '<TEST_DESTINATION>' \
      test
  displayName: 'Validate Xcode toolchain'

能力名稱必須以節點實際回報值及控制台顯示為準,不能自行假定某個名稱永遠存在。若 Azure Pipelines 找不到具備 Xcode 能力的 Agent,先查 xcode-select 指向、Agent 重啟狀態、能力清單和 demands 拼寫,再檢查 Pool 授權。

簽名隔離與發布權限

iOS 簽名不是普通建置步驟。證書、描述檔、鑰匙圈及發布權限一旦放在共享工作區,任何可執行腳本的專案都可能成為敏感資料的間接入口。

較穩妥的分層方式如下:

  • 將證書和描述檔存放於 Secure Files,按流水線或環境限制授權。
  • 不把 .p12、描述檔、解密密碼或長期令牌提交到版本庫。
  • 將一般建置與簽名發布拆成不同 Agent Pool;多專案共享節點時,敏感節點不應接收無關專案。
  • 工作完成後清除匯入的鑰匙圈、描述檔、暫存封裝及解密後檔案。
  • 對簽名工作設定人工審批或環境權限,避免任意分支直接發布。

Secure Files 的權限與使用邊界Apple 平台流水線簽名流程應一起閱讀。驗收不要只看歸檔成功,而要分成三次:

  1. 無簽名建置:證明一般工具鏈和產物流程正常。
  2. 受控簽名歸檔:證明只有獲授權流水線可取得簽名檔案。
  3. 憑據清理:在任務失敗與成功後檢查工作目錄、暫存區和鑰匙圈,確認沒有可直接重用的敏感檔案。

經驗提醒: 只在普通變數中隱藏證書內容,並不等於完成檔案隔離。秘密可能出現在除錯輸出、暫存檔、工作區或匯入後的鑰匙圈中,必須以失敗重試和清理檢查來驗證邊界。

生產上線決策條件

以下條件可作為是否保留自託管遠端 Mac 的分支判斷:

  • 專案不需要固定 Xcode、內網依賴或持久快取,優先使用託管 macOS Agent;若外部程式碼不受信任,更不應直接進入含憑證的自託管節點。
  • 只需要持續執行命令列建置,可使用服務方式常駐;否則將 Simulator 或 UI 測試拆到具備穩定登入工作階段的專用節點。
  • Xcode 能力、共享 Scheme、測試結果和產物均通過最小專案驗收,進入真實專案試跑;否則先修正工具鏈或路由,不以 Online 作為通行證。
  • 簽名憑據可按流水線授權、任務完成後清理,可建立受限制的發布 Pool;否則回退到託管環境或完全隔離的簽名節點。
  • 連續任務、失敗重試、系統重啟和 Agent 更新後都能復原,才可評估長期運行;否則保留託管方案,或把節點降級為人工測試用途。

上線驗收對照表

下表把「能註冊」與「可投入生產」分開,適合作為團隊交接記錄。表內沒有假設特定 Mac 型號、價格、版本或效能,因為這些資料應以實際租用節點和當日控制台為準。

驗收面向 註冊成功的證據 生產可用的證據
Agent 狀態 控制台顯示 Online 重啟後仍能自動恢復並接收任務
工具鏈 capabilities 出現相關能力 xcode-selectxcodebuild、Scheme、測試和產物全數通過
會話 SSH 中可執行命令 斷線、登出及重啟後,符合場景的任務仍能完成
權限 Agent 能存取工作目錄 專用低權限帳戶可用,無不必要管理權限
簽名 能下載或匯入測試憑據 授權、歸檔、清理和失敗重試均有記錄
運維 Agent 可接受單次任務 工作區、快取、磁碟增長、更新與故障責任已明確

託管與遠端 Mac 方案比較

判斷項目 託管 macOS Agent 遠端 Mac 自託管 Agent
工具鏈控制 依當日託管映像檔與官方狀態 團隊控制 Xcode、套件與系統設定
工作區狀態 適合乾淨、可重現的短任務 可保留快取,但必須自行清理
內網存取 受託管環境網路邊界限制 可按節點網路政策連接指定資源
憑據風險 不必長期保留團隊鑰匙圈 必須拆分 Pool、限制授權並清理殘留
維護責任 主要由平台管理 團隊負責更新、重啟、磁碟和故障復原
較適合的情況 不受信任程式碼、短生命週期建置 固定 Xcode、持久快取、內網或受控簽名

遠端 Mac 的選擇與落地

若驗收顯示專案確實需要固定 Xcode、長期在線和獨立權限帳戶,遠端 Mac 比臨時拼接多個不受控環境更容易建立一致的 Agent Pool;但它的代價是團隊要承擔工作區衛生、更新和憑據保護。

相較之下,單純依賴託管 Agent 可能遇到工具鏈版本切換、快取無法長期保留,以及內網資源不可直接存取等限制;若改用一台開發者個人 Mac 作為節點,又會出現帳戶依賴、人工重啟和日常工作互相干擾的問題。若團隊不想先購置並維護一台專用實機,可先參考 遠端 Mac 節點配置與租用週期,以實際工具鏈驗收結果決定租用週期,再建立獨立 Pool,而不是先承諾長期架構。

需要臨時建置環境、版本驗證或一個長時間在線的 Mac 節點時,RUVCLOUD 的遠端 Mac 租用可讓團隊先完成上述註冊、重啟和簽名測試;若最終工作量長期穩定且需要實體介面,自購 Mac 仍可能較合適。完成最小流水線驗證後,再到 遠端 Mac 方案頁面查看可用安排,讓租用決定建立在 Azure Pipelines 的實際驗收,而不是只建立在節點顯示 Online。