Jenkins 默认只构建不部署,需手动配置Post-build Actions或Pipeline脚本执行scp、ssh等操作;常见失败原因包括未定义部署步骤、路径错误、权限不足及未终止旧进程。 很多刚接触 Jenkins 的朋友会遇到一个典型问题:构建明明显示成功了,但服务器上的应用纹丝不动,还是
Jenkins持续集成CI/CD自动化部署流程详解
时间:2026-06-04
浏览:100
文章目录
Jenkins 默认只构建不部署,需手动配置Post-build Actions或Pipeline脚本执行scp、ssh等操作;常见失败原因包括未定义部署步骤、路径错误、权限不足及未终止旧进程。

很多刚接触 Jenkins 的朋友会遇到一个典型问题:构建明明显示成功了,但服务器上的应用纹丝不动,还是旧版本。这背后其实是一个关键概念:Jenkins 本身并不自带“自动化部署”功能。它的核心职责是任务的触发、执行和编排,至于把包传上服务器、重启服务这些“部署动作”,必须由我们显式地告诉它怎么做——要么在构建后步骤里配置,要么写在 Pipeline 脚本里。如果没配这些,打包好的文件就只会静静地躺在 Jenkins 的工作空间里,不会自动跑到目标服务器上。
为什么 build 成功了但服务没更新?
这个场景太常见了:控制台输出一片绿色的 [INFO] BUILD SUCCESS,本地 target/xxx.jar 也生成了,可远程服务器一查,旧进程还在跑,新包压根没传过去。
问题的根源就在于,Jenkins 默认只负责“构建”(Build),不处理“部署”(Deploy)。在自由风格项目中,你必须手动添加 Post-build Actions 并填写 Shell 命令,或者安装像 Publish Over SSH 这样的插件;如果是 Pipeline 项目,则必须在 stages 里明确写出 scp 或执行远程重启的 ssh 命令。
有几个细节特别容易踩坑:
- 路径不是固定的:
workspace的路径会因任务不同而变化,可能是/var/lib/jenkins/workspace/xxx,也可能是/home/jenkins/workspace/yyy,脚本里如果写死了绝对路径,很容易失败。 - 脚本错误被忽略:Shell 脚本里如果没加
set -e,那么即使某条命令(比如scp因权限问题失败)出错,后续命令仍会继续执行,从日志看像是“成功”了,实际上关键步骤已经漏掉了。 - 旧进程没清理:部署前没有通过
kill -9 $(cat /path/to/app.pid)或systemctl stop myapp终止旧进程,导致新应用启动时端口被占用,直接失败。
自由风格项目怎么加部署步骤?
对于快速验证或者简单的单机部署场景,自由风格项目是个不错的选择,它不需要写 Groovy 脚本,通过界面勾选和填写命令就能完成。
关键操作步骤如下:
- 进入任务配置页面,滚动到最底部,找到
Post-build Actions区域。 - 点击“增加构建后操作步骤”,选择
Execute shell。 - 在出现的脚本框里,填写真实有效的部署命令。
举个例子,一个典型的部署脚本可能长这样:
export BUILD_ID=dontKillMe cd $WORKSPACE/target scp -o StrictHostKeyChecking=no app.jar user@192.168.1.100:/opt/myapp/ ssh -o StrictHostKeyChecking=no user@192.168.1.100 “systemctl restart myapp”
这里有两个实用技巧:一是使用 $WORKSPACE 这个 Jenkins 内置变量来定位工作目录,比硬编码路径更安全可靠;二是 StrictHostKeyChecking=no 这个参数,它能避免首次 SSH 连接时因主机密钥确认而卡住,当然,在生产环境中更规范的做法是预先配置好 known_hosts。
如果觉得每次写 Shell 命令麻烦,可以试试 Publish Over SSH 插件。使用前需要在 Jenkins 系统管理的“系统设置”里,预先配置好目标服务器的连接信息(IP、用户名、密钥等)。之后在任务中直接选择对应的服务器和远程目录即可。这个插件底层其实也是调用 scp 和 ssh,只是做了一层封装,让配置更直观。
Pipeline 项目怎么写可维护的部署流程?
自由风格项目适合“一次跑通”,但若要构建清晰、可维护的 CI/CD 流程,Pipeline 才是更专业的解决方案。它的优势在于逻辑结构清晰、配置即代码(便于版本控制)、支持并行阶段,还能方便地加入条件判断,例如只有 main 分支的代码才部署到生产环境。
下面是一个放在项目根目录 Jenkinsfile 中的最小可用示例:
pipeline {
agent any
environment {
APP_NAME = ‘my-springboot-app’
REMOTE_HOST = ‘192.168.1.100’
REMOTE_USER = ‘deploy’
}
stages {
stage(‘Checkout’) {
steps { checkout scm }
}
stage(‘Build’) {
steps { sh ‘mvn clean package -Dma ven.test.skip=true’ }
}
stage(‘Deploy’) {
steps {
sh “scp target/${APP_NAME}.jar ${REMOTE_USER}@${REMOTE_HOST}:/opt/app/”
sh “ssh ${REMOTE_USER}@${REMOTE_HOST} ‘systemctl restart ${APP_NAME}’”
}
}
}
}
编写 Pipeline 脚本时,有几个关键细节需要注意:
- 敏感信息管理:切勿将密码或私钥直接写在
Jenkinsfile里。应该使用 Jenkins 的凭据管理功能存储 SSH 私钥,然后在脚本中通过credentialsId来引用。 - 执行节点选择:
agent any表示使用任何可用的袋里节点执行。如果部署目标与 Jenkins 主节点在同一台机器,可以指定agent { label ‘master’ }来避免不必要的调度开销。 - 阶段划分:在实际项目中,建议将流程拆分成更细的阶段,例如
Test(测试)、Build Image(构建镜像)、Push to Registry(推送镜像)等,而不是把所有操作都堆在Deploy这一个阶段里。
部署失败时最该查哪三处日志?
遇到部署失败,先别急着重新运行任务。在 CI/CD 流程中,超过九成的部署问题都出在权限、路径和环境这三件事上。按照以下顺序排查,效率最高:
- Jenkins 控制台输出:这是最直接的线索。查看日志末尾的红色错误信息,通常会是
Permission denied (publickey)(权限拒绝)或No such file or directory: target/xxx.jar(路径错误)这类明确提示。 - 目标服务器应用日志:通过
journalctl -u myapp -n 50命令查看应用本身的系统服务日志。这能确认进程是否真的成功启动并运行,还是启动后因为端口冲突、配置文件缺失等问题又退出了。 - Jenkins 服务日志:如果连 SSH 命令都没成功发出,可以查看 Jenkins 服务器本地的日志
/var/log/jenkins/jenkins.log。问题可能出在 Jenkins 进程用户没有读取私钥的权限,或者在 Docker 容器环境中没有安装openssh-client包。
说到底,调试部署流程最棘手的往往不是语法错误,而是环境差异。Jenkins 通常以 jenkins 用户身份运行任务,而我们手动操作时用的是 root 或个人账号。这两者的家目录、环境变量 PATH、SSH 袋里状态可能完全不同。一个非常有效的调试方法是:在部署前,先切换到 jenkins 用户,手动执行一遍你写在脚本里的命令,这比在控制台里反复猜测要快得多。
实用工具推荐
绿化、压缩、噪点和虚拟水印,自由调节做旧程度。
选择画质和输出格式,预览压缩前后的大小。