截至 Jenkins LTS 2.555.1,Jenkins 官方要求控制器 JVM 與 Agent JVM 使用 Java 21 或 Java 25;這代表「先升級控制器、之後再處理 Mac Agent」不是安全的遷移順序。Jenkins Java 支援政策 已明確列出這項門檻。Jenkins Java 21 遷移應採取「先盤點、再隔離 Mac 試點、最後升級控制器並分批轉流」的做法,而專案需要的舊 JDK 可以與 Agent JVM 分開保留。

本週建議動作:先建立控制器、插件、Mac Agent、啟動方式和 Xcode 工具鏈清單;若沒有可隔離的 Mac 或回滾容量,先準備一台獨立的遠端 Mac 作為灰度節點,不要在唯一生產打包機上原地試錯。

01

這篇文章適合哪些團隊

本文適合仍有 Jenkins 控制器或 Mac Agent 執行 Java 17 的平台團隊,也適合需要在不中斷 iOS 發布的情況下升級 Jenkins LTS 的企業 IT 負責人。

如果團隊沒有備用 Mac 節點、灰度環境或遠端恢復能力,本文的重點不是立即執行升級,而是先補足可回退的基礎條件。

02

啟動日:建立四類執行環境清單

控制器 JVM、Agent JVM、專案 JDK 和 Xcode 工具鏈是四個不同層次。Jenkins Agent 使用 Java 21,不代表所有 Java 專案都必須改用 Java 21;同樣地,Mac 上安裝了新版 Xcode,也不等於 Agent 已經使用正確的 Java。

啟動日應逐台記錄以下資料:

  • Jenkins 控制器目前版本、JVM 版本與啟動參數。
  • Jenkins LTS 目標版本,以及官方升級指南列出的前置條件。
  • 每台 Mac Agent 的 macOS 版本、CPU 架構、Java 版本、JAVA_HOME、Agent 啟動方式與節點標籤。
  • Pipeline 實際呼叫的專案 JDK、依賴管理工具、Xcode 版本、簽名工作目錄和制品上傳方式。
  • 核心插件、認證插件、憑證插件與 Pipeline 相關插件的目前版本。

截至 2026 年 9 月 3 日,Jenkins 官方文件確認,從 LTS 2.555.1 起,控制器和 Agent 均需 Java 21 或 Java 25;同一套政策也區分了 Agent JVM 與建構工作所用的 JDK。Jenkins LTS 2.555 升級指南 應與 Jenkins 官方 Java 21 遷移文件 一起核對。

不要用「節點目前在線」作為可升級證據。節點可能只是舊程序尚未重啟,或暫時沒有執行需要特定插件、Keychain 和 Xcode 的工作。

03

升級窗口前:固定插件與回滾基線

插件相容性不能只看 Jenkins 核心版本。核心插件、登入與權限插件、憑證插件、Pipeline 插件,以及負責節點資訊顯示的插件,都可能影響控制器升級後的操作結果。插件頁面和目標 LTS 的變更記錄應在升級前重新檢查,而不是等到節點離線後才追查。

回滾基線至少應保存:

  • 控制器設定、Job 定義、節點標籤與任務路由。
  • 現行 Agent 的啟動路徑、環境變數和服務管理設定。
  • 升級前的控制器 JVM、Agent JVM 與專案 JDK 輸出。
  • 最近一次成功的非發布建構,以及包含簽名邊界的發布建構紀錄。
  • 哪些任務可以先轉移,哪些任務必須留在受控 Mac 上。

Jenkins 的節點管理文件說明了節點與 Agent 的管理方式;可在控制器端搭配 Versions Node Monitors 插件說明 觀察節點上的 Java 版本,但插件顯示結果只能作為盤點資料,不能取代 Mac 主機上的實際核查。Jenkins 節點管理文件 亦應納入變更紀錄。

04

隔離試點:先讓 Mac Agent 使用 Java 21

