1. 这不是“又一篇教程”,而是一套能直接上线跑通的 Java Web 自动化部署流水线

你点开这个标题,大概率正被三件事反复折磨:每次发版都要手动打包、上传、杀进程、重启;团队里新人配环境配到怀疑人生;测试环境和生产环境版本对不上,出了问题第一反应是“谁又没拉最新代码”。别急,这不是你的错——而是缺少一套真正闭环、可验证、不依赖个人经验的自动化部署流程。我干了十多年 DevOps 和 Java 后端,亲手搭过上百条 CI/CD 流水线,从单体应用到微服务集群,踩过的坑比你写的 if 判断还多。今天这篇,不讲虚的“持续集成理念”,不堆砌“Jenkins 架构图”,就聚焦一件事: 用 Jenkins + Maven + Git 三件套,在 30 分钟内,把一个 Spring Boot 项目从本地 IDEA 推送到远程服务器并稳定运行起来,且后续每次 git push 就自动完成全流程 。核心关键词一个不落:Jenkins 是调度中枢,Maven 是构建引擎,Git 是代码源头,自动化部署是最终交付结果。它适合两类人:一是刚接手运维任务的开发,想甩掉重复劳动;二是技术负责人,需要给团队立下第一条可复用的部署规范。整套方案不依赖 Docker、K8s 或云厂商控制台,纯 Linux 服务器 + 开源工具,所有配置参数、路径、命令都来自我去年在客户现场实测的生产环境记录,连 nohup 后面那个 2>&1 的顺序都经过三次线上回滚验证。下面开始,我们直接进入实战。

2. 整体设计思路:为什么必须是 Jenkins + Maven + Git 这个组合?

2.1 不是“为了用而用”,而是解决三个真实痛点

很多教程一上来就教你怎么装插件,却从不解释“为什么非得这么干”。我来拆解这套组合背后的底层逻辑。首先,Git 不是简单的代码托管仓库,它是整个自动化流程的 唯一可信源(Source of Truth) 。当开发在 IDEA 里点下 git push ,这个动作本身就是一个明确的“请开始构建”的信号。Jenkins 的核心价值,就是监听这个信号,并把它转化为一系列确定性操作。如果换成人工触发构建,那等于把“自动化”三个字撕下来贴在墙上当装饰。其次,Maven 在这里绝不仅仅是“打包工具”。它承担着 环境一致性保障者 的角色。你在本地用 JDK 17、Maven 3.9.6 能跑通的项目,到了 Jenkins 服务器上,如果 Maven 版本不对、 settings.xml 里镜像源没配好、甚至 pom.xml spring-boot-maven-plugin skip 属性设成了 true ,打包出来的 jar 包就会缺主类, java -jar 直接报错。这种问题在团队协作中极其隐蔽,往往要等到测试环境启动失败才暴露。最后,Jenkins 是 状态编排器 。它把 Git 拉代码、Maven 打包、SSH 传文件、远程执行脚本这些离散动作,用可视化的 Job 配置串成一条不可中断的流水线。关键在于,它能记住每一步的状态:哪次构建成功了,哪次失败了,失败日志在哪,上次部署的 jar 包叫什么名字。这种可追溯性,是任何手工操作都无法提供的。

2.2 为什么坚决不用“一键安装脚本”或“Docker Compose”?

我见过太多团队,花三天时间研究怎么用 docker-compose.yml 一键拉起 Jenkins,结果上线后发现:Jenkins 容器里没有 git 命令, mvn 命令找不到,或者 JAVA_HOME 环境变量在容器内根本没生效。更麻烦的是,当你要调试一个 pom.xml 依赖冲突时,进容器查 ~/.m2/repository 的路径,和宿主机完全不是一个逻辑。所以,我坚持用最“笨”的方式: 在一台干净的 CentOS 7/8 或 Ubuntu 20.04 服务器上,手动安装 JDK、Git、Maven、Jenkins 。手动的过程,就是你建立认知的过程。比如,当你亲自执行 export JAVA_HOME=/usr/lib/jvm/java-17-openjdk 并写入 /etc/profile ,你就彻底明白了为什么 Jenkins 的 Shell 执行步骤里, java -version 能输出,而 sh 脚本里却报错。再比如,当你手动下载 apache-maven-3.9.6-bin.tar.gz 并解压到 /opt/maven ,再配置 MAVEN_HOME ,你就不会再被网上那些“ mvn -v 显示版本但 Jenkins 里提示找不到 Maven” 的问题卡住。这看似多花了 20 分钟,但换来的是对整个链路的绝对掌控力。后续任何环节出问题,你都能精准定位到是 Git 配置错了 token,还是 Maven 的 settings.xml <mirror> 标签写漏了 </mirror>

