本文记录一次完整的 Jenkins CI/CD 搭建过程,从 Jenkins Docker 安装、插件安装、JDK/Maven/Docker 配置,到 Gitee WebHook、Spring Boot 打包、SSH 部署、systemd 管理,最终实现:
本地 git push → Gitee → Jenkins 自动构建 → 自动部署 Spring Boot → 浏览器访问最新版本。
最终实现效果
最终实现下面这条完整链路:
本地开发电脑
│
│ git push
▼
Gitee
│
│ WebHook
▼
Jenkins
│
├── 拉取代码
├── Maven clean package
├── 生成 Spring Boot JAR
├── SCP 上传 JAR
└── SSH 执行 systemctl restart
│
▼
Ubuntu 宿主机
│
▼
Spring Boot
:8081
│
▼
浏览器访问最终以后开发只需要:
git add .
git commit -m "xxx"
git pushJenkins 就会自动完成部署。
环境说明
本次环境:
操作系统:Ubuntu 26.04 LTS
Jenkins:
Docker 部署
镜像:
jenkins/jenkins:lts-jdk21
JDK:
21
Maven:
3.9.10
Spring Boot:测试开放端口
8081
Jenkins:
8080服务器 IP:
43.142.88.165所以:
Jenkins:
http://43.142.88.165:8080
Spring Boot:
http://43.142.88.165:8081本次采用docker部署,docker和docker compose安装方式本次不在概述。
一、安装&启动jenkins,获取初始密码
创建 Jenkins 工作目录:
mkdir -p /opt/jenkins
cd /opt/jenkins
创建 Jenkins 数据目录:
mkdir -p /opt/jenkins/jenkins_home在jenkins目录创建 Jenkins Docker Compose 需在/opt目录上传apache-maven-3.9.10
cat > docker-compose.yml <<'EOF'
services:
jenkins:
image: jenkins/jenkins:lts-jdk21
container_name: jenkins
restart: unless-stopped
user: root
ports:
- "8080:8080"
- "50000:50000"
volumes:
- ./jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
- /usr/bin/docker:/usr/bin/docker:ro
- /opt/apache-maven-3.9.10:/opt/apache-maven-3.9.10:ro
environment:
JAVA_OPTS: >-
-Dhudson.model.DownloadService.noSignatureCheck=true
EOF运行docker compose up -d 启动Jenkins容器 会一次性拉取jdk21和jenkins两个容器
docker ps
应该看到:
查看日志:docker logs -f jenkins
正常启动后Ctrl+C退出日志
执行命令 : docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
获取初始密码
浏览器打开:
http://43.142.88.165:8080输入初始密码。
二、安装jenkins插件&插件安装建议
进入jenkins初始化页面
选择:Install suggested plugins
如果网络原因导致插件安装失败,可以先进入Jenkins
之后进入: Manage Jenkins -> Plugins -> Available plugins
本次测试项目最终需要的主要插件
Git
Git client
Pipeline
Pipeline Stage View
Credentials
Credentials Binding
Docker Pipeline
Docker Commons
Pipeline Maven Integration
JUnit
Config File Provider
SSH Agent
Gitee其中 Gitee非常重要 它负责后面的: Gitee WebHook -> Jenkins 自动构建
为了避免一次安装太多导致排查困难,可以按照功能来安装。
第一组: Git、GitClient 。 作用: Jenkins -> 拉取 Gitee 代码
第二组: Pipeline、Pipeline Stage View。 作用: 让Jenkins支持pipeline{ .... } 以及之后在控制台看到stage1 stage2
第三组: Pipeline Maven Integration 。 作用: 用于Jenkins Pipeline调用Maven
第四组: Credentials、Credentials Binding、SSH Agent 。 作用: 后续SSH 部署会使用
第五组: Docker Pipeline、Docker Commons。 作用: 之后如果继续扩展Docker部署会用到
第六组: Gitee 作用: 用于Gitee WebHook
每一组安装完成之后点击下方复选框重启一次jenkins。
三、配置Jenkins JDK
进入 Manage Jenkins -> Tools
配置JDK
Name: jdk21
JAVA_HOME : /opt/java/openjdk
这里注意:因为jdk是在docker compose文件中一起被拉取的,因此宿主机并没有这个jdk,它在容器内
可以执行命令: docker exec jenkins printenv JAVA_HOME 来查看位置
四、配置Maven
继续在: Manage Jenkins -> Tools 配置Maven
Name: Maven-3.9.10
Maven Home: /opt/apache-maven-3.9.10
完成上述四步之后进入jenkins容器后验证 docker exec -it jenkins bash
检查Java: java -version
检查Maven: mvn -version
检查Git: git --version
检查Docker: docker --version
全部正常以后执行 exit 退出容器
五、创建SpringBoot项目
本次用来测试的项目名称是 jenkins-demo
SpringBoot端口号设置为:
server:
port: 8081
测试接口: Get /hello
例如 : http://43.142.88.165:8081/hello
到这里后,先不要让 Jenkins 管理 Spring Boot 进程
这次本次最重要的经验之一。
本次测试 最开始采用的架构如下图
这种方式看起来可以运行,但是 Jenkins Pipeline 结束后,后台进程可能被 Jenkins 清理。
所以最终改成:
这是更加合理的架构。
之后创建SpringBoot生产目录
宿主机:
mkdir -p /opt/apps/jenkins-demo最终:
/opt/apps/jenkins-demo/
├── jenkins-demo.jar
└── app.log六、创建 systemd 服务
执行
cat > /etc/systemd/system/jenkins-demo.service <<'EOF'
[Unit]
Description=Jenkins Demo Spring Boot Application
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/apps/jenkins-demo
ExecStart=/usr/bin/java -jar /opt/apps/jenkins-demo/jenkins-demo.jar
Restart=always
RestartSec=5
StandardOutput=append:/opt/apps/jenkins-demo/app.log
StandardError=append:/opt/apps/jenkins-demo/app.log
[Install]
WantedBy=multi-user.target
EOF
执行完上面的命令后,再执行
systemctl daemon-reload解释这个jenkins-demo.service含义:
cat > xxx <<'EOF' 含义:把 EOF 和 EOF 中间的文本,直接写入到 /etc/systemd/system/jenkins-demo.service 文件 'EOF' 加单引号:里面内容原样写入,不会解析变量。一次性生成服务配置文件,不用 vim 手动编辑。
二、分块解释 service 文件(systemd 的配置,分 3 大块:[Unit] / [Service] / [Install])
① [Unit] 区块:服务的基本描述、启动依赖
[Unit]
Description=Jenkins Demo Spring Boot Application
After=network.targetDescription:服务描述,systemctl status jenkins-demo时展示,方便识别这是哪个应用After=network.target:等系统网络就绪之后,再启动这个 SpringBoot 程序
作用:防止网络还没初始化完成,SpringBoot 就启动,导致端口 / 网络访问异常 ⚠️ After 只是先后顺序,不是强依赖(网络挂了它照样尝试启动)
② [Service] 区块【核心!】定义程序怎么运行
[Service]
Type=simple
User=root
WorkingDirectory=/opt/apps/jenkins-demo
ExecStart=/usr/bin/java -jar /opt/apps/jenkins-demo/jenkins-demo.jar
Restart=always
RestartSec=5
StandardOutput=append:/opt/apps/jenkins-demo/app.log
StandardError=append:/opt/apps/jenkins-demo/app.logType=simple:最常用类型。ExecStart执行的命令就是主进程,systemd 会监控这个 java 进程。User=root:使用 root 用户运行这个程序(生产环境不推荐 root,测试演示没问题)WorkingDirectory:程序工作目录,相当于cd /opt/apps/jenkins-demo之后再执行 jar,读取相对路径资源、日志输出基准目录。ExecStart:启动命令,等价于java -jar jenkins-demo.jar,systemd 通过这条命令拉起 SpringBoot。
✅ 重点:这个 java 进程归属 systemd,不再属于 Jenkins 的 shell 会话!也就是解决了之前的痛点:Jenkins 流水线跑完,SpringBoot 不会被杀。
Restart=always:只要进程退出,就自动重启 不管是代码抛异常崩溃、OOM、手动 kill,只要进程没了,systemd 自动拉起。RestartSec=5:进程挂掉之后,等待 5 秒再重启,防止无限快速重启把服务器打崩。StandardOutput/StandardError把程序标准输出 + 错误输出,追加写入app.log。等价于旧方案里
nohup ... > app.log 2>&1,但是由 systemd 托管日志。append代表追加,不会覆盖旧日志。
③ [Install] 区块:定义开机自启规则
[Install]
WantedBy=multi-user.targetmulti-user.target:Linux 多用户模式(正常服务器开机进入的模式)执行
systemctl enable jenkins-demo的时候生效:服务器开机,自动启动这个 SpringBoot 服务
三、后面这条命令
systemctl daemon-reload含义:重新加载 systemd 的配置 当你新增 / 修改 /etc/systemd/system/ 下面的 service 文件,必须执行这条! systemd 不会自动扫描文件变更,不执行这条,systemd 识别不到你新建的 jenkins-demo 服务。
六、启动SpringBoot项目
第一次部署 JAR:
cp /opt/jenkins/jenkins_home/workspace/jenkins-demo/target/*.jar \
/opt/apps/jenkins-demo/jenkins-demo.jar启动:
systemctl start jenkins-demo设置开机启动:
systemctl enable jenkins-demo查看:
systemctl status jenkins-demo这里注意,在最初的docker compose文件中
ports:
- "8080:8080"
- "50000:50000"
除了这两个jenkins本身需要的,端口映射不要设置其他和应用实例冲突的端口,或者干脆就不要设置。
比如 -"8081:8081"
我个人想法是我测试的boot实例设置的是8081端口,但是如果写在ports里。那么docker就会占用这个端口,导致实例启动失败(本次踩坑之一)。
之后游览器访问
http://43.142.88.165:8081/hello
如果可以看到 Spring Boot 返回内容:
Hello Jenkins
说明 Spring Boot 部署成功。
六、解决 Jenkins Docker → 宿主机通信
因为 Jenkins 在 Docker 中:
Jenkins Container(容器)
而 systemd 在:
Ubuntu Host
所以需要让 Jenkins 可以 SSH 到宿主机。
首先获取 Jenkins Docker 网络网关:
docker inspect -f '{{range .NetworkSettings.Networks}}{{.Gateway}}{{end}}' jenkins
本次得到:
172.18.0.1
所以:
Jenkins Container
↓
172.18.0.1
↓
Ubuntu Host确认宿主机SSH
执行 ssh -V V要大写
检查 22 端口: ss -lntp | grep ':22'
应该看到:
0.0.0.0:22
[::]:22创建 Jenkins 专用 SSH 密钥
在 Ubuntu 宿主机执行:
ssh-keygen -t ed25519 \
-f /root/.ssh/jenkins_deploy \
-C "jenkins-deploy"
密码可以留空。
检查:
ls -l /root/.ssh/jenkins_deploy*
应该有:
/root/.ssh/jenkins_deploy
/root/.ssh/jenkins_deploy.pub
配置 SSH 公钥
执行:
cat /root/.ssh/jenkins_deploy.pub >> /root/.ssh/authorized_keys
设置权限:
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys
测试 SSH
宿主机执行:
ssh -i /root/.ssh/jenkins_deploy [email protected]
能够登录:
root@VM-0-6-ubuntu:~#
说明密钥正常。
把私钥复制到 Jenkins 容器
宿主机执行:
docker cp /root/.ssh/jenkins_deploy \
jenkins:/tmp/jenkins_deploy
进入 Jenkins:
docker exec -it jenkins bash
执行:
mkdir -p /root/.ssh
mv /tmp/jenkins_deploy \
/root/.ssh/jenkins_deploy
chmod 600 /root/.ssh/jenkins_deploy
测试:
ssh -i /root/.ssh/jenkins_deploy [email protected]
如果能够进入宿主机:
root@VM-0-6-ubuntu:~#
说明:
Jenkins Container
↓ SSH
Ubuntu Host
已经打通。Docker 路径差异(踩坑之一)
宿主机:
/opt/jenkins/jenkins_home
Jenkins 容器:
/var/jenkins_home
因为 Docker Compose 有:
- ./jenkins_home:/var/jenkins_home
所以 Jenkins Pipeline 里面必须使用:
/var/jenkins_home
而不能使用:
/opt/jenkins/jenkins_home
例如:
ls -lh /var/jenkins_home/workspace/jenkins-demo/target/*.jar
可以找到 JAR。
测试SCP
在 Jenkins 容器里:
scp -i /root/.ssh/jenkins_deploy \
/var/jenkins_home/workspace/jenkins-demo/target/*.jar \
[email protected]:/opt/apps/jenkins-demo/jenkins-demo.jar
如果成功:
100%
说明 JAR 已经可以从 Jenkins 上传到宿主机。
测试 systemd
继续执行:
ssh -i /root/.ssh/jenkins_deploy \
[email protected] \
"systemctl restart jenkins-demo"
检查:
ssh -i /root/.ssh/jenkins_deploy \
[email protected] \
"systemctl is-active jenkins-demo"
返回:
active
说明:
Jenkins
↓
SSH
↓
systemd
↓
Spring Boot
已经打通。七、创建 Jenkins Pipeline
项目根目录创建:
Jenkinsfile
pipeline {
agent any
tools {
maven 'Maven-3.9.10'
jdk 'jdk21'
}
stages {
stage('1. 拉取Gitee代码') {
steps {
checkout scm
echo "✅ Gitee代码拉取完成"
}
}
stage('2. Maven编译测试打包') {
steps {
sh 'mvn clean package'
echo "📦 Maven构建完成"
sh '''
echo "========== Jar包 =========="
ls -lh target/*.jar
'''
}
}
stage('3. 部署JAR到服务器') {
steps {
echo "📦 正在部署新的SpringBoot JAR"
sh '''
scp -i /root/.ssh/jenkins_deploy \
target/*.jar \
[email protected]:/opt/apps/jenkins-demo/jenkins-demo.jar
'''
echo "✅ JAR部署完成"
}
}
stage('4. 重启SpringBoot服务') {
steps {
echo "🚀 正在重启SpringBoot服务"
sh '''
ssh -i /root/.ssh/jenkins_deploy \
[email protected] \
"systemctl restart jenkins-demo"
'''
echo "✅ SpringBoot重启完成"
}
}
stage('5. 验证SpringBoot服务') {
steps {
sh '''
echo "🔍 等待SpringBoot启动..."
sleep 5
echo "========== 服务状态 =========="
ssh -i /root/.ssh/jenkins_deploy \
[email protected] \
"systemctl is-active jenkins-demo"
echo "========== 8081端口 =========="
ssh -i /root/.ssh/jenkins_deploy \
[email protected] \
"ss -lntp | grep 8081"
echo "========== 接口测试 =========="
curl -f http://172.18.0.1:8081/hello
echo ""
echo "✅ SpringBoot部署验证成功"
'''
}
}
}
post {
success {
echo '''
========================================
🎉 Jenkins构建成功 🎉
SpringBoot部署成功
========================================
'''
}
failure {
echo '''
========================================
❌ Jenkins构建失败 ❌
SpringBoot部署失败
========================================
'''
}
always {
echo "📝 Pipeline执行结束"
}
}
}
第一次手动 Build
先不要急着配置 WebHook。
点击:
Build Now
确认:
1. 拉取Gitee代码
2. Maven编译测试打包
3. 部署JAR到服务器
4. 重启SpringBoot服务
5. 验证SpringBoot服务
全部成功。
如果全部成功:
Jenkins → Spring Boot
就已经打通。八、配置 Gitee WebHook
进入 Jenkins:
jenkins-demo
↓
Configure
↓
Triggers
勾选:
Gitee webhook 触发构建
Jenkins 会显示:
http://43.142.88.165:8080/gitee-project/jenkins-demo
保存这个链接。
进入 Gitee 仓库:
管理
↓
WebHooks
↓
添加 WebHook
URL:
http://43.142.88.165:8080/gitee-project/jenkins-demo
事件:
Push
配置 WebHook 密码
Jenkins:
jenkins-demo
↓
Configure
↓
Triggers
↓
Gitee WebHook 密码
设置一个随机值,例如:
JenkinsGitee-2026-8fK3mP92
保存。
然后 Gitee:
WebHook 密码/签名密钥
填写完全相同的值:
JenkinsGitee-2026-8fK3mP92
保存。
解决 WebHook 403
如果 Gitee 测试出现:
HTTP ERROR 403
anonymous is missing the Job/Build permission
不要直接把 Jenkins 设置成:
Anyone can do anything
这种方式风险太大。
正确方向是使用 Gitee WebHook 的认证机制。
本次通过:
Jenkins Gitee WebHook 密码
Gitee WebHook 密码/签名密钥
解决了 WebHook 请求认证问题。
验证 WebHook
Gitee WebHook 最后一次请求应该看到:
Response:
200
例如:
POST
http://43.142.88.165:8080/gitee-project/jenkins-demo
事件:
Push
Response:
200
说明:
Gitee
↓
Jenkins
已经正常通信。
最终测试
不要再点击 Gitee 测试。
直接修改 Spring Boot:
例如:
Hello Jenkins CI/CD
改成:
Hello Jenkins CI/CD V2
然后本地:
git add .
git commit -m "test: gitee webhook auto deploy"
git push
观察 Jenkins。
应该自动出现新的 Build。
然后 Jenkins 自动执行:
拉取代码
↓
Maven
↓
生成 JAR
↓
SCP
↓
SSH
↓
systemctl restart
↓
验证
最后浏览器访问:
http://43.142.88.165:8081/hello
看到:
Hello Jenkins CI/CD V2
说明整个 CI/CD 流程真正完成。最终架构总结
最终服务器上的结构:
/opt/
├── jenkins/
│ └── jenkins_home/
│
├── apache-maven-3.9.10/
│
└── apps/
└── jenkins-demo/
├── jenkins-demo.jar
└── app.log
服务:
Jenkins
Docker
:8080
Spring Boot
systemd
:8081
代码:
Gitee
↓
Jenkins
部署:
Jenkins
↓ SCP
Ubuntu
↓ systemctl
Spring Boot九、总结
1. Jenkins 不应该负责长期运行 Spring Boot
不要:
Jenkins
↓
nohup java -jar
应该:
Jenkins
↓
部署 JAR
systemd
↓
管理 Spring Boot2. Docker 容器路径和宿主机路径不一样
宿主机:
/opt/jenkins/jenkins_home
容器:
/var/jenkins_home
Pipeline 中必须使用容器里的路径。3. Jenkins 8080 和 Spring Boot 8081 要分开
Jenkins:
8080
Spring Boot:
8081
Jenkins Docker 不要再映射:
8081:8081
否则会造成端口冲突。4. WebHook 403 不一定是网络问题
如果 Gitee 显示:
403 anonymous is missing the Job/Build permission
说明:
Gitee → Jenkins
其实已经访问成功。
真正的问题是 Jenkins 权限/认证。5. CI/CD 最好一步一步验证
不要一开始就:
Gitee
↓
WebHook
↓
Jenkins
↓
Maven
↓
Docker
↓
Spring Boot
全部一起搞。
正确排查顺序:
① Jenkins 能启动
↓
② Jenkins 能拉代码
↓
③ Maven 能打包
↓
④ Spring Boot 能手动启动
↓
⑤ Jenkins 能上传 JAR
↓
⑥ Jenkins 能 SSH
↓
⑦ systemd 能重启
↓
⑧ Jenkins Pipeline 全流程成功
↓
⑨ Gitee WebHook
↓
⑩ git push 自动部署
这样每一步出现问题都比较容易定位。十、最终效果
开发人员不需要再手动登录服务器:
不用手动上传 JAR
不用手动 kill Java
不用手动启动 Spring Boot
不用手动 Build Jenkins
不用手动刷新部署最终实现:
一次 git push,自动完成整个 Spring Boot 部署流程。
十一、日后升级准备
当前版本已经完成基础 CI/CD。
后续可以继续升级:
V1
Gitee
↓
Jenkins
↓
Spring Boot
升级到:
V2
Gitee
↓
Jenkins
↓
Maven
↓
Docker Image
↓
Docker Compose
↓
Spring Boot
再进一步:
V3
Gitee
↓
Jenkins
↓
Maven
↓
Docker Image
↓
私有镜像仓库
↓
生产服务器
↓
Docker Compose
还可以加入:
Git 分支策略
测试环境
生产环境
审批
回滚
版本号
Docker 镜像版本
日志
健康检查
Nginx
HTTPS
这样就可以逐步从现在的个人项目 CI/CD,升级成更加完整的企业级部署流程。