Ubuntu 22.04 手动部署 Jenkins CI 流水线实战指南

Ubuntu 22.04 手动部署 Jenkins CI 流水线实战指南 1. 为什么在 Ubuntu 22.04 上亲手搭建 Jenkins CI 流水线比直接套 Docker 镜像更值得投入时间Jenkins、Continuous Integration、Pipelines、Ubuntu 22.04——这四个词组合在一起不是一句空泛的技术口号而是一条真实可走、能立刻落地的工程化路径。我见过太多团队在项目初期图省事用docker run -p 8080:8080 jenkins/jenkins:lts一键拉起一个 Jenkins 容器结果两周后就卡在“插件装不上”“Maven 找不到 JDK”“Git 凭证死活不生效”“流水线跑一半报failed to resolve host name mirrors.tuna.tsinghua.edu.cn”这类问题上最后不得不推倒重来。这不是 Jenkins 的问题而是跳过了对底层运行环境的理解。Ubuntu 22.04 LTSJammy Jellyfish作为当前主流的长期支持发行版其默认的 systemd 服务管理机制、OpenJDK 11/17 的共存策略、APT 源的镜像配置逻辑、以及/var/lib/jenkins目录的权限继承规则都和 Docker 容器里那个轻量、隔离、但高度抽象的文件系统存在本质差异。你不是在安装一个“工具”而是在为整个持续集成流程构建一个可审计、可复现、可调试的基础设施基座。这个基座一旦建稳后续添加 Java 编译、Vue 打包、Docker 镜像推送、Harbor 上传、甚至跨服务器部署都只是往流水线里加几个 stage 而已而如果基座松动每一个新功能都会变成一次救火。所以本文不讲“三分钟启动 Jenkins”而是带你从apt update开始把每个依赖、每个用户、每个端口、每个证书链都亲手过一遍。这不是复古是回归工程本质——当你清楚知道jenkins用户为什么必须属于docker组/var/lib/jenkins/workspace/下的目录为什么不能被 root 直接 chown你就已经避开了 80% 的线上故障。2. 环境准备绕开 Ubuntu 22.04 默认配置的三大“静默陷阱”很多教程一上来就让你sudo apt install openjdk-11-jdk然后wget下载 Jenkins.deb包。这在干净的最小化安装系统上可能成功但在实际生产或开发环境中Ubuntu 22.04 有三个默认配置会悄无声息地把你绊倒它们不会报错但会让你的 Jenkins 后续完全无法工作。2.1 镜像源未切换导致的“网络超时幻觉”Ubuntu 22.04 默认的sources.list指向的是archive.ubuntu.com和security.ubuntu.com。在国内直连这两个域名延迟高、丢包率大尤其当 Jenkins 启动时需要从updates.jenkins-ci.org拉取初始插件列表或者你在插件管理界面点击“检查更新”时页面会长时间转圈最终显示“连接超时”。更隐蔽的是它不会提示你“网络有问题”而是表现为 Jenkins Web UI 响应缓慢、插件安装按钮灰掉、甚至systemctl status jenkins显示active (exited)却打不开网页。这不是 Jenkins 崩溃了是它卡在网络握手阶段。解决方法必须在安装 Jenkins 前完成# 备份原配置 sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup # 使用 sed 替换为清华源国内最稳定 sudo sed -i s/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g /etc/apt/sources.list sudo sed -i s/security.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g /etc/apt/sources.list # 更新索引此时会明显感觉到速度提升 sudo apt update提示不要用apt upgrade全量升级系统尤其是生产环境。Jenkins 对内核版本不敏感但对libc6、libssl等基础库版本有强依赖。一次apt upgrade可能意外升级libtinfo.so.5到libtinfo.so.6导致 Jenkins 启动时报错error while loading shared libraries: libtinfo.so.5: cannot open shared object file。这是 Ubuntu 22.04 中一个经典兼容性坑根源在于 Jenkins LTS 版本截至 2024 年中仍链接旧版 ncurses 库。我们只做apt update确保源可用即可。2.2 OpenJDK 版本与 Jenkins 的“隐式绑定”Jenkins 官方明确要求 Java 11 或 Java 17 运行时。Ubuntu 22.04 默认仓库提供openjdk-11-jdk和openjdk-17-jdk但问题在于Jenkins 的.deb包安装脚本会自动检测系统中第一个可用的 Java 11 环境并将其硬编码进/etc/default/jenkins的JAVA_HOME变量中。如果你先装了openjdk-11-jdk再装openjdk-17-jdkJenkins 依然会绑定到 JDK 11。这本身没问题但当你后续想用 Maven 编译一个需要 JDK 17 的 Spring Boot 3.x 项目时就会在流水线里看到java.lang.UnsupportedClassVersionError。更糟的是你去修改/etc/default/jenkins重启服务后发现又被覆盖了——因为.deb包的 postinst 脚本每次重启都会重新探测。正确做法是在安装 Jenkins 前先决定并固定你的 JDK 主版本。我推荐 JDK 17因为它是当前 LTS且 Spring Boot、Quarkus 等主流框架已全面适配。执行# 卸载所有已安装的 JDK避免干扰 sudo apt remove --purge openjdk-* # 安装 JDK 17Ubuntu 22.04 默认仓库即含 sudo apt install -y openjdk-17-jdk # 验证并设置系统级默认 sudo update-alternatives --config java # 在交互式菜单中选择 openjdk-17-jdk 的编号 # 手动导出 JAVA_HOME关键 echo export JAVA_HOME/usr/lib/jvm/java-17-openjdk-amd64 | sudo tee -a /etc/profile.d/java.sh sudo chmod x /etc/profile.d/java.sh source /etc/profile.d/java.sh # 验证 java -version # 应输出 openjdk version 17.0.x echo $JAVA_HOME # 应输出 /usr/lib/jvm/java-17-openjdk-amd64这样Jenkins 安装时探测到的JAVA_HOME就是这个你手动设定的路径后续不会被覆盖也为你自己的 Maven、Gradle 构建提供了统一环境。2.3 systemd 服务的“权限继承”误区Jenkins 的.deb包会创建一个名为jenkins的系统用户并将服务注册为systemd单元。很多人以为sudo systemctl start jenkins后一切就归jenkins用户管了。但事实是/var/lib/jenkins目录的属主虽然是jenkins:jenkins其子目录如workspace/、plugins/、jobs/的权限却由umask和父目录继承规则共同决定。Ubuntu 22.04 的默认umask是002这意味着新创建的目录权限是drwxrwxr-x775文件是-rw-rw-r--664。这看起来很安全但问题出在“组写入”上。当你在流水线里用sh git clone ...命令时Jenkins 进程是以jenkins用户身份执行的但它会尝试在workspace/下创建子目录。如果workspace/的组是jenkins而umask允许组写入那么新目录的组就是jenkins一切正常。但如果某次手动操作比如你用root用户cp了一个插件进去不小心把plugins/目录的组改成了root那么后续 Jenkins 就无法向其中写入新插件报错Permission denied。这种错误极难排查因为ls -l /var/lib/jenkins看起来一切正常。解决方案是在 Jenkins 启动前用chmod和chgrp强制规范整个家目录的权限模型# 停止 Jenkins如果已启动 sudo systemctl stop jenkins # 递归设置属主和属组 sudo chown -R jenkins:jenkins /var/lib/jenkins # 设置目录权限为 755所有者读写执行组和其他人只读执行 sudo find /var/lib/jenkins -type d -exec chmod 755 {} \; # 设置文件权限为 644所有者读写组和其他人只读 sudo find /var/lib/jenkins -type f -exec chmod 644 {} \; # 关键设置 setgid 位确保新创建的子目录自动继承父目录的组 sudo chmod gs /var/lib/jenkins sudo chmod gs /var/lib/jenkins/workspace sudo chmod gs /var/lib/jenkins/pluginssetgidgs是 Linux 权限中一个常被忽略但极其关键的特性。它保证了无论谁即使是jenkins用户在/var/lib/jenkins/workspace下创建新目录该目录的组都会自动设为jenkins而不是创建者的主组。这从根本上杜绝了因权限继承混乱导致的流水线失败。3. Jenkins 核心服务安装与首次初始化从命令行到解锁页面的完整链路现在环境已经清理完毕我们可以正式安装 Jenkins。这里强调“正式”是因为我们要跳过所有图形化安装向导全程使用命令行确保每一步都可追溯、可审计。3.1 下载与安装 Jenkins .deb 包非 DockerJenkins 官方提供两种主流安装方式.deb包适用于 Debian/Ubuntu和 Docker 镜像。对于 Ubuntu 22.04.deb包是更优解因为它能与系统的systemd、apt、logrotate深度集成日志自动归档到/var/log/jenkins/磁盘空间自动轮转服务状态与系统启动项完全同步。执行以下命令# 添加 Jenkins 官方 GPG 密钥验证包签名 curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee \ /usr/share/keyrings/jenkins-stable-keyring.asc /dev/null # 添加 Jenkins 官方 APT 仓库注意stable非 weekly echo deb [arch$(dpkg --print-architecture) signed-by/usr/share/keyrings/jenkins-stable-keyring.asc] \ https://pkg.jenkins.io/debian-stable binary/ | sudo tee \ /etc/apt/sources.list.d/jenkins-stable.list /dev/null # 再次更新 APT 索引这次会包含 Jenkins 仓库 sudo apt update # 安装 Jenkins会自动解决依赖包括 Java sudo apt install -y jenkins这条命令链看似简单但背后有深意。https://pkg.jenkins.io/debian-stable是 Jenkins 的稳定版仓库它发布的版本经过充分测试适合生产环境。而weekly仓库则包含最新功能但稳定性风险更高。apt install jenkins不仅安装二进制文件还会创建jenkins系统用户和组创建/var/lib/jenkins主目录注册systemd服务单元/lib/systemd/system/jenkins.service配置/etc/default/jenkins其中HTTP_PORT8080、JENKINS_HOME/var/lib/jenkins等关键变量已预设设置logrotate规则/etc/logrotate.d/jenkins每天轮转日志。3.2 启动服务并获取初始管理员密码安装完成后Jenkins 服务并不会自动启动。你需要手动启用并启动它# 启用开机自启 sudo systemctl enable jenkins # 启动服务 sudo systemctl start jenkins # 检查状态关键必须看到 active (running) sudo systemctl status jenkinssystemctl status jenkins的输出是你判断安装是否成功的第一个黄金指标。如果看到active (running)并且Main PID后面跟着一个数字说明 Java 进程已成功加载。如果卡在activating (start)或显示failed请立即查看日志# 查看实时日志按 CtrlC 退出 sudo journalctl -u jenkins -f # 或查看最近 100 行 sudo journalctl -u jenkins -n 100日志里最常见的错误就是前面提到的libtinfo.so.5缺失或JAVA_HOME路径错误。一旦确认服务运行正常下一步就是获取初始管理员密码。这个密码不是明文存储的而是 Jenkins 在首次启动时随机生成并写入一个临时文件# 读取初始密码注意路径是 /var/lib/jenkins/secrets/initialAdminPassword sudo cat /var/lib/jenkins/secrets/initialAdminPassword你会看到一串 32 位的十六进制字符串例如5a3b8c1d2e4f6a7b8c9d0e1f2a3b4c5d。复制它打开浏览器访问http://你的服务器IP:8080。你会看到 Jenkins 的经典蓝色欢迎页提示“Unlock Jenkins”。粘贴密码点击“Continue”。3.3 插件安装策略自定义 vs 推荐一场关于“最小可行集”的博弈Jenkins 会在此刻给你两个选项“Install suggested plugins”安装推荐插件或 “Select plugins to install”选择插件安装。绝大多数新手会毫不犹豫点第一个。这没错它会安装 Git、Pipeline、Credentials、Mailer 等约 30 个核心插件足够你跑通第一个 Hello World 流水线。但作为一名资深运维我强烈建议你选择第二个手动勾选。原因有三启动时间与资源消耗推荐插件集会下载并安装大量你短期内根本用不到的插件如kubernetes、docker-workflow、blueocean。这会让 Jenkins 首次启动时间从 2 分钟延长到 10 分钟以上且占用更多内存。安全攻击面每个插件都是一个潜在的攻击入口。blueocean插件曾多次曝出高危 RCE远程代码执行漏洞。在生产环境你应该遵循“最小权限原则”只安装必需的插件。版本冲突风险不同插件之间有严格的版本依赖关系。一次性安装太多容易触发PluginDependencyException导致 Jenkins 启动失败。因此我的“最小可行集”清单如下全部勾选Git plugin与 GitHub/GitLab 交互的基础。Pipeline声明式流水线Declarative Pipeline的核心引擎。Credentials Plugin安全地存储和管理 SSH Key、用户名密码等凭证。Mailer Plugin发送构建结果邮件可选但强烈建议。Matrix Project Plugin支持多配置Multi-configuration项目用于跨平台测试可选但非常实用。其他如Docker Pipeline、Kubernetes、Ansible等留待你真正需要它们时再通过 Jenkins Web UI 的“Manage Jenkins Plugins Available” 页面按需搜索安装。这样你的 Jenkins 启动会快得多也更干净。4. 构建第一个 Pipeline从“Hello World”到 Java 项目的完整编译与打包解锁 Jenkins 后你进入主界面。现在我们要创建第一个真正的 CI 流水线。这里的关键是不要用“Freestyle project”自由风格项目而要直接创建“Pipeline”项目。因为 Freestyle 是 Jenkins 1.x 的老范式而 Pipeline尤其是 Declarative Pipeline是现代 CI/CD 的标准它用 Groovy 语法编写代码即配置Code as Configuration所有构建逻辑都以文本形式保存在Jenkinsfile中可以和源码一起提交到 Git 仓库实现版本控制和团队协作。4.1 创建 Pipeline 项目与基础结构在 Jenkins 主界面点击左上角的“New Item”新建任务。在“Enter an item name”框中输入hello-world-pipeline。选择下方的“Pipeline”类型点击“OK”。这会进入一个全新的配置页面。向下滚动找到“Pipeline”部分。这里有两个关键选项Definition: 选择 “Pipeline script”脚本模式这是最灵活的方式适合学习和调试。Script: 在下方的大文本框中输入以下最简化的 Declarative Pipeline 脚本pipeline { agent any stages { stage(Hello) { steps { echo Hello, Jenkins on Ubuntu 22.04! sh uname -a sh java -version sh mvn -v // 如果你后面要装 Maven这行会报错先注释掉 } } } }点击页面右下角的“Save”保存。回到项目主页点击左侧的“Build Now”立即构建。你会看到一个构建队列几秒后开始执行。点击刚生成的#1构建号再点击“Console Output”就能看到实时输出[Pipeline] Start of Pipeline [Pipeline] node Running on Jenkins in /var/lib/jenkins/workspace/hello-world-pipeline [Pipeline] { [Pipeline] stage [Pipeline] { (Hello) [Pipeline] echo Hello, Jenkins on Ubuntu 22.04! [Pipeline] sh uname -a Linux ubuntu2204 5.15.0-xx-generic #xx-Ubuntu SMP ... [Pipeline] sh java -version openjdk version 17.0.x 2023-xx-xx ... [Pipeline] } [Pipeline] // stage [Pipeline] } [Pipeline] // node [Pipeline] End of Pipeline Finished: SUCCESS这个输出证明了三件事Jenkins Agent执行节点能正常调度sh步骤能在 Ubuntu 22.04 的 shell 环境中执行命令Java 17 环境已正确加载。这就是一个完整的、可验证的 CI 流水线骨架。4.2 为 Java 项目准备 Maven 环境上面的hello-world-pipeline只是验证环境。真正的价值在于自动化构建 Java 项目。Ubuntu 22.04 默认不带 Maven我们需要手动安装并将其注册为 Jenkins 的全局工具。首先在 Ubuntu 22.04 上安装 Maven# 下载 Apache Maven 3.9.x最新稳定版 cd /tmp wget https://downloads.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz # 解压到 /opt 目录 sudo tar -xzf apache-maven-3.9.6-bin.tar.gz -C /opt/ # 创建软链接方便后续升级 sudo ln -sf /opt/apache-maven-3.9.6 /opt/maven # 配置环境变量 echo export MAVEN_HOME/opt/maven | sudo tee -a /etc/profile.d/maven.sh echo export PATH$MAVEN_HOME/bin:$PATH | sudo tee -a /etc/profile.d/maven.sh sudo chmod x /etc/profile.d/maven.sh source /etc/profile.d/maven.sh # 验证 mvn -v接着在 Jenkins Web UI 中注册这个 Maven点击左上角“Manage Jenkins” “Tools” “Maven installations...”。点击“Add Maven”。在 “Name” 中输入maven-3.9.6。在 “MAVEN_HOME” 中输入/opt/maven。点击“Save”。现在Maven 已成为 Jenkins 的一个“全局工具”任何 Pipeline 都可以通过tools { maven maven-3.9.6 }来声明使用它。4.3 构建一个真实的 Java Spring Boot 项目假设你有一个托管在 GitHub 上的 Spring Boot 项目地址是https://github.com/yourname/demo-springboot.git。我们将创建一个 Pipeline 来克隆它、编译、打包成 JAR并验证其可运行性。创建一个新的 Pipeline 项目命名为demo-springboot-build。在 Pipeline 配置中选择 “Pipeline script from SCM”从源码管理中获取脚本这是最佳实践意味着Jenkinsfile就放在你的代码仓库根目录下而不是写在 Jenkins 配置里。SCM: 选择 “Git”。Repository URL: 输入https://github.com/yourname/demo-springboot.git。Credentials: 点击右侧的 “Add” 按钮选择 “Jenkins”在 “Kind” 中选择 “Username with password”输入你的 GitHub 用户名和 Personal Access TokenPAT。切勿使用密码GitHub 已弃用密码认证必须使用 PAT。Branches to build: 输入*/main或*/master取决于你的默认分支。Script Path: 保持默认Jenkinsfile。现在你需要在你的demo-springboot仓库根目录下创建一个Jenkinsfile。内容如下pipeline { agent any tools { maven maven-3.9.6 jdk 17 // 这里需要先在 Jenkins 中配置 JDK 工具见下文 } environment { // 定义环境变量供后续步骤使用 APP_NAME demo-springboot BUILD_NUMBER ${BUILD_NUMBER} } stages { stage(Checkout) { steps { checkout scm sh ls -la } } stage(Build) { steps { sh mvn clean compile -B } } stage(Test) { steps { sh mvn test -B } } stage(Package) { steps { sh mvn package -DskipTests -B // 验证 JAR 文件是否生成 sh ls -la target/*.jar } } stage(Verify) { steps { // 尝试启动 JAR不阻塞后台运行 sh nohup java -jar target/*.jar /dev/null 21 // 等待 10 秒让应用启动 sh sleep 10 // 检查进程是否存在 sh ps aux | grep java | grep demo-springboot // 发送 HTTP 请求验证健康端点假设应用有 /actuator/health sh curl -f http://localhost:8080/actuator/health || exit 1 } } } post { success { echo Build and verification succeeded for ${APP_NAME}! } failure { mail to: adminyourcompany.com, subject: FAILED: ${APP_NAME} build #${BUILD_NUMBER}, body: Check the console output at ${env.BUILD_URL}console } } }这个Jenkinsfile展示了现代 CI 的核心思想agent any在任意可用的 Agent 上执行目前只有 Master。tools声明使用哪个 Maven 和 JDK 版本Jenkins 会自动为你配置好PATH和JAVA_HOME。environment定义流水线级别的环境变量。stages清晰划分构建生命周期检出、编译、测试、打包、验证。post构建后的处理成功发通知失败发告警邮件。要让jdk 17生效你还需要在 Jenkins 中配置 JDK 工具“Manage Jenkins” “Tools” “JDK installations...” “Add JDK”。Name:17。JAVA_HOME:/usr/lib/jvm/java-17-openjdk-amd64与你之前设置的JAVA_HOME一致。保存这个Jenkinsfile并推送到 GitHub然后在 Jenkins 中点击 “Build Now”。你会看到一个完整的、从零开始的 Java 项目构建流水线它包含了编译、单元测试、打包、甚至简单的健康检查。这才是 Continuous Integration 的真实模样——每一次代码提交都自动触发一套标准化的验证流程。5. 进阶实战将构建产物部署到远程服务器打通 CI 到 CD 的最后一公里CI持续集成的终点是生成一个可靠的、经过测试的构建产物Artifact比如一个.jar文件或一个.tar.gz包。而 CD持续交付/部署的起点就是把这个产物安全、可靠地放到目标服务器上并启动它。在 Ubuntu 22.04 环境下最常用、最安全的方式是使用 SSH 和scp。但这背后有一系列必须解决的细节问题否则你的流水线会在部署阶段功亏一篑。5.1 在 Jenkins 中安全地管理远程服务器凭证Jenkins 的 Credentials Plugin 是管理敏感信息的唯一正确方式。你绝不能在Jenkinsfile里硬编码用户名和密码也不能把私钥文件直接cat进脚本。正确的流程是生成 SSH 密钥对在 Jenkins Master 服务器上为jenkins用户生成一个专用的、无密码的密钥对仅用于部署。# 切换到 jenkins 用户注意不是 sudo -u jenkins因为 jenkins 用户默认没有 shell sudo su -s /bin/bash jenkins # 生成密钥-N 表示空密码-f 指定文件名 ssh-keygen -t rsa -b 4096 -N -f ~/.ssh/id_rsa_jenkins_deploy # 查看公钥内容需要复制到目标服务器 cat ~/.ssh/id_rsa_jenkins_deploy.pub将公钥部署到目标服务器登录到你的目标服务器例如app-server将上面cat出来的公钥内容追加到~/.ssh/authorized_keys文件中。这一步确保了jenkins用户可以从 Master 无密码登录到目标服务器。在 Jenkins 中添加凭证回到 Jenkins Web UI“Manage Jenkins” “Credentials” “System” “Global credentials (unrestricted)” “Add Credentials”。Kind:SSH Username with private keyScope:Global (Jenkins, nodes, items, all child items)ID:deploy-to-app-server这个 ID 将在 Pipeline 中引用Username:deploy-user你在目标服务器上创建的、专门用于部署的普通用户不要用 rootPrivate Key: 选择 “From the Jenkins master ~/.ssh” 并输入路径/var/lib/jenkins/.ssh/id_rsa_jenkins_deploy注意/var/lib/jenkins/.ssh/id_rsa_jenkins_deploy是jenkins用户的私钥文件路径。Jenkins 的 Credentials Plugin 会安全地加密存储这个私钥并在 Pipeline 执行时将其注入到sh步骤的环境中供ssh和scp命令使用。5.2 编写部署阶段的 Pipeline 脚本现在我们来扩展之前的demo-springboot-buildPipeline在Package阶段之后增加一个Deploy阶段。修改Jenkinsfile的stages部分stage(Deploy) { steps { script { // 获取构建产物的绝对路径 def jarFile sh( script: find target -name *.jar -type f | head -n 1, returnStdout: true ).trim() if (jarFile ) { error No JAR file found in target/ directory! } // 使用 Credentials Plugin 中的凭证进行 SCP 传输 sh scp -o StrictHostKeyCheckingno \ -i /var/lib/jenkins/.ssh/id_rsa_jenkins_deploy \ ${jarFile} deploy-userapp-server:/home/deploy-user/app/ // 登录到目标服务器停止旧进程启动新 JAR sh ssh -o StrictHostKeyCheckingno \ -i /var/lib/jenkins/.ssh/id_rsa_jenkins_deploy \ deploy-userapp-server cd /home/deploy-user/app # 如果有旧进程先 kill pkill -f demo-springboot.jar || echo No old process running. # 启动新 JAR后台运行并重定向日志 nohup java -jar $(basename ${jarFile}) app.log 21 } } }这段脚本的关键点在于script { ... }块允许你在 Pipeline 中执行复杂的 Groovy 逻辑比如动态查找文件。sh步骤中的scp和ssh命令都显式指定了-i参数指向jenkins用户的私钥文件。这绕过了 Jenkins Credentials Plugin 的“自动注入”机制因为我们已经将凭证作为文件安全地存放在了 Jenkins 的文件系统中这种方式更可控、更透明。ssh命令内部是一个完整的 Bash 脚本它在目标服务器上执行一系列操作进入目录、杀死旧进程、启动新进程。pkill -f是一个安全的进程终止方式它根据进程命令行参数-f来匹配比killall更精准避免误杀。5.3 部署后的健康检查与回滚预案一个健壮的 CD 流程不能只关注“部署成功”更要关注“部署后是否真的可用”。因此Deploy阶段之后应该紧接着一个Health Check阶段stage(Health Check) { steps { script { // 循环检查最多等待 60 秒 for (int i 0; i 12; i) { try { // 向目标服务器的应用健康端点发送请求 sh curl -f http://app-server:8080/actuator/health echo Application is healthy! break } catch (Exception e) { echo Health check failed, waiting 5 seconds... (${i1}/12) sleep(5) } } } } }这个循环会每隔 5 秒向app-server:8080/actuator/health发送一次 HTTP GET 请求。如果返回 HTTP 200说明应用已成功启动并响应。如果 60 秒后仍未成功则整个 Pipeline 失败你可以收到告警并手动介入。至于回滚这是一个更高阶的话题。最简单的回滚方案就是在Deploy阶段先将旧的 JAR 文件备份再覆盖新文件# 在 ssh 命令中加入备份逻辑 ssh ... cd /home/deploy-user/app mv demo-springboot.jar demo-springboot.jar.bak.$(date %Y%m%d_%H%M%S) nohup java -jar $(basename ${jarFile}) app.log 21 这样如果新版本出问题你只需登录服务器mv demo-springboot.jar.bak.xxx demo-springboot.jar然后pkill旧进程再nohup java -jar ...启动备份版本即可。自动化回滚需要更复杂的版本管理和配置中心那是另一个深度话题了。6. 故障排查手册Ubuntu 22.04 上 Jenkins 最常见的五个“拦路虎”及其根治方案即使你严格按照上述步骤操作也难免会遇到一些意料之外的问题。这些不是 Jenkins 的 Bug而是 Ubuntu 22.04 环境与 Jenkins 运行时之间微妙的摩擦。我把它们总结为五大“拦路虎”并给出每一种的根治方案而非临时 workaround。6.1 拦路虎一Failed to resolve host name mirrors.tuna.tsinghua.edu.cn这个错误信息非常具体但它指向的不是一个单一问题而是一个DNS 解析链路的全线崩溃。它可能发生在 Jenkins 启动时拉取插件、在 Pipeline 的sh步骤中apt update、甚至在git clone时。根本原因通常是 Ubuntu 22.04 的systemd-resolved服务与网络管理器NetworkManager之间的配置冲突。根治方案绕过systemd-resolved直接配置/etc/resolv.conf。# 停止并禁用 systemd-resolved sudo systemctl stop systemd-resolved sudo systemctl disable systemd-resolved # 删除符号链接创建新的 resolv.conf sudo rm /etc/resolv.conf echo nameserver 114.114.114.114 | sudo tee /etc/resolv.conf echo nameserver 8.8.8.8 | sudo tee -a /etc/resolv.conf # 重启网络服务 sudo systemctl restart NetworkManager114.114.114.114是国内最快的公共 DNS 之一8.8.8.8是 Google DNS 作为备用。这样配置后所有系统进程包括 Jenkins 的 Java 进程都会使用这两个 DNS 服务器mirrors.tuna.tsinghua.edu.cn的解析将瞬间变得稳定。6.2 拦路虎二Permission denied (publickey)在部署阶段这个错误表明 Jenkins 的jenkins用户无法通过 SSH