Jenkins 配置 Publish over SSH 自动部署项目

一、前提条件

  1. 环境准备
    • Jenkins 已安装 Publish Over SSH 插件(进入 Manage JenkinsPlugins → 搜索并安装 Publish Over SSH)。
    • 目标部署服务器(需部署项目的服务器)已开启 SSH 服务(默认端口 22,若为其他端口需单独配置)。
    • Jenkins 服务器(或容器)与目标服务器网络互通(可通过 pingtelnet <目标IP> 22 验证)。

二、配置 Jenkins 与目标服务器的 SSH 免密登录

1. 在 Jenkins 容器内生成 SSH 密钥对

由于 Jenkins 通常通过 Docker 容器运行,需进入容器内生成密钥(确保密钥由 Jenkins 服务用户持有):

bash 复制代码
# 进入 Jenkins 容器(替换容器名为实际容器名,如 "jenkins")
docker exec -it -u root jenkins /bin/bash  

# 生成 RSA 密钥对(一路回车,可选设置密钥密码 Passphrase,生产环境建议设置)
ssh-keygen -t rsa -b 2048 -C "jenkins-ssh-key"  

# 生成后密钥路径:私钥 /root/.ssh/id_rsa,公钥 /root/.ssh/id_rsa.pub  

2. 将公钥复制到目标部署服务器

方式 1:使用 ssh-copy-id 自动复制(推荐,需目标服务器支持)
bash 复制代码
# 首次连接目标服务器,需手动确认指纹(输入 "yes")并输入目标服务器密码  
ssh <目标服务器用户名>@<目标服务器IP>  # 例如:ssh appuser@172.20.113.93  

# 复制公钥到目标服务器(替换用户名和IP)  
ssh-copy-id -i ~/.ssh/id_rsa.pub <目标服务器用户名>@<目标服务器IP>  
方式 2:手动复制公钥(若 ssh-copy-id 不可用)
  1. 查看 Jenkins 容器内的公钥内容

    bash 复制代码
    cat /root/.ssh/id_rsa.pub  

    复制输出的公钥文本(以 ssh-rsa 开头)。

  2. 登录目标服务器,粘贴公钥到 authorized_keys

    bash 复制代码
    # 登录目标服务器  
    ssh <目标服务器用户名>@<目标服务器IP>  
    
    # 创建 .ssh 目录(若不存在)  
    mkdir -p ~/.ssh && chmod 700 ~/.ssh  
    
    # 编辑 authorized_keys 文件,粘贴 Jenkins 公钥  
    vi ~/.ssh/authorized_keys  # 粘贴公钥后保存退出  
    
    # 设置权限(必须,否则 SSH 会拒绝免密登录)  
    chmod 600 ~/.ssh/authorized_keys  

3. 验证 SSH 免密连接

在 Jenkins 容器内执行以下命令,确认无需密码即可登录目标服务器:

bash 复制代码
ssh <目标服务器用户名>@<目标服务器IP>  # 若直接进入目标服务器终端,说明免密配置成功  

三、Jenkins 全局配置 Publish over SSH

1. 进入配置页面

Jenkins 首页 → Manage JenkinsSystem (系统配置)→ 找到 Publish over SSH 模块。

2. 配置 SSH 服务器(目标部署服务器)

(1)配置 SSH 密钥
字段 填写说明
Passphrase 若生成密钥时设置了"密钥密码",则填写该密码;未设置则留空。
Path to key 私钥在 Jenkins 容器内的绝对路径(如 /root/.ssh/id_rsa)。
Key 直接粘贴私钥文件(id_rsa)的完整文本内容(若填写此项,Path to key 会被忽略)。

推荐配置:直接粘贴私钥内容(避免容器路径变更导致失效):

  • 在 Jenkins 容器内执行 cat /root/.ssh/id_rsa,复制完整私钥文本(从 -----BEGIN RSA PRIVATE KEY----------END RSA PRIVATE KEY-----)。
  • 粘贴到 Key 字段中。
(2)添加目标服务器信息

点击 SSH ServersAdd,配置目标部署服务器参数:

