在日常开发中,Spring Boot 项目部署通常会经历这些步骤:
拉取代码
本地打包
上传服务器
停止旧进程
启动新 Jar 包
查看日志
验证接口如果每次都手动操作,不仅效率低,也容易出错。
本文记录一种基于 Jenkins、Maven、Git 和 SSH Publisher 的简单自动化部署流程。
整体流程如下:
开发者提交代码到 GitLab
↓
Jenkins 拉取代码
↓
Jenkins 使用 Maven 打包 Spring Boot 项目
↓
Jenkins 通过 SSH 将 Jar 包上传到测试服务器
↓
测试服务器清理旧进程和旧 Jar 包
↓
启动新的 Spring Boot 应用一、环境准备
本文示例使用三台服务器:
整体职责如下:
GitLab:保存项目代码;
Jenkins:负责拉代码、编译、打包、发布;
测试服务器:负责运行最终的 Spring Boot 服务。
二、创建 GitLab 项目
先在 GitLab 中创建一个空白项目。
基本流程是:
创建 Group
创建 Project
获取远程仓库地址
创建 Access TokenAccess Token 后续用于 IDEA 或 Jenkins 访问 GitLab 仓库。
创建完成后,可以拿到类似下面的仓库地址:
http://192.168.40.99/group-name/project-name.git三、创建 Spring Boot 测试项目
在 IDEA 中创建一个简单的 Spring Boot 项目。
依赖选择:
Spring Web配置端口:
server.port=8088创建测试 Controller:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/")
public class HelloController {
@RequestMapping
public String sayHello() {
return "Hello dev";
}
}本地启动后访问:
http://127.0.0.1:8088如果返回:
Hello dev说明项目可以正常运行。
四、将代码推送到 GitLab
在 IDEA 中配置 Git。
路径大致为:
Settings -> Git -> Path to Git executable然后将当前项目初始化为 Git 仓库:
Version Control -> Create Git Repository配置远程仓库:
Git -> Manage Remotes填入 GitLab 项目的 HTTP 地址。
之后执行:
Commit
Push将代码推送到 GitLab。
如果 GitLab 使用分支保护或 Merge Request 流程,需要在 GitLab 页面完成代码合并。
五、Jenkins 安装 Maven 插件
Jenkins 需要使用 Maven 构建项目,因此需要安装 Maven 插件。
路径:
Dashboard -> Manage Jenkins -> Plugins -> Available plugins搜索:
Maven安装 Maven Integration 相关插件。
安装完成后,回到 Jenkins 首页。
六、创建 Jenkins 构建任务
新建 Jenkins 任务:
Dashboard -> New Item任务类型可以选择 Maven 项目。
例如任务名称:
first进入任务配置页面后,配置 Git 仓库地址和凭据。
七、配置 Git 仓库
在 Jenkins 任务配置中找到源码管理部分。
选择:
Git填写仓库地址:
http://192.168.40.99/group-name/project-name.git添加 GitLab 凭据。
如果使用 Access Token,可以将用户名和 Token 配置到 Jenkins 凭据中。
然后配置要构建的分支,例如:
*/main或者:
*/master具体取决于 GitLab 项目的默认分支。
八、配置 Maven
在 Jenkins 全局工具配置中配置 Maven。
路径:
Manage Jenkins -> Tools配置 Maven 安装路径。
例如:
/usr/local/maven/apache-maven-3.x.x在任务配置中,Root POM 通常保持默认:
pom.xml如果项目是多模块结构,需要根据实际路径调整。
例如:
backend/pom.xmlGoals 可以配置为:
clean package -DskipTests如果需要执行测试,可以去掉:
-DskipTests九、测试 Jenkins 打包
保存任务配置后,点击:
Build Now进入构建历史,查看控制台输出。
如果构建成功,Jenkins 会在 workspace 下生成 Jar 包。
示例路径:
/root/.jenkins/workspace/first/target/可以在 Jenkins 服务器上测试运行:
java -jar jenkins-study-0.0.1-SNAPSHOT.jar如果项目正常启动,说明 Jenkins 已经可以完成代码拉取和 Maven 打包。
十、常见打包问题
如果执行:
java -jar jenkins-study-0.0.1-SNAPSHOT.jar报错:
no main manifest attribute通常说明 Spring Boot Maven 插件没有正确参与打包。
需要检查 pom.xml 中是否配置了:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>如果配置中有 skip,需要确认是否被设置成了:
<skip>false</skip>确保最终打出来的是可执行 Spring Boot Jar。
十一、安装 SSH Publisher 插件
Jenkins 要把 Jar 包上传到测试服务器,可以使用 SSH Publisher 插件。
插件安装路径:
Dashboard -> Manage Jenkins -> Plugins -> Available plugins搜索:
SSH Publisher安装完成后,进入系统配置页面。
十二、配置测试服务器 SSH 信息
路径:
Dashboard -> Manage Jenkins -> System找到:
Publish over SSH新增一台服务器。
示例配置:
Name: test97
Hostname: 192.168.40.97
Username: root
Remote Directory: /root如果使用密码登录,就配置密码。
如果使用密钥登录,就配置私钥。
配置完成后点击:
Test Configuration
确认 Jenkins 能正常连接测试服务器。
十三、配置构建后上传 Jar 包
进入 Jenkins 任务配置:
Dashboard -> first -> Configuration找到:
Post Steps选择:
Send files or execute commands over SSH配置上传文件。
示例:
Source files: target/jenkins*.jar
Remove prefix: target
Remote directory: /root/jenkins-study含义:
Source files:从 Jenkins workspace 中匹配 Jar 包;Remove prefix:去掉上传路径中的target目录;Remote directory:上传到测试服务器的目标目录。
例如最终 Jar 包会上传到:
/root/jenkins-study/jenkins-study-0.0.1-SNAPSHOT.jar十四、启动远程 Jar 包
在 SSH Publisher 的 Exec command 中配置启动命令:
nohup java -jar /root/jenkins-study/jenkins*.jar >> /root/jenkins-study/log.out 2>&1 &这条命令的含义是:
nohup:忽略挂起信号,终端关闭后进程仍然运行
>>:将标准输出追加到 log.out 文件
2>&1:将错误输出重定向到标准输出
&:后台运行构建完成后,可以在测试服务器执行:
jps如果看到项目进程,说明启动成功。
十五、远程服务器找不到 Java 的问题
如果测试服务器日志中出现:
nohup: failed to run command ‘java’: No such file or directory说明 Jenkins 通过 SSH 执行命令时,没有拿到正确的 Java 环境变量。
可以在测试服务器上配置 /etc/bashrc:
export JAVA_HOME=/usr/local/jdk/jdk-17.0.12
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/lib/然后执行:
source /etc/bashrc也可以在 Jenkins 的启动命令中直接使用 Java 绝对路径,例如:
nohup /usr/local/jdk/jdk-17.0.12/bin/java -jar /root/jenkins-study/jenkins*.jar >> /root/jenkins-study/log.out 2>&1 &这种方式更直接,也不依赖 Shell 环境变量。
十六、为什么需要清理旧进程
如果第一次构建已经启动了应用,后续再次构建时直接执行:
nohup java -jar /root/jenkins-study/jenkins*.jar >> /root/jenkins-study/log.out 2>&1 &可能会启动失败。
原因是旧进程还在占用端口。
例如应用端口是:
8088旧进程没有停止,新进程启动时就会报端口占用。
表现可能是:
jps 看到的进程 PID 一直没变
log.out 中出现端口被占用所以每次部署前需要先清理旧进程和旧 Jar 包。
十七、编写清理脚本
在测试服务器 /root 目录下创建脚本:
vim /root/clean.sh内容如下:
#!/bin/bash
appname=$1
if [ -z "$appname" ]; then
echo "应用名称不能为空!"
exit 1
else
echo "应用名称为 $appname"
fi
# 清理旧版本 jar 包
rm -rf /root/$appname/${appname}*.jar
# 获取正在运行的项目 pid
pid=$(ps -ef | grep "$appname" | grep 'java -jar' | grep -v grep | awk '{print $2}')
echo "pid 为 $pid"
if [ -z "$pid" ]; then
echo "$appname is not started"
else
kill -9 $pid
echo "$appname was stopped"
fi
赋予执行权限:
chmod +x /root/clean.sh脚本参数说明:
$1:脚本第一个参数,也就是应用名称
-z:判断字符串是否为空
ps -ef:查看进程
grep:过滤应用进程
awk '{print $2}':取进程 PID十八、配置 Jenkins Pre Steps
在 Jenkins 任务配置中添加 Pre Steps。
选择:
Send files or execute commands over SSH执行清理命令:
/root/clean.sh jenkins-study这样每次构建时会先执行:
停止旧进程
删除旧 Jar 包然后再上传新 Jar 包并启动。
重新构建后,可以在测试服务器查看:
jps如果 PID 发生变化,说明旧应用已经停止,新应用已经启动。
十九、测试部署结果
部署完成后访问测试服务器:
http://192.168.40.97:8088如果返回:
Hello dev说明 Jenkins 自动化部署流程已经跑通。
完整流程是:
GitLab 拉取代码
Maven 打包
SSH 上传 Jar 包
执行清理脚本
启动新应用
访问接口验证二十、目前方案的问题
这套流程可以完成基础自动化部署,但仍然比较简化。
实际项目中还需要继续完善。
1. 不建议直接 kill -9
示例中使用:
kill -9 $pid这是强制停止进程。
更稳妥的方式是先使用:
kill $pid等待应用优雅关闭。
如果超时后还没退出,再考虑:
kill -9 $pid这样可以给 Spring Boot 应用释放资源的机会。
2. 没有做版本备份
当前脚本会直接删除旧 Jar 包。
如果新版本启动失败,不方便快速回滚。
更好的方式是:
保留最近几个版本
部署失败时回滚上一个 Jar3. 没有健康检查
当前启动后只是通过 jps 判断进程是否存在。
但进程存在不代表应用真正可用。
可以增加健康检查接口,例如:
/actuator/health部署后自动请求健康检查接口。
只有返回正常,才认为部署成功。
4. 没有处理多环境配置
实际项目通常有:
dev
test
prod不同环境需要不同配置。
可以通过启动参数指定:
--spring.profiles.active=test例如:
nohup java -jar /root/jenkins-study/jenkins*.jar --spring.profiles.active=test >> /root/jenkins-study/log.out 2>&1 &5. 凭据和 Token 需要安全管理
GitLab Token、SSH 密码、私钥等不要写在脚本或日志中。
应该统一放到 Jenkins Credentials 中管理。
二十一、可以继续优化的方向
后续可以继续改进:
使用 Jenkins Pipeline 管理构建流程;
使用 Git Tag 或 Commit ID 标记部署版本;
增加构建前单元测试;
增加部署后健康检查;
增加失败回滚脚本;
使用 systemd 管理 Spring Boot 进程;
使用 Docker 镜像部署;
使用 Webhook 实现代码提交后自动触发构建;
增加钉钉、企业微信或邮件通知;
区分测试环境和生产环境的部署权限。
结论
本文记录了一套简单的 Jenkins 自动化部署流程。
核心步骤是:
GitLab 保存代码;
Jenkins 拉取代码;
Maven 构建 Spring Boot Jar;
SSH Publisher 上传 Jar 到测试服务器;
Pre Steps 执行清理脚本;
Post Steps 启动新 Jar;
访问接口验证部署结果。