Jenkins 升級 Java 21 前,企業不應先把所有控制器切換到新 JVM。正確順序是挑選一台不承載生產簽名的 Mac Agent,安裝受支援的 Java 21,並讓 Agent 程序明確使用該執行檔。

在 Mac 試點節點先做版本核查:

"$JAVA_HOME/bin/java" -version

預期輸出應能確認主版本為 Java 21;實際輸出格式取決於採用的 JDK 發行版,因此不應把某個廠牌的完整版本字串寫死在自動化檢查中。

若 Agent 以命令啟動,應在啟動腳本中明確指定路徑,而不是依賴互動式 Shell 的預設環境:

export JAVA_HOME="/path/to/java-21"
exec "$JAVA_HOME/bin/java" -jar agent.jar

實際路徑必須依企業核准的 JDK 安裝位置替換。若 Agent 由 LaunchDaemon、其他服務管理工具或網頁控制台啟動,則要在該服務的環境中設定 JAVA_HOME;只在使用者的 .zshrc 設定,通常無法保證無人值守啟動時讀到相同變數。

試點至少驗證:

  • Agent 能否註冊並取得正確節點標籤。
  • 控制器重啟或短暫斷線後,Agent 能否重新連線。
  • Mac 主機重啟後,Agent 是否能依預期自動上線。
  • 控制器讀到的 JVM 版本是否為 Java 21。
  • 工作目錄、權限、Keychain 存取和暫存檔位置是否維持原狀。

完整的 Agent 啟動方式和連線模型可參考 Jenkins Agent 使用文件。這一步要留存「啟動前、斷線中、重新連線後、主機重啟後」的紀錄,因為一次成功建構不足以證明節點具備恢復能力。

Mac 上的 Jenkins Agent 指定 Java 21

關鍵不是在 Mac 上「安裝過」Java 21,而是確認 Jenkins Agent 程序實際由 Java 21 啟動。IT 團隊應從節點程序、服務設定和 Jenkins 節點資訊三處交叉核對;若其中一處仍指向 Java 17,這台 Mac 就不應進入下一批轉流。

05

真實流水線:分開驗證舊 JDK 與 Xcode

Java 21 Agent 仍可建構需要舊 JDK 的專案,前提是專案 JDK 由 Jenkins Tool、Pipeline 環境變數或建構腳本獨立選擇。不能讓 Agent 啟動時使用的 JVM,隨著每個專案的 JDK 設定任意切換。

建議以一條具代表性的 iOS CI/CD 流水線作為試點,而不是只執行空白 Job。流程應包含:

  1. 取得原始碼並確認憑證權限沒有改變。
  2. 還原 Swift Package、CocoaPods 或其他依賴。
  3. 以既定 Xcode 工具執行建構與測試。
  4. 產生非生產制品,確認工作目錄與輸出檔案一致。
  5. 執行受限制的制品上傳驗證。

Xcode 命令列工具的使用方式應依 Apple Xcode Command Line Tools 參考文件 核對。簽名發布仍應留在受控節點,試點階段優先使用非生產憑證或只讀驗證任務;Apple 對簽名程式碼的要求可參考 Apple 程式碼簽名文件

故障分類要寫得足夠具體:

  • Agent 連不上:檢查 Java 路徑、服務環境、連線和主機重啟流程。
  • 插件呼叫失敗:檢查插件版本、控制器變更和權限。
  • 專案 JDK 失敗:檢查 Pipeline 選用的 JDK,而不是回退 Agent JVM。
  • Xcode 或簽名失敗:檢查 macOS 權限、Keychain、證書和工具鏈。
  • 制品上傳失敗:檢查憑證、頻寬與目的端服務,不要直接歸因於 Java 21。
06

分批放量:控制器升級與生產轉流

當隔離 Mac Agent、關鍵插件和代表性 Xcode 流水線都通過後,才進入控制器升級窗口。控制器升級、JVM 切換和任務路由必須能分別回退,不能一次改動所有層次。