字段 填写说明
Name 自定义服务器名称(如"deploy-server-172.20.113.93",后续构建时选择)。
Hostname 目标服务器 IP 或域名(如 172.20.113.93)。
Username 目标服务器登录用户名(如 appuser)。
Remote Directory (可选)默认远程目录(若构建后步骤中未指定,会使用此目录,一般留空)。
Port SSH 端口(默认 22,若目标服务器 SSH 端口非 22,需填写实际端口,如 2222)。

高级选项(按需配置)

  • 勾选 Use password authentication, or use a different key:若不使用全局密钥,可单独指定该服务器的密钥。
  • Timeout (ms):设置 SSH 连接超时时间(默认 30000 ms,网络差时可延长)。

3. 测试 SSH 连接

点击 Test Configuration ,若显示 Success,说明目标服务器配置正确;否则检查密钥、用户名、IP 或端口是否错误。

4. 保存配置

点击页面底部 Save,完成 Publish over SSH 全局配置。

四、在项目中添加构建后部署步骤(以 Spring Boot 项目为例)

以之前的 Spring Boot 项目任务(如 project-springboot-admin)为例,添加"通过 SSH 发送构建产物并部署"的步骤。

1. 进入项目配置页面

项目任务页面 → Configure (配置)→ Post-build Actions (构建后操作)→ 点击 Add post-build action → 选择 Send build artifacts over SSH

2. 配置 SSH 部署参数

(1)选择目标服务器
  • SSH Server:从下拉列表选择在全局配置中添加的目标服务器(如"deploy-server-172.20.113.93")。
(2)配置文件传输(Transfer Set)
字段 填写说明
Source files 需传输到目标服务器的文件路径(相对于 Jenkins 项目工作区的相对路径)。 示例:dsrm-server/target/dsrm-server.jar(Spring Boot 项目打包后的 JAR 包路径)。
Remove prefix (可选)移除源文件路径的前缀(如填写 dsrm-server/target,则传输到目标服务器的文件名为 dsrm-server.jar,而非带路径的文件)。
Remote directory 目标服务器接收文件的目录(绝对路径)。 示例:/home/etc/xxxxxx/target(根据实际部署路径填写)。
Exec command 文件传输完成后在目标服务器执行的部署命令(如备份旧版本、启动新服务)。
(3)填写部署命令(Exec command)

用户提供的示例命令(需根据实际路径调整):

bash 复制代码
# 1. 备份旧版本 JAR 包(以当前时间戳命名,保留历史版本)  
mv /data/app/xxxxx.jar /data/app/xxxxx.jar-$(date +%Y%m%d%H%M%S)  

# 2. 将传输到目标服务器的新 JAR 包移动到部署目录  
mv /home/etc/xxxxxx/target/dsrm-server.jar /data/app/xxxx.jar  

# 3. 执行重启脚本(后台运行,避免 Jenkins 构建进程阻塞)  
sh -c "cd /data/app && ./restart.sh & disown"  

3. 保存项目配置

点击 Save,完成构建后部署步骤配置。

五、部署脚本(restart.sh)说明

目标服务器 /data/app/restart.sh 脚本用于停止旧服务、启动新服务,内容如下(需提前创建并赋予执行权限):

bash 复制代码
#!/bin/bash  
# 停止旧服务  
rm -f nohup.out  # 清理旧日志  
app="xxxx.jar"  # 替换为实际 JAR 包名称(如 dsrm-server.jar)  
pid=$(ps -ef | grep "$app" | grep -v grep | awk '{print $2}')  # 获取进程 ID  

if [ -n "$pid" ]; then  
    echo "Stopping old process: $pid"  
    kill -9 "$pid"  # 强制停止进程  
fi  

# 启动新服务(使用指定 JDK 路径,后台运行并输出日志)  
jdk11_path="/data/software/jdk-17/bin/java"  # 替换为目标服务器 JDK 实际路径  
nohup setsid "$jdk11_path" -jar "$app" > nohup.out 2>&1 < /dev/null &  
echo "New process started successfully"  

脚本权限设置(目标服务器执行):

