🔥 系列专栏:GitHub Webhook 深度实战 前文回顾: 系列第一篇讲解 GitHub Webhook 底层原理、密钥校验、事件调试;
第二篇完成 Webhook 对接 Jenkins 流水线,实现代码 Push 自动拉取、单元测试、打包构建,完整走完 CI 持续集成流程。
本篇作为进阶 CD 持续交付实战,基于上一篇现成 Pipeline 改造,新增远程服务器自动部署能力,打通「提交代码→自动拉取→单元测试→构建产物→远程发布上线」完整自动化链路,一套脚本覆盖 CI+CD,适配 Java SpringBoot 项目,内网 / 公网服务器均可落地,附带完整排坑、服务器免密配置、生产环境安全规范。
一、前置准备(承接第二篇环境,新增 CD 依赖)
1.1 已有环境(沿用第二篇)
- Jenkins 2.300+ LTS 稳定版,已安装 Git、Maven、GitHub Integration、Pipeline、JUnit 插件
- GitHub 仓库配置 Webhook,可正常触发 Jenkins 流水线 CI 流程
- 项目根目录存在基础 Jenkinsfile,能完成代码拉取、测试、打包、产物归档
1.2 CD 阶段新增必备配置
1.2.1 Jenkins 安装远程发布核心插件
进入【管理 Jenkins - 插件管理 - 可选插件】搜索安装:
- SSH Agents Plugin:支持 ssh 远程连接服务器执行 shell 脚本
- Publish Over SSH:业界通用远程文件传输、远程执行命令插件(本篇主推) 安装完成重启 Jenkins 生效。
1.2.2 配置服务器 SSH 凭证(免密登录核心)
两种方案,推荐方案 1(密钥免密,生产安全)
方案 1:SSH 公私钥免密(推荐)
- Jenkins 服务器生成密钥对:
ssh-keygen -t rsa,一路回车不设置密码 - 将公钥
id_rsa.pub内容复制到目标部署服务器~/.ssh/authorized_keys - Jenkins 全局配置 SSH 服务: 管理 Jenkins → 系统 → Publish over SSH → SSH Servers → Add SSH Server
- Name:自定义服务标识(prod-server)
- Hostname:部署服务器公网 IP / 内网 IP
- Username:服务器登录账号(root / 普通运维账号)
- Remote Directory:远程存放 jar 包目录
/data/app/demo - Advanced → 勾选 Use Private Key,粘贴 Jenkins 私钥完整内容保存
方案 2:账号密码登录(仅测试环境使用,生产禁用)
直接填写服务器账号密码,安全性差,仅本地演示使用。
1.2.3 目标服务器环境提前就绪
- 安装对应 JDK 版本(和项目编译 JDK 版本保持一致)
- 创建应用目录:
mkdir -p /data/app/demo /data/app/demo/logs - 提前编写启停脚本
start.sh / stop.sh,用于远程一键重启服务/data/app/demo/stop.sh
#!/bin/bash pid=`ps -ef | grep demo.jar | grep -v grep | awk '{print $2}'` if [ -n "$pid" ];then kill -9 $pid echo "旧进程已停止 pid:$pid" fi/data/app/demo/start.sh
#!/bin/bash nohup java -jar demo.jar --spring.profiles.active=prod > logs/run.log 2>&1 & echo "服务启动完成" sleep 2 pid=`ps -ef | grep demo.jar | grep -v grep | awk '{print $2}'` echo "运行进程pid:$pid"赋予脚本执行权限:chmod +x start.sh stop.sh
二、改造完整版 Jenkinsfile(CI+CD 一体化)
基于第二篇 CI 脚本扩展新增6. 远程传输产物、7. 服务器自动部署两大阶段,完整脚本可直接替换仓库根目录 Jenkinsfile,适配 Maven SpringBoot 项目。
pipeline { agent any environment { // 和Jenkins全局工具配置Maven名称保持一致 MAVEN_HOME = tool 'Maven3' PROJECT_VERSION = '1.0.0' // SSH服务名称,和Publish over SSH配置名称统一 SSH_SERVER = "prod-server" // 远程服务器应用目录 REMOTE_APP_PATH = "/data/app/demo" // 本地产物路径 LOCAL_JAR = "target/*.jar" } stages { stage('1. 环境初始化') { steps { echo "========== CI+CD流水线启动,初始化环境 ==========" sh 'mvn -v' sh 'git --version' } } stage('2. 拉取GitHub最新代码') { steps { echo "清理工作空间,拉取远程代码" cleanWs() sh 'git pull origin main' } } stage('3. 单元测试校验(质量卡点)') { steps { echo "执行单元测试,测试失败直接阻断流水线" sh "${MAVEN_HOME}/bin/mvn clean test -Dmaven.test.failure.ignore=false" } post { always { junit allowEmptyResults: true, testResults: '**/target/surefire-reports/*.xml' } } } stage('4. Maven打包构建产物') { steps { echo "编译打包,跳过测试(已单独执行测试阶段)" sh "${MAVEN_HOME}/bin/mvn clean package -DskipTests=true" } } stage('5. 本地归档构建产物') { steps { echo "归档Jar包,Jenkins后台留存历史版本" archiveArtifacts artifacts: 'target/*.jar', fingerprint: true, onlySuccessful: true } } // 新增CD阶段:上传Jar到远程服务器 stage('6. SSH传输产物至部署服务器') { steps { echo "开始将构建好的Jar包上传至生产服务器" sshPublisher(publishers: [ sshPublisherDesc( configName: env.SSH_SERVER, transfers: [ sshTransfer( sourceFiles: env.LOCAL_JAR, remoteDirectory: env.REMOTE_APP_PATH, postTransfers: [ postTransferStep( // 上传完成后先执行停止脚本 transfers: [sshCommand(command: "cd ${REMOTE_APP_PATH} && sh stop.sh")] ) ] ) ] ) ]) } } // 新增CD阶段:远程启动服务,完成上线 stage('7. 远程服务器自动部署上线') { steps { echo "执行启动脚本,重启后端服务,完成CD发布" sshPublisher(publishers: [ sshPublisherDesc( configName: env.SSH_SERVER, transfers: [ sshTransfer( sourceFiles: "", remoteDirectory: env.REMOTE_APP_PATH, postTransfers: [ postTransferStep( transfers: [sshCommand(command: "cd ${REMOTE_APP_PATH} && sh start.sh")] ) ] ) ] ) ]) } } } post { success { echo "✅ CI+CD全流程完成:代码拉取→测试→打包→上传→自动部署上线成功" } failure { echo "❌ 流水线执行失败,终止发布,检查对应阶段日志排查问题" } always { // 可选:对接钉钉/企业微信机器人推送构建结果 } } }脚本核心 CD 逻辑拆解
- sshPublisher:调用全局配置的 SSH 服务器,自动建立免密连接
- sourceFiles:指定本地 Jenkins 工作空间打包生成的 jar 文件
- remoteDirectory:远程服务器存放包的应用目录
- postTransfers:文件上传完成后执行远程 shell 命令,先停旧服务,再启动新版本
- 流水线分层隔离:CI 流程(测试、打包)和 CD 流程(传输、部署)完全解耦,测试失败直接阻断发布,避免故障版本上线
三、Jenkins 流水线任务配套修改
第二篇已创建好 Pipeline 任务,仅需两处微小更新:
- 流水线脚本路径不变,依旧读取仓库根目录
Jenkinsfile,提交新脚本后自动生效 - 确认【构建触发器】依旧勾选
GitHub hook trigger for GITScm polling,保证 Push 自动触发 - 可选配置:构建超时时间、并发构建禁止(避免多人同时推送代码重复部署) 流水线配置页面 → 【选项】→ 勾选禁止并发构建,防止多任务同时覆盖服务器 Jar 包
四、GitHub Webhook 无需改动,复用原有配置
Payload URL、Content-Type、触发事件、Secret 密钥全部沿用第二篇配置,无需修改。 触发链路完整闭环: 本地 Git Push 代码 → GitHub 推送 Webhook 请求 → Jenkins 接收事件自动启动 Pipeline 流水线执行链路: 环境初始化 → 拉取代码 → 单元测试校验 → 打包 Jar → 本地归档 → SSH 上传至服务器 → 停止旧服务 → 启动新版本 → 发布完成
五、全流程完整验证测试
- 本地修改业务代码,提交推送 GitHub
git add . git commit -m "feat: 测试自动CI+CD部署" git push origin main- 立刻刷新 Jenkins 任务页面,流水线自动启动
- 逐阶段观察执行状态:前 5 个 CI 阶段绿色通过后,自动执行 6、7 两个 CD 部署阶段
- 登录目标部署服务器验证:
/data/app/demo目录存在最新上传的 demo.jarps -ef | grep java能查询到新版本服务进程- 访问项目接口,确认功能更新生效
- 查看 GitHub Webhook 记录,显示推送请求绿色成功✅
六、高频 CD 部署场景排坑指南
问题 1:SSH 上传文件失败,提示连接拒绝 / 权限不足
- 检查 Jenkins 全局 SSH 配置 IP、账号、密钥是否正确
- 服务器防火墙开放 22 端口,安全组放行 Jenkins 服务器出口 IP
- 服务器
~/.ssh文件夹权限 700,authorized_keys 权限 600,权限过宽会拒绝免密登录
问题 2:远程执行 stop.sh/start.sh 无效果,进程未重启
- 脚本缺少执行权限
chmod +x *.sh - 脚本路径使用绝对路径,避免相对路径导致找不到文件
- 查看服务器 logs 日志,排查 Java 启动报错(端口占用、配置缺失、JDK 版本不匹配)
问题 3:单元测试报错,直接阻断部署
属于设计预期,测试用例失败不允许发布上线,优先修复代码单元测试问题,生产环境禁止跳过 test 阶段。
问题 4:并发推送代码,Jar 包覆盖引发服务异常
解决方案:流水线配置开启【禁止并发构建】,上一次发布未完成时,新触发任务排队等待。
问题 5:Jenkins 提示 Publish over SSH 插件方法不存在
确认插件安装完成并重启 Jenkins,脚本中sshPublisher为该插件专属语法,缺少插件直接报错。
七、生产环境 CD 优化进阶方案
- 环境区分部署多分支匹配多服务器:main 分支部署生产、dev 分支部署测试环境,通过 Git 分支判断切换 SSH 服务器配置。
- 版本备份回滚机制上传 Jar 包前将旧包重命名备份,新增回滚流水线任务,一键切换历史版本。
- 发布结果消息通知CD 部署完成后调用钉钉 / 企业微信机器人,推送构建版本、提交记录、部署服务器、运行状态。
- 健康检查卡点新增远程 curl 健康检测脚本,启动服务后循环访问健康接口,接口正常才算部署成功,否则标记流水线失败告警。
- 密钥安全管控禁止明文账号密码,统一使用 SSH 密钥;Jenkins 凭证使用加密存储,不硬编码 IP、账号到 Jenkinsfile。
- 限流与灰度发布多节点集群场景扩展脚本,实现分批灰度部署,避免全量停机引发业务中断。
八、系列整体总结与下一篇预告
本系列三篇完整能力汇总
- 第一篇:吃透 GitHub Webhook 底层原理、密钥校验、事件调试、接口调试,打好自动化基础
- 第二篇:Webhook 对接 Jenkins,落地完整 CI 持续集成(代码拉取、单元测试、产物打包归档)
- 第三篇:基于 CI 流水线扩展 CD 持续交付,打通自动远程服务器部署,实现代码 Push 即上线全自动化闭环
下一篇预告(系列四)
后续将讲解企业级加固方案:Webhook 请求密钥鉴权防恶意攻击、Jenkins 权限分级、流水线分支过滤、多环境 (dev/test/prod) 隔离部署、灰度发布与自动回滚完整实战,完善企业生产可用的标准化自动化发布体系。
文末总结
本篇文章完成 CI+CD 完整自动化闭环,从开发提交代码到服务自动上线全程零人工介入,解决传统开发手动打包、手动上传服务器、手动启停服务的低效问题。整套方案基于 GitHub Webhook+Jenkins Pipeline 实现,适配中小型企业 Java 后端项目,合规、可复用、易维护,所有脚本开箱即用,直接落地到测试 / 生产环境。