建議按以下順序執行:

  • 先停止或凍結會產生發布制品的變更,保留升級前成功建構紀錄。
  • 將尚未遷移的 Mac 節點保留在獨立標籤,避免新版本 Job 誤派到舊 Agent。
  • 先把非發布、可重跑的任務轉到 Java 21 節點。
  • 再轉移歸檔、測試和制品驗證任務。
  • 最後才轉移簽名與發布任務;每批都確認真實建構、斷線重連和回滾結果。
  • 若控制器或插件出現無法歸因的異常,停止放量,回到上一個已驗證的控制器與路由組合。

Jenkins 升級後 Mac 節點離線的回滾邏輯

回滾時先判斷故障層級。若只有 Agent 離線,先把任務路由回未遷移節點,並恢復原 Agent 啟動路徑;若控制器升級或插件變更造成問題,才回退控制器版本與控制器 JVM。專案 JDK 不應因 Agent 回滾而被一併改動,否則會失去故障歸因能力。

07

多台 Mac Agent 的准入清單

多台 Mac Agent 不應以「全部改完再測」的方式遷移。每一台節點都要先符合同一套准入條件,再進入下一批;沒有通過的節點應留在舊路由,直到完成修正。

  • [ ] 已記錄控制器版本、控制器 JVM 與目標 LTS 升級路徑。
  • [ ] 已記錄每台 Mac Agent 的 Java 版本、JAVA_HOME、啟動方式與節點標籤。
  • [ ] 已分開記錄 Agent JVM、專案 JDK、Xcode 與簽名環境。
  • [ ] 已核對核心、認證、憑證與 Pipeline 插件的目標版本相容性。
  • [ ] 已保存控制器設定、節點路由、啟動參數與環境變數。
  • [ ] 已有一台不承載生產簽名的 Mac 完成 Java 21 試點。
  • [ ] 已驗證 Agent 註冊、斷線重連與主機重啟後自動上線。
  • [ ] 已完成包含 Xcode 建構、測試與制品處理的真實流水線。
  • [ ] 已為每個故障類型指定控制器、Agent、專案 JDK 或 Xcode 的責任層。
  • [ ] 已確認至少一條任務路由可以在不改動專案 JDK 的情況下回退。
  • [ ] 已將通過驗收的 Java、插件、Xcode 和啟動設定固化為節點基線。
  • [ ] 已安排首週持續檢查離線、重連、插件異常和無人值守重啟結果。

Jenkins Agent 使用 Java 21 後的舊 Java 專案

可以共存,但必須由專案層明確指定舊 JDK。最穩妥的做法是讓 Agent 固定使用受支援的 Java 21,再由不同 Pipeline 選擇各自需要的專案 JDK;不要透過替換全域 JAVA_HOME 來解決單一專案需求。

08

目前方案與遠端 Mac 的取捨

如果唯一的生產 Mac mini 同時承擔簽名、發布和 Jenkins Agent,原地升級通常有三個缺點:沒有隔離空間、失敗時無法保留生產路由,而且主機重啟或 Java 路徑錯誤可能直接影響發布窗口。自行添購備用實機則會增加採購、維護、折舊和閒置容量的負擔,短期升級所需的灰度節點未必值得永久持有。

因此,當團隊只是需要一台獨立 Mac 做 Java 21 試點、短期擴充 iOS CI/CD 容量或建立回滾緩衝,按週、按月或按季使用 NodeMini 的遠端 Mac,會比在唯一生產主機上冒險更容易安排。NodeMini 提供透過 VNC、SSH 或網頁控制台使用真實 Mac 的方式;團隊可先從遠端 Mac 算力方案評估試點所需的隔離主機,再依NodeMini 繁體中文服務入口了解適合的使用週期。

對長期、穩定且高負載的專屬建構工作,企業仍應比較自購 Mac、專用硬體或既有資料中心資源;若需要直接連接特定實體周邊,也不適合只依賴遠端租賃。真正需要臨時算力、灰度節點或快速回滾容量時,先以清單確認隔離試點條件,再安排一台獨立遠端 Mac,通常比中斷整條 iOS 發布鏈路後才補救更可控。