作者:没有四次元口袋的蓝胖
日期:2026-09-15
标签:CI/CD, GitLab, Jenkins, DevOps
写在前面
这是一篇 CI/CD 自动化部署实战记录。从 GitLab 代码托管、分支规范制定,到 Jenkins 自动化构建部署,完整记录了团队从零搭建 CI/CD 流水线的全过程。
一、项目背景
团队之前的部署流程:每次代码提交后,需要 手动登录服务器 → mvn clean package → 上传 jar/war 包 → 重启 Tomcat,流程繁琐且容易出错。
目标:引入 GitLab + Jenkins,实现"代码推送即自动构建,构建完成即自动部署"。
二、GitLab 分支规范与代码管理
2.1 Git Flow 分支策略
| 分支 | 用途 | 保护策略 |
|---|---|---|
master | 生产环境代码 | Protected,禁止直接 push,必须通过 MR |
develop | 开发测试环境 | Protected,禁止直接 push,必须通过 MR |
feature/* | 功能开发分支 | 从 develop 拉出,开发完提 MR 回 develop |
hotfix/* | 紧急修复 | 从 master 拉出,修复完同时合并到 master 和 develop |
2.2 分支保护配置
GitLab → Settings → Repository → Protected branches:
- master、develop 均设置为 Protected
- Allowed to merge:Maintainers
- Allowed to push and merge:No one(禁止直接 push)
- Require approval:至少 1 人审核
这样所有代码合并必须走 MR 流程,从制度上保障代码质量。
2.3 🎯 面试高频问题
Q:MR(Merge Request)和 PR(Pull Request)有什么区别?
本质一样,只是叫法不同。MR 是 GitLab 的叫法,PR 是 GitHub 的叫法。都是"我改了代码,请审核后再合并"。
Q:为什么不直接 push 到 master?
没有审核流程 = 任何人都能把未测试的代码推上线。MR 机制强制 Code Review + 构建验证,是生产环境的基本保障。
三、Jenkins 环境搭建
3.1 安装 Jenkins
Jenkins 基于 Java,需要先装好 JDK。这里选择用 Tomcat 部署 WAR 包的方式:
# 1. 下载 Jenkins WAR 包
wget https://mirrors.tuna.tsinghua.edu.cn/jenkins/war-stable/latest/jenkins.war
# 2. 放到 Tomcat 的 webapps 目录下
cp jenkins.war /opt/tomcat/webapps/
# 3. 启动 Tomcat
/opt/tomcat/bin/startup.sh
# 4. 访问 http://服务器IP:8080/jenkins
# 首次访问需要输入初始密码
cat /root/.jenkins/secrets/initialAdminPassword
3.2 插件安装
首次进入 Jenkins 选择"安装推荐插件",之后手动补充关键插件:
| 插件 | 作用 |
|---|---|
| Git Plugin | 从 GitLab 拉取代码 |
| Maven Integration | 支持 Maven 项目构建 |
| Publish Over SSH | 将构建产物传输到远程服务器 |
| Email Extension | 构建结果邮件通知 |
| GitLab Plugin | 与 GitLab 集成(Webhook + 构建状态回传) |
3.3 全局工具配置
Jenkins → 系统管理 → 全局工具配置:
- JDK:指定 JAVA_HOME 路径
- Maven:指定 Maven 安装目录
- Git:指定 git 可执行文件路径
3.4 凭据管理
Jenkins → Credentials → 添加凭据,配置 GitLab 的访问凭证:
- 类型选择:SSH Username with private key(推荐)或 Username with password
- Scope:Global(全局可用)
💡 最佳实践:所有密码、Token 都通过 Jenkins Credentials 管理,不要在脚本中硬编码!
3.5 🎯 常见坑点
坑1:Jenkins 的 SSH 密钥权限问题
Jenkins 以 jenkins 用户运行,生成 SSH 密钥后要确保 .ssh 目录权限是 700,密钥文件权限是 600,否则 SSH 连接会被拒绝。
坑2:Maven 构建时内存不足
默认 Jenkins 的 JVM 内存可能不够,大项目构建时 OOM。解决方法:修改 jenkins.xml 或启动脚本中的 -Xmx 参数。
四、Freestyle 项目配置(核心)
4.1 创建项目
Jenkins → 新建任务 → 输入项目名称 → 选择"构建一个自由风格的软件项目"。
4.2 第一阶段:源码管理
- Source Code Management:选择 Git
- Repository URL:填写 GitLab 仓库 SSH 地址(如
[email protected]:group/project.git) - Credentials:选择之前配置的 GitLab 凭据
- Branch Specifier:
*/develop(根据项目环境选择分支)
4.3 第二阶段:构建触发器
选择 Build when a change is pushed to GitLab:
- Jenkins 会生成一个 Webhook URL,格式类似:
http://jenkins-server:8080/project/项目名称 - 将此 URL 填入 GitLab → Settings → Webhooks
- 勾选 Push events
- 点击 Add webhook
Webhook 工作原理:
git push → GitLab 检测到 push → 向 Jenkins 发 HTTP POST → Jenkins 触发构建
⚠️ 注意:GitLab 服务器必须能访问到 Jenkins 的地址。如果是内网环境,需要确保网络互通。
4.4 第三阶段:构建步骤(Build)
选择 Execute shell,填入构建脚本:
#!/bin/bash
echo "===== 开始构建 ====="
# 设置环境变量
export JAVA_HOME=/usr/local/java/jdk1.8
export MAVEN_HOME=/usr/local/maven
export PATH=$MAVEN_HOME/bin:$JAVA_HOME/bin:$PATH
# Maven 编译打包(跳过测试)
mvn clean package -DskipTests
# 检查打包结果
if [ $? -ne 0 ]; then
echo "构建失败!"
exit 1
fi
echo "===== 构建成功 ====="
ls -lh target/*.jar
4.5 第四阶段:部署(Publish Over SSH)
Publish Over SSH 插件配置:
Jenkins → 系统管理 → 系统配置 → Publish over SSH:
- Path to key:SSH 私钥路径
- SSH Servers:添加目标服务器信息
- Name:自定义标识
- Hostname:目标服务器 IP
- Username:登录用户名
- Remote Directory:远程基础路径
每个项目的 Post-build Action 配置:
- Source files:
target/*.jar(要传输的文件) - Remove prefix:
target(去掉路径前缀) - Remote directory:
/opt/app/project-name(部署目录) - Exec command(传输后执行的远程脚本):
#!/bin/bash
# 进入部署目录
cd /opt/app/project-name
# 备份旧版本
cp app.jar app.jar.bak.$(date +%Y%m%d%H%M)
# 停止旧进程
pid=$(ps -ef | grep app.jar | grep -v grep | awk '{print $2}')
if [ -n "$pid" ]; then
kill -9 $pid
echo "已停止旧进程: $pid"
fi
# 启动新应用(nohup 后台运行)
nohup java -jar app.jar --spring.profiles.active=prod > /dev/null 2>&1 &
echo "应用启动成功!"
4.6 🎯 面试高频问题
Q:构建和部署是怎么分开的?
构建在 Jenkins 所在的服务器执行 mvn clean package,产出 jar/war 文件。部署通过 Publish Over SSH 插件,将构建产物传输到目标服务器,再通过远程 Shell 脚本重启应用。两步分离的好处:构建服务器不需要和应用服务器是同一台,职责清晰。
Q:部署脚本里为什么要备份旧版本?
方便回滚。如果新版本上线后发现问题,可以快速把 .bak 文件改名恢复,不用重新构建。
五、多环境部署策略
| 环境 | 分支 | 触发方式 | 说明 |
|---|---|---|---|
| 开发环境 | develop | 自动触发(git push 即构建部署) | 快速迭代,方便开发自测 |
| 生产环境 | master | 手动触发(Jenkins 点击"立即构建") | 安全可控,防止未经审核的代码上线 |
为什么生产环境要手动触发?
- 防止误操作把未审核的代码推上线
- 生产发布需要运维或负责人确认发布时间窗口
- 可以配合上线前的检查清单(数据库变更、配置变更等)
六、构建通知与质量门禁
6.1 邮件通知
Jenkins → 项目配置 → Post-build Actions → E-mail Notification:
- 勾选 Send separate e-mails to individuals who broke the build
- 构建失败时自动通知相关开发者
6.2 GitLab 构建状态集成
安装 GitLab Plugin 后:
- MR 页面会显示 Jenkins 构建状态(✅ Success / ❌ Failure)
- 构建不通过 → 禁止合并,从流程上保障代码质量
6.3 🎯 常见坑点
坑1:邮件通知发不出去
Jenkins 默认邮件配置需要设置 SMTP 服务器。如果用 QQ/163 邮箱,需要在邮箱设置中开启 SMTP 服务并获取授权码,不是登录密码。
坑2:Webhook 配置了但不触发构建
排查步骤:
- 检查 Webhook URL 是否正确(注意端口和项目名称)
- 检查 Jenkins 项目是否勾选了 “Build when a change is pushed to GitLab”
- 在 GitLab Webhook 页面点 “Test” → “Push events”,查看返回状态码
- 检查网络:GitLab 服务器能否访问 Jenkins 地址
七、整体部署架构图
┌──────────┐ git push ┌──────────┐ Webhook ┌──────────┐
│ Developer │ ───────────────→ │ GitLab │ ────────────→ │ Jenkins │
│ (本地) │ │ (代码仓库) │ │ (构建服务器)│
└──────────┘ └──────────┘ └─────┬────┘
│
SSH 传输 jar/war
│
▼
┌──────────┐
│ App Server│
│ (Tomcat) │
└──────────┘
│
用户访问
▼
┌──────────┐
│ Browser │
└──────────┘
八、写在最后
学习建议
- Shell 脚本是运维的基本功,
awk、sed、grep、find必须熟练,部署脚本离不开它们 - Jenkins Freestyle 适合入门,但工作中更推荐 Pipeline(Jenkinsfile),支持代码化配置、并行执行、阶段控制,建议后续学习
- CI/CD 不仅仅是工具配置,更重要的是理解流程设计——分支策略、环境隔离、安全门禁、回滚机制
- 实操建议:自己搭一套 GitLab + Jenkins 环境,从 push 到自动部署跑通全流程,面试时才能讲得清楚
🎯 面试高频三连问
Q1:描述一下你做的 CI/CD 流程?
开发在本地完成功能后,push 到 feature 分支 → 提 MR 到 develop → Jenkins 通过 Webhook 自动触发构建 → 构建成功后通过 Publish Over SSH 部署到开发环境 → 测试通过后提 MR 到 master → 运维手动触发构建部署到生产环境。
Q2:Jenkins Freestyle 和 Pipeline 有什么区别?
Freestyle 通过界面配置,适合简单场景;Pipeline 通过 Jenkinsfile 代码化配置,支持 stage、parallel、agent 等高级语法,适合复杂流程,且可以纳入 Git 版本管理。
Q3:如果 Jenkins 构建的包在目标服务器跑不起来,你怎么排查?
- 检查 JDK 版本是否一致;2. 检查环境变量是否齐全;3. 查看应用日志定位启动报错;4. 检查配置文件(application.yml)的环境是否匹配;5. 对比本地能跑的环境和服务器环境的差异。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/2301_78547133/article/details/165573959