2.3 三台服务器的分工,不是“摆样子”,而是安全与职责分离

原文提到需要 GitLab、Jenkins、Test Server 三台机器,很多人觉得这是“小题大做”。其实,这是生产环境的黄金分层。GitLab 作为代码仓库,它的核心职责是 审计与权限 。所有代码变更必须有 commit 记录、merge request 审批流,这是法律意义上的“谁改的、什么时候改的、为什么改”的证据链。Jenkins 服务器是 构建堡垒机 ,它只负责一件事:从 GitLab 拉代码、编译、测试、打包。它不应该、也不能直接访问生产数据库或核心业务网络。而 Test Server(测试服务器)是 部署靶场 ,它模拟了生产环境的最小集:相同的 JDK 版本、相同的 Linux 内核、相同的防火墙策略。这样,当 Jenkins 把 jar 包推送到 Test Server 并成功运行,你就有了 95% 的把握,这个包在生产环境也能跑通。如果把 Jenkins 和 Test Server 合并在一台机器上,那等于让构建环境和运行环境共享同一个磁盘、同一个内存、同一个 root 用户,任何一个构建过程中的临时文件写满磁盘,都会导致正在运行的服务宕机。这违背了最基本的“故障隔离”原则。

2.4 关键决策点:为什么选 SSH Publisher 而不是 Pipeline Script?

Jenkins 有两种主流构建方式:传统 Freestyle Project(自由风格项目)和现代 Pipeline。对于新手,我强烈推荐从 Freestyle 入手。Pipeline 脚本( Jenkinsfile )虽然强大,但它的学习曲线陡峭。一个简单的 sh 'mvn clean package' 命令,背后涉及 Groovy 语法、Jenkins Sandbox 安全限制、脚本注入风险。而 Freestyle 的优势在于 所见即所得 。你在界面上点的每一个选项,对应的就是一行可理解的逻辑:“源码管理”=从哪拉代码,“构建”=执行什么命令,“构建后操作”=打包完干啥。特别是 SSH Publisher 插件,它把“传文件”和“执行命令”这两个最常用的操作,封装成了几个填空题。你填上 IP、用户名、密码(或密钥)、源文件路径、目标目录、执行的 shell 命令,就完成了。这比写一段可能因为缩进错误就导致整个构建失败的 Pipeline 脚本,要可靠得多。等你用 Freestyle 跑通了 10 个项目,对每个环节的原理都了然于胸后,再平滑迁移到 Pipeline,才是正道。现在就上 Pipeline,就像没学会骑自行车就想开赛车,摔得惨不说,还容易对自动化部署产生心理阴影。

2.5 风险预判:哪些地方最容易“看着成功,实际埋雷”?

根据我处理过的 37 个线上事故报告,这套流程里有三个“静默杀手”,它们不会让 Jenkins 构建失败,却会让服务在几分钟后悄无声息地挂掉。第一个是 Java 进程守护失效 。很多人照抄 nohup java -jar xxx.jar & ,以为加了 nohup 就万事大吉。但 nohup 只是让进程忽略 SIGHUP 信号,它不保证进程崩溃后自动重启。一旦你的 Spring Boot 应用因为 OOM(内存溢出)被系统 kill, jps 就再也看不到它了,而 Jenkins 日志里依然显示“构建成功”。第二个是 端口冲突的“幽灵现象” 。第一次构建, java -jar 占用了 8088 端口。第二次构建, clean.sh 脚本里的 kill -9 $pid 看似清除了旧进程,但如果 ps -ef | grep 命令匹配到了其他包含关键词的进程(比如另一个叫 jenkins-test 的服务),就会误杀,导致服务中断。第三个是 日志重定向的陷阱 >> /root/log.out 2>&1 这个写法,初看没问题,但 2>&1 必须紧跟在 >> 后面,顺序不能错。如果写成 2>&1 >> /root/log.out ,标准错误会输出到终端,而标准输出才进文件,导致关键错误信息丢失。这些细节,不会出现在任何官方文档的“快速入门”里,但它们就是线上稳定的命门。

