1. 为什么内网Jenkins升级和插件安装这么“痛”?
我猜很多运维兄弟或者开发同学,都遇到过和我一样的困境:公司内网有一台“祖传”的Jenkins,版本老旧,插件寥寥无几,全靠一堆Shell脚本硬撑。想用个Pipeline做流水线?想用Multijob管理复杂的项目依赖?门都没有。更头疼的是,这台Jenkins已经跑了成百上千个任务,牵一发而动全身,谁也不敢轻易动它。
我之前的处境就是这样。内网那台Jenkins还是2.346.1,插件列表干净得能照镜子。几十个Freestyle项目,构建全靠手动点,参数全靠手动填。项目A跑完了才能触发项目B,项目C和D可以并行跑……这种依赖关系全靠人肉记忆和定时器,效率低不说,还容易出错。Multijob插件简直就是为这种场景量身定做的,但内网没得装。
最让人抓狂的是插件依赖地狱。你以为下载一个pipeline插件就完事了?Too young。它背后可能依赖workflow-api、workflow-cps等十几个插件,而这些插件又各自有依赖。手动下载?就像玩一个没有地图的拼图游戏,永远不知道缺的是哪一块。更可怕的是,插件和Jenkins版本还有严格的兼容性要求,新插件可能不支持旧版本Jenkins,强行安装轻则功能异常,重则服务崩溃。
所以,直接在内网环境里“盲操”是绝对的自杀行为。我的思路很明确:在可以联网的外网环境,模拟出一个完整、健康、目标版本的Jenkins生态,然后把这个“生态球”整体搬迁到内网,替换掉旧版本。这样做的好处是,所有的插件依赖关系都在外网由Jenkins自身和官方更新中心自动解析、下载、安装完毕,我们拿到内网的是一个已经解决了所有依赖冲突的、即插即用的插件包。这就像是在温室里培育好一株完整的植物,再连土带根一起移栽,成活率远高于在内网贫瘠的土壤里一颗颗播种。
2. 外网环境:精心培育你的“插件生态球”
这一步是整个操作的核心,目的是打造一个干净、目标明确的新Jenkins实例。千万别图省事用你本地乱七八糟的Jenkins来做,建议找一台干净的测试机或者虚拟机。
2.1 准备一个纯净的Jenkins运行环境
首先,确定你要升级到的目标版本。去Jenkins官方长期支持版发布页看看,选一个稳定版。我这里以2.528.3为例,这个版本比较稳定,插件兼容性也广。
# 1. 创建工作目录,这个目录将作为新Jenkins的JENKINS_HOME export JENKINS_HOME="/opt/jenkins_new_2.528.3" mkdir -p $JENKINS_HOME # 2. 下载对应版本的Jenkins WAR包 # 你可以从镜像站下载,比如清华镜像:https://mirrors.tuna.tsinghua.edu.cn/jenkins/war-stable/ wget -O jenkins.war https://get.jenkins.io/war-stable/2.528.3/jenkins.war这里有个关键点:一定要通过export JENKINS_HOME来指定工作目录。这样能确保所有插件、配置、任务都生成在这个独立的目录下,不会和你系统上可能存在的其他Jenkins实例混淆。为这个目录起个清晰的名字,包含版本号,后面迁移时一目了然。
2.2 启动并完成初始化引导
接下来,用一个不同的端口启动这个新Jenkins实例,避免和本地可能存在的其他Jenkins冲突。
# 使用指定的JENKINS_HOME和端口启动 nohup java -jar jenkins.war --httpPort=8081 > /tmp/jenkins_new.log 2>&1 &启动后,用浏览器访问http://你的服务器IP:8081。你会看到经典的Jenkins解锁页面,需要从日志中获取初始管理员密码。
# 查看日志,找到初始密码 tail -f /tmp/jenkins_new.log # 日志中会有一行类似:************************************************************* # ************************************************************* # ************************************************************* # Jenkins initial setup is required. An admin user has been created and a password generated. # Please use the following password to proceed to installation: # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # *************************************************************输入密码后,在“安装推荐插件”和“选择插件来安装”这两个页面,我强烈建议你选择“安装推荐插件”。为什么?因为Jenkins官方推荐的插件集合是一个经过验证的、兼容性良好的基础生态。先把这个基础打牢,我们再按需添加。
2.3 核心操作:安装你真正需要的插件
基础插件装完后,进入Jenkins管理界面,来到“插件管理” -> “可选插件”。现在,开始安装你的目标插件,比如Pipeline和Multijob。
这里有个至关重要的技巧:不要只搜索“Multijob”然后点击安装就完事了。点击插件名称,进入插件详情页。你会看到“依赖项”这个标签页。点进去,Jenkins会清晰地列出这个插件所有依赖的其他插件及其版本。
我们的目标不是只下载multijob一个JPI文件,而是通过Jenkins的安装过程,让它自动把整个依赖树上的所有插件(包括传递依赖)都下载到本地$JENKINS_HOME/plugins目录下。
所以,直接点击“直接安装”按钮。安装完成后,不要重启Jenkins(除非它强制要求)。接着,用同样的方法安装Pipeline插件以及其他任何你需要的插件,比如Git、SSH插件等。
安装过程中,你可以随时去$JENKINS_HOME/plugins目录下看看:
ls -la $JENKINS_HOME/plugins/*.jpi | wc -l你会发现插件数量在不断增加。每个.jpi文件就是一个插件包,旁边通常还有一个同名的.jpi.pinned文件(表示该插件已被固定安装)。至此,一个包含了完整依赖关系的“插件生态球”就在外网环境培育完成了。
2.4 打包你的成果
确认所有需要的插件都安装完毕后,可以停止这个外网Jenkins服务(kill掉Java进程)。然后,对我们精心培育的“生态球”进行打包。
# 进入工作目录的父目录 cd /opt # 将整个plugins目录和jenkins.war打包 tar -czf jenkins_migration_package_2.528.3.tar.gz \ ./jenkins_new_2.528.3/plugins/ \ ./jenkins.war这个压缩包,就是我们将要带入内网的“火种”。
3. 内网迁移:无缝替换,实现“无感”升级
现在,我们拿着打包好的“火种”进入内网环境。内网有两台“Jenkins”:旧的(在运行,端口8080)和新的(我们即将部署,端口先设为8081)。
3.1 部署新版本Jenkins
在内网服务器上,找一个合适的路径,解压我们的迁移包。
# 假设放在 /data/jenkins_new mkdir -p /data/jenkins_new tar -xzf jenkins_migration_package_2.528.3.tar.gz -C /data/jenkins_new解压后,目录结构应该是这样的:
/data/jenkins_new/ ├── plugins/ # 完整的插件生态 │ ├── pipeline.jpi │ ├── multijob.jpi │ └── ... (所有依赖插件) └── jenkins.war # 新版本的WAR包接下来,启动新版本Jenkins,关键点来了:必须使用和在外网时相同的JENKINS_HOME路径结构,并且使用一个不同的临时端口。
# 指定JENKINS_HOME,必须和打包时外网的路径一致(相对路径一致即可) export JENKINS_HOME="/data/jenkins_new/jenkins_new_2.528.3" # 如果plugins目录不在JENKINS_HOME下,需要手动拷贝过去 mkdir -p $JENKINS_HOME cp -r /data/jenkins_new/plugins $JENKINS_HOME/ # 使用一个新端口(如8081)启动,避免与旧版(假设在8080)冲突 nohup java -jar /data/jenkins_new/jenkins.war --httpPort=8081 > /data/jenkins_new/startup.log 2>&1 &访问http://内网IP:8081,你会发现新Jenkins启动后,不需要再经过安装插件的引导流程,直接就能进入主界面,并且在“插件管理”中能看到所有我们从外网迁移过来的插件都已经安装好了。这是因为Jenkins启动时会读取$JENKINS_HOME/plugins目录下的所有.jpi文件并加载它们。
3.2 迁移核心资产:Jobs任务
新Jenkins插件就绪后,下一步是把旧Jenkins的核心资产——也就是所有的构建任务(Jobs)——迁移过来。
操作原则:先迁移,再对比,确保万无一失。
- 停止旧Jenkins的自动构建:在旧Jenkins管理界面,进入“系统管理” -> “准备关机”,可以勾选“禁止新的构建任务”等选项,让正在跑的任务完成,但不再触发新的。这是为了确保迁移过程中任务状态的一致性。
- 拷贝jobs目录:旧Jenkins的
JENKINS_HOME下(假设是/var/lib/jenkins),直接将其中的jobs目录整个拷贝到新Jenkins的JENKINS_HOME下。# 假设旧版目录为 /var/lib/jenkins_old cp -r /var/lib/jenkins_old/jobs /data/jenkins_new/jenkins_new_2.528.3/ - 重启新Jenkins:拷贝完成后,重启新Jenkins(
kill掉进程再重新用相同命令启动)。重启后,刷新页面,你应该能在新Jenkins的首页看到所有从旧版迁移过来的任务列表。
3.3 终极切换:端口接管与收尾
现在,我们有了两个并行的Jenkins:旧版(8080,任务已静止)和新版(8081,任务已迁移)。我们需要让新版正式接管旧版的“门户”(即IP和端口)。
- 全面验证:在新版Jenkins(8081端口)上,随机抽查几个关键任务。查看任务配置是否完整,尤其是涉及SCM(如Git)、构建参数、构建后操作等部分。可以尝试对一两个非核心任务进行一次手动构建,测试整个流程是否通畅。
- 修改新版监听端口:确认无误后,停止新版Jenkins服务。然后,修改新版
JENKINS_HOME下的一个关键配置文件:jenkins.model.JenkinsLocationConfiguration.xml。这个文件定义了Jenkins自认为的根URL。
将其中的vi /data/jenkins_new/jenkins_new_2.528.3/jenkins.model.JenkinsLocationConfiguration.xml<jenkinsUrl>修改为旧版使用的地址和端口。<?xml version='1.1' encoding='UTF-8'?> <jenkins.model.JenkinsLocationConfiguration> <jenkinsUrl>http://内网服务器IP:8080/</jenkinsUrl> </jenkins.model.JenkinsLocationConfiguration> - 切换端口启动:这次,我们用旧版的端口(8080)启动新版Jenkins。
# 先确保旧版Jenkins已完全停止 # 然后启动新版,使用8080端口 nohup java -jar /data/jenkins_new/jenkins.war --httpPort=8080 > /data/jenkins_new/startup_final.log 2>&1 & - 最终验证与旧版下线:访问
http://内网IP:8080,现在响应的已经是新版Jenkins了,而且所有的任务、历史记录都在。进行最后一轮全面功能测试。确认一切正常后,就可以放心地永久停止并卸载旧版本的Jenkins了。
4. 避坑指南:我踩过的那些“雷”
这个方法听起来很顺畅,但实际操作中细节决定成败。下面是我在多次迁移中总结出来的血泪教训。
坑一:用户权限与安全配置丢失旧版JENKINS_HOME下的users、secrets、credentials.xml等目录和文件,存储了所有的用户账号、密码、API Token和凭据。如果你只拷贝了jobs目录,那么新版Jenkins登录账号会丢失,所有任务里配置的Git密码、SSH密钥等凭据都会失效。避坑方法:在迁移jobs目录的同时,必须同步迁移users、secrets、credentials.xml、config.xml(主配置文件)。不过,config.xml里可能包含旧版特有的全局配置,直接覆盖可能引发问题。更稳妥的做法是:先迁移users、secrets、credentials.xml,然后手动对比新旧config.xml,将必要的全局配置(如邮件服务器、全局环境变量等)手工合并到新版的配置中。
坑二:插件版本冲突与降级外网安装插件时,默认安装的都是最新版。但最新版插件可能依赖更高版本的Jenkins核心,或者与某些旧版插件不兼容。虽然我们整体迁移了插件生态,但如果旧版Jenkins的jobs目录里,某个任务配置用到了某个插件的老版本特性,而新版插件已移除该特性,任务加载时就会报错。避坑方法:在外网环境安装插件时,不要无脑点“直接安装”。在插件详情页,点击“版本”标签,查看所有历史版本。如果你知道内网某些任务对特定插件版本有依赖,可以在这里选择安装一个稍旧但稳定的版本。原则是:在满足功能需求的前提下,版本选择宁旧勿新,优先保证稳定性。
坑三:构建工具与环境的差异你的构建任务很可能依赖特定的JDK版本、Maven版本、Node.js版本等。旧版Jenkins上可能通过“全局工具配置”指定了这些工具的路径。新版Jenkins的JENKINS_HOME是全新的,这些配置是空的。避坑方法:迁移前,在旧版Jenkins上记录下所有“全局工具配置”的信息。在新版Jenkins启动并迁移任务后,第一时间去“全局工具配置”页面,按照记录重新配置一遍。或者,更彻底一点,将旧版JENKINS_HOME/tools目录也一并拷贝过来(如果工具是Jenkins自动下载管理的)。
坑四:文件路径的硬编码有些任务的Shell脚本里,可能硬编码了像/var/lib/jenkins/workspace/xxx这样的绝对路径。迁移后,新的JENKINS_HOME路径变了,这些脚本就会找不到文件。避坑方法:在迁移完成后,抽查一些核心任务的构建脚本,检查是否有硬编码的路径。最好的实践是,在任务脚本中始终使用Jenkins提供的环境变量,比如${WORKSPACE},这样无论Jenkins安装在哪里,路径都是正确的。
这套“外网培育,整体迁移”的方案,我亲自在多个生产环境实践过,成功率极高。它的精髓在于将复杂的、易错的在线依赖解析过程,转移到了可控的外网环境,在内网进行的只是简单的文件替换和端口切换,极大降低了风险。记住,耐心做好外网的准备工作,内网的迁移就会像按下开关一样简单。