GitLab Runner macOS 構建機應先部署為只承載可信專案的專用節點,再用真實排隊與並發資料決定是否擴容。不要把一台具備 Shell 權限與簽名憑證的 Mac,直接開放給所有倉庫。
這篇適合正在把 iOS 專案遷移到 GitLab CI/CD、需要補齊 macOS Runner 的平台工程負責人。
如果你負責簽名安全、網路隔離、憑證審計,或正在比較購買、租用與混合配置,也可以直接按本文時間線執行。
先定義構建機邊界,再決定第一台主機
企業部署最容易犯的錯,是先買設備,再想 Runner 要服務哪些工作。正確順序應該相反。
先列出以下邊界:
- 哪些專案屬於可信構建範圍。
- 測試、Nightly、Release 是否需要分開。
- 哪些工作必須使用特定 Xcode 版本。
- 哪些工作會接觸 Apple 簽名私密金鑰。
GitLab Runner 可以設為專案級、群組級或實例級。專案級範圍最小,群組級適合同一團隊下的可信專案,實例級則會擴大暴露面。註冊時還要透過 tags 將工作導向指定 Runner,可參考 GitLab Runner 範圍與工作路由文件。
建議第一階段採用以下邊界:
- 一台專用 macOS 主機。
- 一個專用執行帳號。
- 一組可信專案。
- 一個明確的
ios-shelltag。 - 發布簽名工作另設
ios-releasetag。
這樣做的代價是初期資源利用率可能不高,但你換來的是更容易審計的權限模型。對企業 IT 而言,這通常比把所有專案塞進同一台主機更容易通過安全評估。
注意: Shell executor 不是容器隔離。GitLab 官方明確提醒,Shell 工作可使用 Runner 使用者的權限,也可能讀取同一主機上其他專案留下的檔案,因此只應執行可信構建。
第一小時完成 macOS、帳號與遠端管理準備
GitLab 官方確認,Runner 可安裝在 Apple Silicon 與 Intel Mac 上。iOS 與 macOS 本機構建可使用 Shell executor,因為工作需要直接呼叫 Xcode、xcodebuild、Simulator 與 Keychain。安裝前可先核對 GitLab macOS Runner 安裝文件。
準備順序不要顛倒,建議依照以下步驟完成:
建立專用 macOS 使用者。
不使用日常管理員帳號跑 CI 工作。將日常維護帳號與 Runner 執行帳號分開,並限制 SSH、遠端桌面或網頁控制台的可進入範圍。確認主機可被救援。
先定義主要遠端入口與備援入口。至少要能在 Runner 離線時,透過遠端管理方式檢查登入狀態、磁碟狀態、launchctl與系統日誌。啟用磁碟保護。
FileVault 用於保護靜態資料。Apple 說明指出,Apple Silicon Mac 的加密金鑰處理依賴 Secure Enclave,啟用 FileVault 後,啟動時需要使用者憑證解鎖。請參考 Apple FileVault 安全文件,並把復原金鑰交由企業既有的安全保管流程管理。安裝 Xcode 與命令列工具。
以實際專案需要的版本建立基線,記錄 macOS、Xcode、Swift、CocoaPods、Swift Package Manager 及其他依賴。不要在流水線第一次執行時才下載和決定版本。建立環境快照。
將xcodebuild -version、sw_vers、uname -m、可用 SDK、磁碟容量與 Runner 版本寫入部署紀錄。這些不是性能承諾,而是日後排查環境漂移的證據。
macOS 上的 GitLab Runner 不是系統服務。官方文件指出,它以使用者模式的 LaunchAgent 運作,啟動時機與使用者登入狀態相關,並且需要使用者工作階段來存取 Keychain 與執行 iOS Simulator。
要讓 Runner 在重啟後恢復,必須逐項驗證:
- 指定使用者是否能恢復登入。
- LaunchAgent 是否重新載入。
- 磁碟是否已解鎖。
- Runner 是否重新連線。
- Xcode 與 Keychain 是否可被工作流程使用。
不要只把服務設為「開機啟動」,就認定 GitLab Runner macOS 構建機已經具備無人值守能力。
註冊 Runner:從最小範圍與明確 tags 開始
註冊時,先在 GitLab 介面建立 Runner,再取得 authentication token。不要把舊式 registration token 當成長期部署標準;註冊參數與權限模型應以 GitLab Runner 註冊文件 的現行流程為準。
可使用必要骨架完成註冊:
gitlab-runner register \
--non-interactive \
--url "https://gitlab.example.com/" \
--token "$RUNNER_AUTH_TOKEN" \
--executor "shell" \
--description "ios-build-trusted" \
--tag-list "ios-shell,apple-silicon" \
--run-untagged="false"
部署時請特別檢查:
run-untagged不要讓普通工作自動落到此節點。- 發布 Runner 設為 protected,只接受受保護分支或標籤。
- 專案級 Runner 優先於實例級 Runner。
ios-shell、ios-release、xcode-specific等 tags 要反映真實能力。- Runner 設定檔與 authentication token 只允許平台管理員讀取。
若有外部貢獻者或不受信任的合併請求,不應讓它們直接取得簽名 Runner。Shell executor 的核心限制不是 GitLab 設定項目本身,而是工作會在主機使用者環境中執行,因此主機隔離比單純增加 tags 更重要。
第一條流水線:先驗證構建,再接入簽名
第一條流水線不應一開始就處理正式發布。先用不含生產簽名私密金鑰的測試專案,確認 GitLab CI/CD 與 macOS 主機之間的基本閉環。
建議按以下順序測試:
確認程式碼拉取。
驗證 Runner 能從 GitLab 取得正確分支,並確認工作目錄不是上一次任務的殘留目錄。確認 Xcode 工具鏈。
執行xcodebuild -version,檢查所需 SDK 與 scheme 是否存在。執行最小構建與測試。
先跑指定 scheme 的 build,再加入單元測試。不要把 archive、export、上傳商店一次混在第一個 job。保存測試結果與產物。
將.xcresult、測試報告及必要的 archive 設為 artifacts,確認失敗時仍能取得診斷資料。最後才接入簽名。
使用臨時 Keychain 匯入證書與 Provisioning Profile,完成 export 後清除工作目錄、臨時 Keychain 與敏感檔案。
Apple 的簽名流程需要憑證與對應私密金鑰。Xcode 及命令列工具會從 Keychain 找到可用的 code-signing identity,相關邏輯可參考 Apple Xcode 團隊簽名憑證文件。
一個簡化的工作骨架如下:
ios_build:
tags:
- ios-shell
script:
- xcodebuild -version
- xcodebuild test -workspace "$WORKSPACE" -scheme "$SCHEME" -destination "$DESTINATION"
artifacts:
when: always
paths:
- "*.xcresult"
正式發布時,建議使用另一個 job:
ios_release:
tags:
- ios-release
only:
- protected
script:
- ./ci/import-temporary-keychain.sh
- xcodebuild archive ...
- xcodebuild -exportArchive ...
- ./ci/cleanup-signing-materials.sh
簽名材料不要直接寫入 .gitlab-ci.yml。應使用受保護且遮罩的 CI/CD 變數,必要時採用檔案型變數,在工作開始時匯入臨時 Keychain,完成 archive 或 export 後立即刪除。可參考 GitLab CI/CD 變數安全文件。
快取要有邊界。快取可以減少依賴重建,但共享 Shell 主機上的快取也可能留下跨專案資料。依賴快取與簽名檔案必須分開管理;不能因為構建變快,就把整個工作目錄長期保留。
配置對比:哪一種 Runner 範圍適合企業?
| 部署方式 | 適合工作 | 主要優點 | 主要風險 | 建議 |
|---|---|---|---|---|
| 專案級 Shell Runner | 單一產品或高敏感專案 | 權限邊界最清晰 | 資源利用率可能較低 | 發布簽名優先 |
| 群組級 Shell Runner | 同一團隊的可信 iOS 專案 | 管理成本較低 | 專案間可能有殘留風險 | 測試與 Nightly 可用 |
| 實例級 Shell Runner | 廣泛共享的普通工作 | 集中管理方便 | 暴露範圍最大 | 不建議放簽名憑證 |
| 分離的專用節點池 | 多個 Xcode 基線或敏感級別 | 可按版本與權限路由 | 需要更多維運 | 生產環境較合適 |
這張表反映的是權限與運維取捨,不是固定採購答案。若你有多個 Xcode 版本,與其讓一台主機不斷切換,不如用 tags 將版本需求分開,例如 xcode-current、xcode-legacy。實際 tag 名稱應以你們的維運規範為準。
第一週加固:不要只看 Runner 是否在線
部署完成後,至少安排一次無人值守恢復演練。測試項目包括:
- macOS 重啟後是否自動登入指定使用者。
- LaunchAgent 是否重新載入。
- Runner 是否在 GitLab 控制台恢復可接工作。
- FileVault 解鎖流程是否符合你的遠端救援能力。
- Xcode、Keychain 與 Simulator 是否可被流水線使用。
- 網路中斷後,Runner 是否能重新連線。
- 失敗工作是否保留足夠日誌,但不洩漏憑證。
- 構建後是否刪除工作目錄與臨時簽名資料。
經驗: 「控制台顯示 online」只代表 Runner 能與 GitLab 通訊,不代表 Xcode、Keychain、Simulator、磁碟解鎖與發布流程都可用。生產准入必須以完整流水線和重啟演練作為證據。
建議把 Runner 放在可控的網路區段,限制入站管理來源,僅開放必要的 GitLab、套件來源與 Apple 服務連線。主機上不要存放與構建無關的 SSH 私密金鑰,也不要讓同一執行帳號具備不必要的管理權限。
你可以參考 企業遠端 Mac 構建機安全驗收方向,把網路、權限、日誌與遠端救援列入同一份審查表。若目前沒有完整文件,至少要在內部變更單中保存每次測試的時間、操作者、結果與失敗原因。
用容量證據決定何時擴容
企業需要部署多少台 Mac 構建節點,不能用開發者人數直接換算。你應該持續記錄以下資料:
- Pipeline 排隊等待時間。
- 構建耗時的典型值與高峰值。
- 同時執行工作數。
- 構建失敗率與重試率。
- Xcode 版本切換造成的維護窗口。
- 磁碟成長與快取佔用。
- 發布高峰時段的等待情況。
- 單一節點離線後對交付的影響。
先讓單節點承載真實流水線,再依照結果做決策。不要用團隊人數、預估提交量或供應商建議直接推算節點數。
可用以下條件列表作為決策工具:
- 若單節點可以承受目前高峰,且沒有發布與測試同時排隊,則先維持單節點。
- 若排隊時間已經影響合併或發布窗口,則增加第二台同能力節點。
- 若不同專案需要不同 Xcode 基線,則按 Xcode 版本分組,而不是讓一台主機頻繁切換。
- 若發布憑證與普通測試工作共用同一 Runner,則先拆分權限,再談性能擴容。
- 若負載有明顯週期性,或你缺少現場維運能力,則優先評估可按週、月或季擴容的遠端 Mac。
- 若工作長期穩定、全天候高負載,且需要物理介面或特殊周邊,則自購並自行管理實體 Mac 可能更合適。
成本比較時,不要先填入未核實的價格。可先使用這個公式:
年度 TCO = 硬體採購或租用費 + 維護工時 + 維修與替換成本 + 網路與機房成本 + 閒置成本 + 安全與審計成本
建議建立一份待填表格,逐項輸入你們的真實資料:
| 成本項目 | 自購 Mac | 遠端 Mac 租用 | 混合配置 |
|---|---|---|---|
| 初始設備支出 | 待填 | 待填 | 待填 |
| 每月固定成本 | 待填 | 待填 | 待填 |
| 峰值備用成本 | 待填 | 待填 | 待填 |
| 維運工時 | 待填 | 待填 | 待填 |
| 憑證與安全管理成本 | 待填 | 待填 | 待填 |
| 退出或調整難度 | 待評估 | 待評估 | 待評估 |
如果要先測試遠端節點,可從 KVMNODE 的繁體中文 Mac 遠端方案頁核對可用方案,再將實際交付方式、登入入口、Runner 註冊、流水線結果與重啟記錄納入試點報告。不要在沒有真實測試資料前,預先宣稱節省比例或固定性能。
生產准入:用 go/no-go 條件收尾
在正式接入更多專案前,請把以下條件寫入准入紀錄。
Go:
- 可信專案可完成拉取、構建、測試與產物歸檔。
- 發布工作只會落到受保護 Runner。
- 簽名憑證以受保護變數或安全檔案方式注入。
- 工作完成後,臨時 Keychain、Profile 與工作目錄可清除。
- 重啟後 Runner、Keychain 與 Xcode 流程均可恢復。
- 你已記錄排隊、耗時、失敗率與磁碟成長。
- 有遠端救援路徑,且不依賴某一位工程師的個人電腦。
No-go:
- 未受信任的合併請求可以取得簽名材料。
- Shell Runner 同時承載公開、外部及敏感專案。
- FileVault 啟用後沒有可驗證的遠端解鎖或救援流程。
- 重啟後只恢復控制台在線,完整構建卻失敗。
- 團隊只憑開發者人數決定節點數。
- 沒有保留失敗流水線的日誌與產物。
完成單節點試點後,將峰值並發、Xcode 版本、發布頻率、簽名邊界與重啟記錄整理給採購和資安團隊。這比先一次購買整批 Mac,更能支援後續的預算審批與容量規劃。
如果你目前用的是辦公室內共用 Mac,常見問題是設備閒置與高峰排隊並存、重啟後需要人工登入、維修時沒有備援,還可能把簽名憑證和普通測試工作放在同一環境。對負載波動明顯、需要快速試點的團隊,租用 KVMNODE 的遠端 Mac 可以先建立一個可撤回的構建節點,再用真實流水線決定長期租用週期或自購設備數量。需要臨時算力、版本驗證或發布高峰備援時,這通常比直接採購整批硬體更容易控制決策風險。