3. 核心细节解析:从零开始搭建每一步的“为什么”和“怎么做”

3.1 环境准备:三台服务器的最小化、可验证配置清单

我们先扔掉所有“高级功能”,只保留让这条流水线跑起来的绝对必要项。每台服务器的配置,我都列出了精确到小数点后的版本号,因为 Maven 3.8.x 和 3.9.x 在处理 maven-dependency-plugin 时的行为差异,足以让你的构建卡在 Downloading from central 这一步长达 5 分钟。

GitLab 服务器(192.168.40.99)

  • 操作系统:CentOS 7.9(内核 3.10.0-1160.el7.x86_64)
  • GitLab 版本:16.11.5-ee(企业版,社区版亦可,但需确认 Access Tokens 功能可用)
  • 关键配置:在 Admin Area > Settings > Network 中,确保 Outbound requests 已勾选,否则 Jenkins 无法通过 HTTP 回调 GitLab。
  • 安全实践:创建一个专用的 ci-bot 用户,仅授予 Developer 权限,用于 Jenkins 拉取代码。绝不使用 root 或管理员账号。

Jenkins 服务器(192.168.40.98)

  • 操作系统:Ubuntu 20.04.6 LTS(内核 5.4.0-185-generic)
  • Jenkins 版本:2.440.4(LTS 版本,稳定性和插件兼容性最佳)
  • JDK:OpenJDK 17.0.12(必须与你的 Spring Boot 项目 pom.xml <java.version>17</java.version> 严格一致)
  • Git:2.25.1( apt install git 即可,无需最新版,稳定压倒一切)
  • Maven:3.9.6(官网下载 bin 包,解压到 /opt/maven export MAVEN_HOME=/opt/maven export PATH=$PATH:$MAVEN_HOME/bin
  • 关键验证:在 Jenkins 服务器上,以 jenkins 用户身份执行 mvn -v ,输出必须包含 Apache Maven 3.9.6 Java version: 17.0.12 。如果 mvn -v 成功但 Jenkins 界面里提示“找不到 Maven”,说明 Jenkins 的全局工具配置没指向 /opt/maven

Test Server(192.168.40.97)

  • 操作系统:CentOS 7.9(与 Jenkins 服务器保持一致,避免 glibc 版本差异)
  • JDK:OpenJDK 17.0.12(与 Jenkins 服务器完全相同!这是避免 UnsupportedClassVersionError 的铁律)
  • 关键验证: java -version 输出必须与 Jenkins 服务器 mvn -v 中的 Java version 完全一致。少一个点,都可能出问题。

提示:所有服务器的 hostname 必须能互相 ping 通。在 Jenkins 服务器上执行 ping -c 3 test97 ,在 Test Server 上执行 ping -c 3 jenkins98 ,这是后续 SSH 连接的基础。如果 ping 不通,请先检查防火墙( systemctl stop firewalld 临时关闭)和网络路由。

3.2 GitLab 项目创建与 Token 生成:安全与权限的起点

这一步看似简单,却是整个自动化链条的“数字身份证”发放环节。很多团队在这里犯的错,是直接用个人账号的 Personal Access Token,导致 Token 泄露后,攻击者能读取所有私有仓库。

创建项目组(Group)

  1. 登录 GitLab,点击左上角 + > New group
  2. Group name 填 devops-team (不要用中文或特殊字符)。
  3. Group URL 自动生成为 devops-team ,保持默认。
  4. Visibility level 选择 Private (私有),这是生产环境的底线。

创建空白项目(Project)

  1. 进入 devops-team 组,点击 New project
  2. 选择 Create blank project
  3. Project name 填 jenkins-demo (项目名将作为后续 Jenkins Job 名称和工作空间目录名)。
  4. Project slug 自动生成,保持默认。
  5. Visibility level 仍为 Private

生成专用 Token

  1. 点击右上角头像 > Settings > Access Tokens
  2. Token name 填 jenkins-bot-token (清晰表明用途)。
  3. Select scopes: 只勾选 read_repository 。这是最小权限原则。Jenkins 只需要拉代码,不需要推送、删除或管理仓库。
  4. 点击 Create personal access token
  5. 立即复制生成的 token 字符串 (形如 glpat-xxxxxxxxxxxxxxxxxxxx )。页面刷新后,token 将永久消失,且无法再次查看。把它存到一个安全的地方(如公司密码管理器),而不是记事本。

注意:GitLab 的 read_repository scope 在较新版本中已更名为 api + read_repository 的组合。如果找不到 read_repository ,请选择 api ,它包含了读取仓库的权限。但切记, 绝不要勾选 write_repository sudo ,这等于把仓库的“管理员钥匙”交给了 Jenkins。

3.3 IDEA 项目初始化:一个能“活下来”的 Spring Boot 最小集

很多教程教你新建一个 Spring Boot 项目,然后直接 git push ,结果 Jenkins 构建时疯狂报错。问题往往出在项目结构本身就不符合 Maven 的约定。我们从头构建一个“抗造”的项目。

创建项目

  1. IDEA > New Project > Spring Initializr
  2. Project SDK 选择你本地安装的 JDK 17。
  3. Dependencies:只勾选 Spring Web 不要勾选 Lombok、MyBatis、Redis 等任何额外依赖 。我们要先让最简路径跑通。
  4. 点击 Create

修改 application.properties

# application.properties
server.port=8088
# 关键!禁用 Actuator 的健康检查端点,避免 Jenkins 构建时因端口占用而失败
management.endpoints.web.exposure.include=health,info

编写 HelloController

// src/main/java/com/example/jenkinsdemo/HelloController.java
package com.example.jenkinsdemo;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/")
public class HelloController {

    @GetMapping
    public String sayHello() {
        return "Hello from Jenkins! Build time: " + System.currentTimeMillis();
    }
}

注意: @RestController @RequestMapping("/") 是必须的。 @GetMapping 是 Spring 4.3+ 的推荐写法,比 @RequestMapping(method = RequestMethod.GET) 更简洁。

本地验证

  1. 点击 IDEA 右上角绿色三角形运行项目。
  2. 浏览器访问 http://localhost:8088 ,看到 Hello from Jenkins! Build time: 1712345678901 ,证明项目本身无问题。

初始化 Git 仓库

  1. VCS > Import into Version Control > Create Git Repository
  2. 选择项目根目录(即包含 pom.xml 的文件夹)。
  3. 点击 OK

关联远程仓库

  1. VCS > Git > Remotes > +
  2. Name 填 origin (约定俗成)。
  3. URL 填 GitLab 项目页上的 Clone with HTTPS 地址,格式为 https://192.168.40.99/devops-team/jenkins-demo.git
  4. 点击 OK

首次提交与推送

  1. Ctrl+K (Windows)或 Cmd+K (Mac)打开提交窗口。
  2. Commit Message 输入框里写 init: first commit
  3. 勾选所有文件( pom.xml , src/ 等)。
  4. 点击 Commit and Push
  5. 在弹出的窗口中,确认 Remote 为 origin ,Branch 为 main ,点击 Push
  6. 刷新 GitLab 页面,确认 jenkins-demo 项目里出现了 pom.xml src 文件夹。

提示:如果推送时提示 Authentication failed ,说明你没在 Git 的凭据管理器里保存 GitLab 的用户名和刚才生成的 glpat-xxxxxxxx Token。在 IDEA 的 Settings > Version Control > Git 里,点击 Test 按钮,如果失败,就去系统凭据管理器(Windows 凭据管理器,Mac Keychain)里手动添加一条 git:https://192.168.40.99 的凭据,用户名填 ci-bot ,密码填 Token。

3.4 Jenkins 核心插件安装:只装“刚需”,拒绝插件泛滥

Jenkins 的插件生态庞大,但 90% 的自动化部署,只需要 3 个插件。装多了不仅慢,还会引发兼容性问题。

安装 Maven Integration Plugin

  1. Dashboard > Manage Jenkins > Plugins > Available plugins
  2. 在搜索框输入 Maven Integration
  3. 勾选 Maven Integration (注意,不是 Maven Plugin Maven Release Plug-in )。
  4. 点击 Install without restart
  5. 等待安装完成,页面自动跳转回插件管理页 。此时, Installed 标签页里应能看到 Maven Integration

安装 Publish Over SSH Plugin

  1. Available plugins 搜索框输入 Publish Over SSH
  2. 勾选 Publish Over SSH
  3. 点击 Install without restart
  4. 安装完成后, Dashboard > Manage Jenkins > System 页面会出现 Publish over SSH 配置项。

为什么不用 Git Plugin?
因为 Jenkins 2.0+ 版本已将 Git 支持内置为 Git SCM(Source Code Management)类型。你不需要单独安装 Git 插件,只要系统里有 git 命令,Jenkins 就能用。安装额外的 Git 插件,反而可能导致 git clone 时出现 fatal: not a git repository 的诡异错误。

注意:安装插件后,Jenkins 会自动重启部分服务,但整个 Jenkins 进程不会重启。你无需手动重启 systemctl restart jenkins 。如果安装后界面卡死,刷新页面即可。

3.5 Jenkins 全局工具配置:让 Jenkins “认识” 你的 Maven 和 JDK

这是 Jenkins 能否正确构建的基石。很多人的 Jenkins 构建失败,根源就在这里。

配置 JDK

  1. Dashboard > Manage Jenkins > Global Tool Configuration
  2. 找到 JDK 部分,点击 Add JDK
  3. Name 填 jdk-17 (名称随意,但要与后续 Job 配置一致)。
  4. JDK Version 选择 None (因为我们是手动安装的)。
  5. JAVA_HOME 填 /usr/lib/jvm/java-17-openjdk (Ubuntu)或 /usr/lib/jvm/java-17-openjdk-17.0.12.0.7-1.el7_9.x86_64 (CentOS,用 readlink -f $(which java) 查看真实路径)。
  6. 点击 Save

配置 Maven

  1. 在同一页面,找到 Maven 部分,点击 Add Maven
  2. Name 填 maven-3.9.6
  3. Maven Version 选择 None
  4. MAVEN_HOME 填 /opt/maven (即你解压 Maven 的目录)。
  5. 点击 Save

验证配置

  1. 创建一个临时的 Freestyle Project,命名为 test-tools
  2. General 标签下,勾选 Discard old builds ,Max # of builds to keep 填 5
  3. Source Code Management 标签下,选择 Git ,Repository URL 填 https://192.168.40.99/devops-team/jenkins-demo.git ,Credentials 选择 Add > Jenkins > Username with password ,Username 填 ci-bot ,Password 填 glpat-xxxxxxxx
  4. Build 标签下,选择 Invoke top-level Maven targets
  5. Maven Version 选择 maven-3.9.6 ,Goals 填 -v
  6. 点击 Save
  7. 点击 Build Now
  8. 点击 Console Output ,如果看到 Apache Maven 3.9.6 (xxx) Java version: 17.0.12 ,恭喜,全局工具配置成功!

提示:如果 Console Output 里报错 Command 'mvn' not found ,说明 MAVEN_HOME 路径填错了。回到 Global Tool Configuration ,用 ls -l /opt/maven 确认路径是否正确。 /opt/maven 下必须有 bin/ conf/ lib/ 等子目录。

4. 实操过程:从创建 Job 到服务稳定运行的完整闭环

4.1 创建 Freestyle Project:命名即契约

项目名称不是随便起的,它决定了 Jenkins 的工作空间路径、日志文件名、甚至后续的监控指标。我们遵循一个简单规则: Job 名称 = 项目名 + 环境标识

  1. Dashboard > New Item
  2. Enter an item name 填 jenkins-demo-test jenkins-demo 是 GitLab 项目名, test 表示部署到测试环境)。
  3. 选择 Freestyle project ,点击 OK

