某些流水線在託管 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 一定能在無圖形登入狀態下完成測試。
驗收可按以下順序進行:
- 在 SSH 工作階段執行不含簽名的命令列建置。
- 關閉 SSH,確認 Agent 仍能接收新的流水線工作。
- 登出圖形帳戶,測試純命令列任務是否仍能完成。
- 以需要 Simulator 的測試驗證登入工作階段要求。
- 重新啟動遠端 Mac,確認 Agent 服務、工作目錄及網路連線恢復。
- 檢查重啟後的第一個任務沒有使用殘留的半成品或舊測試程序。
如果純命令列工作正常,但圖形測試在登出後失敗,正確做法是把兩類工作分到不同 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 平台流水線簽名流程應一起閱讀。驗收不要只看歸檔成功,而要分成三次:
- 無簽名建置:證明一般工具鏈和產物流程正常。
- 受控簽名歸檔:證明只有獲授權流水線可取得簽名檔案。
- 憑據清理:在任務失敗與成功後檢查工作目錄、暫存區和鑰匙圈,確認沒有可直接重用的敏感檔案。
經驗提醒: 只在普通變數中隱藏證書內容,並不等於完成檔案隔離。秘密可能出現在除錯輸出、暫存檔、工作區或匯入後的鑰匙圈中,必須以失敗重試和清理檢查來驗證邊界。
生產上線決策條件
以下條件可作為是否保留自託管遠端 Mac 的分支判斷:
- 若專案不需要固定 Xcode、內網依賴或持久快取,則優先使用託管 macOS Agent;若外部程式碼不受信任,更不應直接進入含憑證的自託管節點。
- 若只需要持續執行命令列建置,則可使用服務方式常駐;否則將 Simulator 或 UI 測試拆到具備穩定登入工作階段的專用節點。
- 若Xcode 能力、共享 Scheme、測試結果和產物均通過最小專案驗收,則進入真實專案試跑;否則先修正工具鏈或路由,不以 Online 作為通行證。
- 若簽名憑據可按流水線授權、任務完成後清理,則可建立受限制的發布 Pool;否則回退到託管環境或完全隔離的簽名節點。
- 若連續任務、失敗重試、系統重啟和 Agent 更新後都能復原,則才可評估長期運行;否則保留託管方案,或把節點降級為人工測試用途。
上線驗收對照表
下表把「能註冊」與「可投入生產」分開,適合作為團隊交接記錄。表內沒有假設特定 Mac 型號、價格、版本或效能,因為這些資料應以實際租用節點和當日控制台為準。
| 驗收面向 | 註冊成功的證據 | 生產可用的證據 |
|---|---|---|
| Agent 狀態 | 控制台顯示 Online | 重啟後仍能自動恢復並接收任務 |
| 工具鏈 | capabilities 出現相關能力 | xcode-select、xcodebuild、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。