bash 复制代码
chmod +x /data/app/restart.sh  # 赋予执行权限  

六、验证自动部署

1. 手动触发构建

进入项目任务页面 → Build Now,等待构建完成。

2. 查看部署日志

  • Jenkins 构建日志 :构建后点击 Console Output ,搜索 SSH: Transferred 1 file(s)(文件传输成功)和 Exec command complete(部署命令执行完成)。
  • 目标服务器日志 :登录目标服务器,查看 /data/app/nohup.out,确认新服务启动日志(如 Started XxxApplication in x.x seconds)。

七、常见问题排查

1. SSH 连接失败(日志显示 Connection refusedAuthentication failed

  • 原因:目标服务器 SSH 端口错误、公钥未正确复制、Jenkins 私钥配置错误。
  • 解决
    • 确认目标服务器 SSH 端口(默认 22),全局配置中 Port 字段是否正确。
    • 重新执行公钥复制步骤,确保目标服务器 ~/.ssh/authorized_keys 包含 Jenkins 公钥,且权限为 700(.ssh 目录)和 600(authorized_keys)。
    • 检查 Jenkins 全局配置的私钥是否完整(无多余空格或换行)。

2. 文件传输失败(日志显示 No such file

  • 原因Source files 路径错误(相对于 Jenkins 项目工作区)。
  • 解决 :在 Jenkins 项目工作区(如 /var/jenkins_home/workspace/project-springboot-admin)确认 JAR 包实际路径,调整 Source files(如 dsrm-server/target/dsrm-server.jar)。

3. 部署命令执行失败(日志显示 mv: cannot stat ...

  • 原因Remote directory 路径错误或目标服务器目录权限不足。
  • 解决
    • 登录目标服务器,确认 Remote directory(如 /home/etc/xxxxxx/target)是否存在,若不存在则创建:mkdir -p /home/etc/xxxxxx/target
    • 确保 Jenkins 登录用户(如 appuser)对目标目录有读写权限:chown -R appuser:appuser /home/etc/xxxxxx/target

4. 服务启动失败(nohup.out 日志报错)

  • 原因:JDK 路径错误、JAR 包损坏或配置文件缺失。
  • 解决
    • 检查 restart.sh 中的 jdk11_path 是否指向目标服务器实际 JDK 路径(执行 which java 确认)。
    • 手动在目标服务器执行 java -jar /data/app/xxxx.jar,查看启动错误(如依赖缺失、端口占用)。

八、总结

通过以上步骤,Jenkins 可在构建完成后自动将 Spring Boot 项目的 JAR 包通过 SSH 传输到目标服务器,并执行部署脚本完成服务重启。该流程可扩展到多服务器部署(添加多个 SSH Server)或其他项目(如 Vue 项目传输前端包到 Nginx 目录),实现全自动化部署。

相关推荐
闲人编程20 小时前
Elasticsearch搜索引擎集成指南
python·elasticsearch·搜索引擎·jenkins·索引·副本·分片
田井中律.20 小时前
【无标题】
ssh
先做个垃圾出来………1 天前
SSH密钥管理最佳实践
运维·ssh
mailangduoduo1 天前
零基础教学连接远程服务器部署项目——VScode版本
服务器·pytorch·vscode·深度学习·ssh·gpu算力
vx_Biye_Design2 天前
【关注可免费领取源码】房屋出租系统的设计与实现--毕设附源码40805
java·spring boot·spring·spring cloud·servlet·eclipse·课程设计
人间打气筒(Ada)2 天前
jenkins基于Pipeline发布项目
java·pipeline·jenkins·流水线·ci·cd·cicd
vx_Biye_Design2 天前
基于Spring Boot+vue的湖北旅游景点门票预约平台的设计--毕设附源码29593
java·vue.js·spring boot·spring cloud·servlet·eclipse·课程设计
lang201509283 天前
JSR-340 :高性能Web开发新标准
java·前端·servlet
狂野小青年3 天前
Jenkins如何添加全局凭证
运维·jenkins
铅笔侠_小龙虾3 天前
Flutter 组件层级关系
前端·flutter·servlet