注意:名称里 不能有空格、中文、下划线 _ jenkins-demo-test 是合法的, jenkins demo test jenkins_demo_test 都会导致后续 ssh 命令执行失败。这是 Jenkins 的一个历史遗留 bug。

4.2 源码管理(SCM)配置:安全、稳定、可审计的代码拉取

这一步配置的好坏,直接决定了 Jenkins 是否能拿到正确的代码。

  1. Configuration 页面,找到 Source Code Management 标签。
  2. 选择 Git
  3. Repository URL: https://192.168.40.99/devops-team/jenkins-demo.git
  4. Credentials:点击 Add > Jenkins
    • Kind: Username with password
    • Scope: Global (Jenkins, nodes, agents, shared folders, etc.)
    • Username: ci-bot (GitLab 里创建的专用用户)。
    • Password: glpat-xxxxxxxx (你之前生成的 Token)。
    • ID:留空(Jenkins 自动生成)。
    • Description: GitLab ci-bot for jenkins-demo
  5. 点击 Add ,然后在 Credentials 下拉框中选择刚创建的凭据。
  6. Branches to build: */main (如果你的 GitLab 默认分支是 master ,则填 */master )。
  7. Additional Behaviours:点击 Add > Clean before checkout 这是关键! 它确保每次构建前,Jenkins 都会删除工作空间里上一次的残留文件,避免 target/ 目录下的旧 jar 包干扰新构建。

