一台 Mac Agent 还在 Java 17,Jenkins 控制器却先升级完成,结果旧节点集体离线,iOS 发布任务开始排队。
最快的解法是:先盘点插件和节点运行时,在隔离 Mac 上完成 Java 21、重连、重启恢复和真实 Xcode 流水线验证,再升级控制器,最后按任务风险分批转流。项目需要的旧 JDK 可以与 Agent JVM 分开保留。
谁适合按这条路径迁移
这篇文章适合仍有 Jenkins 控制器或 Mac Agent 运行 Java 17 的平台团队,也适合需要在不中断 iOS 发布的情况下升级 Jenkins LTS 的企业 IT 负责人。
如果团队没有备用 Mac、灰度节点或远程恢复能力,迁移前应先解决容量问题;在唯一生产节点上原地切换 Java,不属于可控的升级方案。
⚠️ 注意: 截至 2026 年 9 月 3 日,Jenkins 官方确认,从 Jenkins LTS 2.555.1 开始,控制器 JVM 与 Agent JVM 都必须使用 Java 21 或 Java 25。这个门槛不等于项目必须全部迁移到 Java 21,二者需要分开判断。(Jenkins 官方 Java 支持策略)
最后更新于 2026 年 9 月 3 日,数据核实自 Jenkins 官方 Java Support Policy、LTS 2.555.x Upgrade Guide、2.555.1 Changelog、节点管理文档及 Apple Xcode 命令行文档。
本周先建立迁移基线,而不是直接改版本
Jenkins Java 21 迁移的第一项工作不是安装新 JDK,而是建立一份可回查的运行时清单。Jenkins 至少涉及 4 个容易混淆的层次:
- 控制器 JVM:启动 Jenkins 控制器本身的 Java。
- Agent JVM:启动
agent.jar或 Remoting 进程的 Java。 - 项目 JDK:Maven、Gradle、脚本或其他 Java 项目实际调用的 Java。
- Xcode 工具链:
xcodebuild、模拟器工具、证书、Keychain 和签名环境。
Jenkins 官方明确指出,控制器和 Agent 的运行时,与构建 Java 项目或运行 Java 工具所用的 JDK 可以独立管理;但个别插件可能有更严格的版本要求,因此必须逐个验证。(Jenkins 官方 Java 运行时说明)
本周建议先导出以下信息:
- 控制器 Jenkins 版本、启动方式和当前 JVM。
- 所有 Mac Agent 的系统版本、芯片架构、Java 版本和启动方式。
- 每个节点的标签、执行器数量、任务路由和是否承载签名。
- 核心插件、认证插件、凭证插件和 Pipeline 插件的当前版本。
- Xcode 版本、
xcode-select指向、Keychain 使用方式和制品上传步骤。 - 当前 Agent 启动参数、工作目录、环境变量和自动启动配置。
节点在线并不代表它具备升级条件。Jenkins Agent 是连接控制器的 Java 客户端进程,节点还可能受到磁盘、临时目录、响应时间、时钟同步或重启后无法自动启动等问题影响。(Jenkins 节点管理文档)
目标版本与 Mac 节点的迁移顺序
Jenkins LTS 2.555.1 于 2026 年 4 月 15 日发布,并将 Java 21 或更高版本设为运行要求;官方升级说明要求在升级到该版本前,先处理控制器和 Agent 的 Java 运行时,同时在升级前后更新插件。(Jenkins 2.555 升级指南)
可以把当前环境按下面方式拆开判断:
| 检查对象 | 迁移前要确认什么 | 迁移后的验收标准 |
|---|---|---|
| 控制器 JVM | 是否仍运行 Java 17,启动服务是否固定了 Java 路径 | 控制器正常启动,插件加载无异常 |
| Mac Agent JVM | 是否能安装并显式调用 Java 21 | 注册、断线重连、重启后自动上线 |
| 项目 JDK | 哪些任务仍依赖 Java 8、11 或 17 | Pipeline 明确选择项目所需 JDK |
| Xcode 工具链 | xcodebuild、证书和 Keychain 是否依赖用户会话 |
构建、测试、签名和上传结果可归因 |
| 插件与凭证 | 核心插件、认证插件、凭证插件是否有兼容说明 | 关键 Job 能完成真实调用 |
因此,升级到目标 LTS 前不能把仍在 Java 17 的 Agent 留到控制器升级之后再处理。更稳妥的时间线是:
- 第 1 天:盘点控制器、插件、Mac Agent 和任务路由。
- 第 2 天:备份配置,准备 Java 21 和旧运行时回退路径。
- 第 3 天:隔离一台 Mac Agent,完成重连、重启和代表性构建。
- 第 4 天:更新关键插件,完成控制器升级前检查。
- 第 5 天:升级控制器,并先转移非发布任务。
- 后续运行日:按节点批次转移测试、归档和签名任务。
这个顺序不是为了追求更快,而是为了让故障保持单一变量:先判断 Agent JVM 是否可用,再判断控制器与插件是否兼容,最后判断 Xcode 流水线是否受到影响。
隔离 Mac 试点:固定 Agent 的 Java 21 启动路径
在 Mac 上固定 Jenkins Agent 的 Java 21,关键不在于修改全局默认 Java,而在于让 Agent 启动命令使用绝对路径。这样项目脚本仍可调用自己的 JDK,Agent 进程不会因为用户环境或系统默认设置变化而漂移。
先在试点 Mac 上核查 Java:
/usr/libexec/java_home -V
/usr/libexec/java_home -v 21
典型输出应能看到 Java 21 的安装路径。实际版本号以节点输出为准,不要把示例版本写入生产基线:
21.x.x
/Library/Java/JavaVirtualMachines/.../Contents/Home
随后用该路径启动 Agent:
JAVA_HOME=$(/usr/libexec/java_home -v 21)
exec "$JAVA_HOME/bin/java" \
-jar /opt/jenkins/agent.jar \
-url "$JENKINS_URL" \
-secret "$JENKINS_AGENT_SECRET" \
-name "mac-java21-pilot" \
-workDir "/opt/jenkins/work"
Jenkins 官方的 Agent 模型要求节点具备 Java 和到控制器的网络连接,Agent 命令通常通过 java -jar agent.jar 启动;企业环境应进一步把 Java 路径、工作目录和密钥注入方式固定下来。(Jenkins Agent 使用文档)
不要只在终端手动启动一次。试点至少要验证:
- Agent 首次注册后,Jenkins 节点页面显示的 JVM 版本为 Java 21。
- 主动断开网络后,Agent 能按预期重连。
- Mac 主机重启后,Agent 能在无人登录桌面时自动启动。
- 工作目录权限、临时目录和源码检出权限没有变化。
- Jenkins 的节点监控没有把 Agent 判定为不兼容。
Versions Node Monitors 插件可以显示 JVM 和 Remoting 版本,并支持按控制器运行时检查 Agent 是否满足最低 Java 特性版本。该插件文档还明确展示了 Java 17 Agent 面对 Java 21 控制器时会被判定为不满足要求的情况。(Versions Node Monitors 插件说明)
真实 Xcode 流水线验证要放在控制器升级前
只运行一个 echo 或简单 Shell Job,不能证明 Mac Agent 已经具备生产迁移条件。Apple 官方文档说明,xcodebuild 等命令行工具属于 Xcode 工具链,调用前需要安装 Xcode,并将正确的 Xcode 设置为当前开发者目录。(Apple Xcode 命令行工具参考)
试点阶段应选择一条接近生产的非发布流水线,至少覆盖:
java -version
xcode-select -p
xcodebuild -version
xcodebuild \
-workspace App.xcworkspace \
-scheme App \
-configuration Debug \
-sdk iphonesimulator \
-destination 'generic/platform=iOS Simulator' \
clean build test
这里的重点不是比较构建速度,而是把失败位置分层记录:
- Agent 连接失败:检查 Java 路径、网络、启动服务和 Remoting。
- 插件调用失败:检查插件版本、凭证绑定和 Pipeline 步骤。
- 项目 JDK 失败:检查
JAVA_HOME、Jenkins Tool 或构建脚本。 - Xcode 构建失败:检查 Xcode 选择、依赖缓存、工作目录和权限。
- 签名失败:检查 Keychain、证书、Provisioning Profile 和运行用户。
签名任务尤其不能在试点时直接使用生产凭证。Apple 的代码签名文档指出,签名身份必须存在于 Keychain 中,codesign 才能使用;因此升级 Java 后,即使 Agent 已在线,运行用户或无人值守启动方式发生变化,仍可能导致签名失败。(Apple 代码签名文档)
企业可以先用模拟器构建、单元测试或只读制品验证,确认 Java 迁移没有改变 macOS 权限和工作目录,再把签名任务转入灰度节点。关于节点正式投产前的检查,可参考 Jenkins Mac 构建节点生产验收清单,重点补齐无人值守启动、凭证隔离和节点标签证据。
控制器升级窗口采用双轨转流
当试点 Mac Agent 和关键插件通过后,才进入控制器升级窗口。控制器升级前应同时保存两类回滚对象:
- 版本回滚对象:控制器版本、插件版本、配置文件和备份。
- 路由回滚对象:节点标签、Job 的
agent选择、执行器状态和暂停策略。
不要把所有节点一次性改成同一个新标签。可以先保留旧节点标签,新增一个 mac-java21-pilot 或类似灰度标签,让少量任务明确路由到新节点;控制器升级完成后,再逐批替换生产 Job 的标签。
建议采用以下放量顺序:
- 第一批:代码扫描、文档生成、非发布测试。
- 第二批:普通 Xcode 构建和自动化测试。
- 第三批:归档、制品上传和内部测试分发。
- 最后一批:生产签名、正式发布和高峰期任务。
每一批都必须同时观察 Job 结果和节点状态。Jenkins 官方升级指南特别要求在升级前后更新插件,否则核心版本变化可能暴露插件兼容问题。(Jenkins LTS 升级指南)
如果控制器升级后 Mac 节点离线,先不要删除节点或重新生成所有凭证。应依次检查:
ps aux | grep '[a]gent.jar'
/usr/libexec/java_home -v 21
"$("/usr/libexec/java_home -v 21")/bin/java" -version
tail -n 100 /opt/jenkins/work/agent.log
然后对照迁移前保存的启动命令,判断是 Java 路径变化、工作目录权限变化、密钥失效,还是控制器端插件与 Remoting 版本不匹配。节点监控、节点日志和控制器日志应作为同一份故障证据保存,而不是只记录“节点离线”。
首周把通过的组合固化为节点准入标准
迁移完成后,至少观察一个完整运行周期,再决定是否清理旧 Java。首周需要持续记录:
- Agent 离线和重连事件。
- Mac 主机重启后的自动上线结果。
- 插件异常和 Pipeline 失败分类。
- Xcode 构建、测试、归档和上传结果。
- 生产签名是否仍在受控节点执行。
- 旧 Java 项目是否通过显式 JDK 选择正常完成。
通过验收后,应把以下信息固化成节点基线:
节点名称:
控制器版本:
Agent JVM:
项目 JDK:
Xcode 版本:
xcode-select 路径:
Agent 启动路径:
工作目录:
节点标签:
签名权限:
重启恢复方式:
回滚对象:
如果现有机群没有可隔离的试点节点,或者唯一生产 Mac 无法在窗口内停机测试,就不应把风险压到一台机器上。此时可以先评估增加一台独立的远程 Mac 作为灰度节点,用于 Java 21、Agent 重连和真实 Xcode 流水线验证;关于恢复能力和升级回滚,可进一步阅读 Mac 打包服务器高可用与升级回滚方案。
迁移前后的执行清单
以下清单适合在升级窗口前逐项确认;任何一项无法回答,都不建议直接升级控制器:
- [ ] 已记录控制器当前 Jenkins 版本、JVM 版本和启动路径。
- [ ] 已记录每台 Mac Agent 的 Java 版本、启动方式、标签和任务类型。
- [ ] 已区分控制器 JVM、Agent JVM、项目 JDK 与 Xcode 工具链。
- [ ] 已确认目标 Jenkins LTS 的 Java 支持要求。
- [ ] 已检查核心插件、认证插件、凭证插件和 Pipeline 插件。
- [ ] 已备份控制器配置、节点配置、Agent 启动参数和环境变量。
- [ ] 已准备一台不承载生产签名的隔离 Mac。
- [ ] 已用 Java 21 启动 Agent,并确认节点页面显示的 JVM 版本。
- [ ] 已验证 Agent 断线重连和 Mac 重启后的无人值守恢复。
- [ ] 已完成源码拉取、依赖恢复、Xcode 构建和测试。
- [ ] 已确认项目旧 JDK 能通过 Pipeline 独立选择。
- [ ] 已确认生产凭证没有在试点阶段暴露给非生产节点。
- [ ] 已设计非发布、测试、归档和签名任务的分批路由。
- [ ] 已保存控制器版本、Agent JVM 和任务标签的回滚方案。
- [ ] 已安排首周的离线、重连、重启和流水线失败分类记录。
常见迁移问题
旧 Java 项目是否必须同步迁移
不必。Agent JVM 负责让 Jenkins Agent 连接控制器,项目 JDK 则由构建任务选择。对于仍依赖旧 Java 的项目,应在 Pipeline 中显式设置工具版本或调用对应路径,并单独验证相关插件是否有更高版本要求。
Mac Agent 在线但 Xcode 任务失败怎么办
先确认 Agent 进程使用的 Java 21,再确认 xcode-select -p、Xcode 版本、工作目录和运行用户。若构建失败发生在签名阶段,应重点检查 Keychain 和签名身份,不要把所有失败归因于 Java 迁移。
多台节点是否可以通过同一条命令批量切换
可以批量分发配置,但不建议批量同时放量。不同 Mac 的启动方式、用户权限、Xcode 安装位置和任务标签可能不同,应先按节点角色分组,再按试点、非发布、测试、归档和签名顺序逐批迁移。
没有备用 Mac,是否应该暂停 Jenkins 升级
如果目标是 Jenkins LTS 2.555.1,而现有 Agent 仍运行 Java 17,继续等待并不会消除兼容性门槛。更合理的做法是先获得可隔离的灰度容量;如果本地采购周期过长,可以短期使用按需付费的远程 Mac 计算资源承担试点和回滚缓冲,但仍需按企业安全要求验证访问权限与凭证隔离。
什么时候可以删除 Java 17
当所有控制器、Agent、项目流水线和关键插件都已完成分层验证,并且回滚窗口已经关闭后,再考虑清理旧运行时。项目仍需要 Java 17 的任务不应因为 Agent 迁移而被强制删除旧 JDK。
如果当前方案是把 Jenkins 和 Mac 构建任务压在唯一一台本地 Mac 上,常见缺点是无法安全停机试点、重启恢复依赖现场操作、生产签名与灰度验证互相争抢节点,而且采购第二台机器还会带来折旧、维护和闲置容量问题。对于只需要短期灰度、升级窗口缓冲或临时回滚容量的团队,租赁 NodeMini 的独立远程 Mac 更容易先完成 Java 21 迁移验证,再决定是否长期扩充本地硬件;但长期稳定重负载或必须直接连接特定物理设备的团队,仍应优先评估自购 Mac。
本周可以先用迁移清单确认 3 个条件:是否有隔离试点节点、是否能双轨保留任务路由、是否能在失败后快速切回旧组合。只要其中一项为“否”,就先补齐灰度容量,再安排控制器升级窗口。