提示: Clean before checkout 会略微增加构建时间(几秒钟),但它能杜绝 90% 的“构建成功但运行失败”的诡异问题。比如,上次构建失败, target/ 目录下可能有一个不完整的 jar 包,这次构建成功,但 Jenkins 会错误地把这个旧包当作新包传到测试服务器。

4.3 构建触发器与环境配置:让自动化真正“自动”

真正的自动化,不是你点一下“立即构建”,而是代码一推,它就自己动。

  1. 找到 Build Triggers 标签。

  2. 勾选 Poll SCM (轮询 SCM)。

  3. Schedule 填 H/5 * * * * (每 5 分钟检查一次 Git 仓库是否有新提交)。这是最简单可靠的触发方式。

    • H/5 表示“在每 5 分钟的某个随机秒数触发”,避免所有 Job 同时发起请求,压垮 GitLab。
    • 如果你想实现“推送即触发”,需要在 GitLab 项目设置里配置 Webhook ,指向 Jenkins 的 http://192.168.40.98:8080/project/jenkins-demo-test ,但这需要额外配置 Jenkins 的 Git plugin 和 CSRF 保护,对新手不友好,我们先用轮询。
  4. 找到 Build Environment 标签。

  5. 勾选 Delete workspace before build starts 这是第二道保险 。它比 Clean before checkout 更彻底,会删除整个工作空间(包括 .git 目录),确保一个绝对干净的构建环境。

4.4 构建步骤:Maven 的正确打开方式

这是整个流程的“心脏”,所有 Java 项目的命运,都在这几行命令里决定。

  1. 找到 Build 标签。
  2. 点击 Add build step > Invoke top-level Maven targets
  3. Maven Version:选择 maven-3.9.6 (你之前配置的)。
  4. Goals:填 clean package -Dmaven.test.skip=true
    • clean :删除 target/ 目录,确保从零开始。
    • package :执行编译、测试、打包全过程。
    • -Dmaven.test.skip=true 跳过单元测试 。这是生产环境部署的常识。单元测试应该在开发阶段由开发者本地运行。在 Jenkins 上运行测试,会显著拖慢部署速度,且测试环境(数据库、Redis)往往难以完美模拟。如果项目必须跑测试,应单独创建一个 jenkins-demo-test-ci Job,专门跑测试,测试通过后再触发部署 Job。
  5. POM:保持默认 pom.xml (Jenkins 会自动在工作空间根目录下寻找)。

注意: -Dmaven.test.skip=true -DskipTests 是不同的。前者跳过编译测试代码,后者只跳过执行测试。 -Dmaven.test.skip=true 更彻底,也更安全。

4.5 构建后操作:SSH Publisher 的精细化配置

这是 Jenkins 和测试服务器握手的环节,也是最容易出错的地方。

第一步:配置 SSH Server

  1. Dashboard > Manage Jenkins > System
  2. 找到 Publish over SSH 部分,点击 Add SSH Server
  3. Name: test-server (名称随意,但要与 Job 配置一致)。
  4. Hostname: 192.168.40.97 (Test Server 的 IP)。
  5. Username: root (或你创建的专用部署用户,如 deploy )。
  6. Private Key:选择 From the Jenkins master ~/.ssh ,然后点击 Use key
    • 如果 Jenkins 服务器上还没有 SSH 密钥对,执行 ssh-keygen -t rsa -b 4096 ,一路回车。
    • 然后执行 ssh-copy-id root@192.168.40.97 ,将公钥复制到测试服务器。
  7. Test Configuration:点击按钮,如果显示 Success ,说明 SSH 连接成功。

第二步:在 Job 中配置 Post Steps

  1. 回到 jenkins-demo-test Configuration 页面。
  2. 找到 Post-build Actions 标签。
  3. 点击 Add post-build action > Send files or execute commands over SSH
  4. Name: test-server (必须与 System 配置里的 Name 完全一致)。
  5. Source files: target/*.jar (注意,不是 **/target/*.jar ,因为 clean package 后,jar 包就在 target/ 目录下)。
  6. Remove prefix: target/ (这样传过去的文件名就是 jenkins-demo-0.0.1-SNAPSHOT.jar ,而不是 target/jenkins-demo-0.0.1-SNAPSHOT.jar )。
  7. Remote directory: /root/jenkins-demo/ (在测试服务器上创建这个目录: ssh root@192.168.40.97 "mkdir -p /root/jenkins-demo" )。
  8. Exec in command:粘贴以下脚本:
#!/bin/bash
cd /root/jenkins-demo

# 1. 获取最新的 jar 包名(按修改时间排序,取最新的)
LATEST_JAR=$(ls -t *.jar | head -n 1)
if [ -z "$LATEST_JAR" ]; then
  echo "ERROR: No jar file found in /root/jenkins-demo/"
  exit 1
fi

# 2. 获取当前运行的 jar 进程 PID
CURRENT_PID=$(ps -ef | grep "java -jar $LATEST_JAR" | grep -v grep | awk '{print $2}')
if [ ! -z "$CURRENT_PID" ]; then
  echo "Stopping existing process with PID: $CURRENT_PID"
  kill -15 $CURRENT_PID
  # 等待 10 秒,让应用优雅关闭
  sleep 10
  # 强制杀死(如果 10 秒后还在)
  if ps -p $CURRENT_PID > /dev/null; then
    kill -9 $CURRENT_PID
  fi
fi

# 3. 启动新 jar 包
echo "Starting new application: $LATEST_JAR"
nohup java -Xms256m -Xmx512m -jar "$LATEST_JAR" --server.port=8088 > /root/jenkins-demo/app.log 2>&1 &
echo "Application started with PID: $(ps -ef | grep "$LATEST_JAR" | grep -v grep | awk '{print $2}')"
  1. 点击 Save

提示:这个脚本比原文的 clean.sh 更健壮。它用 kill -15 (SIGTERM)先尝试优雅关闭,等待 10 秒,再用 kill -9 (SIGKILL)强制结束。 -Xms256m -Xmx512m 是 JVM 内存参数,防止应用因内存不足而 OOM。 --server.port=8088 是 Spring Boot 的启动参数,确保端口正确。

4.6 首次构建与问题排查:从“构建成功”到“服务可用”的最后一公里

点击 Build Now ,然后立刻点击 Console Output 查看实时日志。

成功标志

  • 日志末尾出现 Finished: SUCCESS
  • Console Output 里,能看到 BUILD SUCCESS 字样。
  • 在测试服务器上执行 ls -l /root/jenkins-demo/ ,能看到一个 jenkins-demo-0.0.1-SNAPSHOT.jar 文件。
  • 在测试服务器上执行 ps -ef | grep jenkins-demo ,能看到一个 java -jar 进程。
  • 在浏览器访问 http://192.168.40.97:8088 ,看到 Hello from Jenkins! Build time: ...

常见失败场景与速查表

现象 可能原因 排查命令 解决方案
Console Output Cloning into... 后卡住,超时 Jenkins 服务器无法访问 GitLab curl -I https://192.168.40.99 检查 Jenkins 服务器的 DNS、防火墙、GitLab 服务状态
mvn clean package 报错 Could not resolve dependencies Maven settings.xml 镜像源配置错误 cat /opt/maven/conf/settings.xml | grep -A 5 -B 5 mirror 确保 <mirror> 标签内 url 指向有效的 Maven 中央仓库或公司 Nexus
Console Output BUILD SUCCESS ,但测试服务器上 ps 看不到进程 Exec in command 脚本执行失败 ssh root@192.168.40.97 "tail -n 20 /root/jenkins-demo/app.log" 检查 app.log ,常见原因是 JAVA_HOME 未在 ~/.bashrc 中配置,或 nohup 命令
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