Jenkins SSH连接配置详解:从原理到实战的自动化部署指南

📅 2026/8/17 9:34:39
Jenkins SSH连接配置详解:从原理到实战的自动化部署指南
1. 从“手动传包”到“一键部署”为什么Jenkins SSH连接是自动化部署的基石如果你和我一样经历过手动登录服务器、上传War包、重启Tomcat、再刷新页面看日志的“石器时代”部署流程那你一定明白当项目迭代到一天需要发布好几次的时候这种重复劳动是多么的折磨人。我最初接触Jenkins就是被它“自动化”的承诺所吸引但很快发现光有Jenkins这个“大脑”还不够它得能指挥远在另一台机器上的“手脚”去执行命令。这个指挥的通道就是SSH。简单来说Jenkins配置SSH Server连接远程服务器就是让Jenkins这个中央调度中心能够安全、无需人工干预地登录到你的测试、预发布或生产服务器执行一系列部署脚本。这不仅仅是省去了你敲命令的功夫更是将“构建-测试-部署”这条流水线彻底打通的关键一步。没有这一步你的Jenkins可能只是一个高级的代码编译和打包工具打通了这一步它才真正成为持续集成与持续部署CI/CD的引擎。从网络热词里你能看到大家关心的不仅仅是“连接”更是连接之后的一系列动作jenkins自动化部署、jenkins持续集成测试、jenkins自动部署。而所有这一切的起点往往就是建立一个稳定可靠的SSH连接。无论是部署一个简单的Spring Boot应用还是复杂的微服务集群抑或是执行jenkins 调用jmeter进行自动化测试SSH都是那个最通用、最核心的远程执行协议。所以这篇文章不是一份冷冰冰的官方文档翻译。我会结合我这些年趟过的坑从为什么需要它、到具体怎么配、再到配好了怎么用以及出了问题怎么查给你捋得明明白白。无论你是刚接触jenkins菜鸟教程的新手还是想优化现有流程的老手这篇都能给你带来可以直接“抄作业”的实操细节。2. 核心原理拆解Jenkins的SSH插件到底在背后做了什么在开始动手配置之前我们得先搞清楚Jenkins和远程服务器之间通过SSH通信的底层逻辑。这能帮你理解后续每一个配置项的意义并在出问题时快速定位。2.1 认证方式的抉择密码 vs. 密钥SSH连接的核心是身份认证。Jenkins SSH插件主要支持两种方式用户名密码认证最简单直接就像你用vscode连接远程服务器时输入密码一样。Jenkins会将你配置的密码通常是加密存储在连接时发送给服务器进行验证。优点配置简单无需在服务器端做额外操作。缺点安全性密码可能被记录在配置或日志中尽管Jenkins会尽力加密存在泄露风险。自动化如果服务器密码定期更换就需要同步更新Jenkins配置不利于完全自动化。兼容性一些严格的安全策略可能禁止纯密码SSH登录。SSH私钥认证这是生产环境强烈推荐的方式。它涉及一对密钥公钥和私钥。流程你在Jenkins服务器上生成一对密钥。将公钥写入远程服务器的~/.ssh/authorized_keys文件中。当Jenkins发起连接时它会使用本地的私钥进行签名远程服务器用存储的公钥验证签名。匹配则通过。优点高安全性私钥永远不出Jenkins服务器且可以设置复杂的密码短语保护私钥本身。便于自动化一次配置长期有效不受用户密码变更影响。权限精细可以为不同的Jenkins任务配置不同的密钥对对应服务器上不同的用户实现权限隔离。注意很多人在用vscode连接ssh远程服务器或mobaxterm时习惯了密码登录但在自动化场景下密钥认证是唯一可靠的选择。这就像给你家的智能锁服务器录入了Jenkins的指纹公钥以后它来“开门”就无需每次都输密码了。2.2 Jenkins SSH插件的角色连接池与会话管理Jenkins的“SSH Server”配置并不是指在Jenkins里安装一个SSH服务端像bitvise ssh server那样。恰恰相反Jenkins在这里是SSH客户端。我们配置的“SSH Server”条目实际上是告诉Jenkins“我有一个远程服务器它的连接信息是这样的”。连接池Jenkins插件会管理到这些远程服务器的连接。当多个任务需要连接同一台服务器时插件可能会复用连接以提高效率。会话与命令执行建立连接后Jenkins会在远程服务器上启动一个SSH会话然后在这个会话中执行你指定的Shell命令例如cd /app ./deploy.sh。执行完毕后会话关闭但底层TCP连接可能被保留以备下次使用。2.3 与“Agent节点”配置的关系你可能会看到jenkins 怎么配置agent节点的热词。这里需要厘清一个概念通过SSH连接服务器执行命令和配置一个SSH Agent节点是两种不同但有关联的用法。SSH连接执行命令更轻量更直接。就像你手动SSH过去执行一串命令。Jenkins将命令发送给远程服务器执行并获取输出。适用于简单的部署、文件传输如用xcopy复制到远程服务器的思路但在Linux下是scp或rsync、服务重启等。SSH Agent节点更重量级功能更强。Jenkins会将一个Agent程序是一个Jar包通过SSH连接推送到远程服务器并启动。之后整个Jenkins任务或其中的某个阶段可以调度到这个Agent节点上运行。这意味着任务的Workspace、工具环境如JDK, Maven都在远程服务器上。适合需要特定环境如某台服务器有GPU或需要分散构建负载的场景。本文重点讲解第一种——基础的SSH连接与命令执行这是更普遍的需求。理解了它再去看SSH Agent配置就会容易很多。3. 手把手配置从生成密钥到Jenkins后台设置理论说完了我们进入实战。假设我们的目标是让Jenkins能通过SSH密钥连接到一台IP为192.168.1.100的CentOS 7服务器并以deploy用户身份执行部署命令。3.1 第一步在Jenkins服务器上生成SSH密钥对首先我们需要在运行Jenkins服务的机器上生成密钥对。通常Jenkins服务是以jenkins系统用户运行的我们需要以这个用户的身份来生成密钥。切换到jenkins用户如果Jenkins是用系统服务安装的如通过linux安装jenkins教程里的方式sudo su - jenkins如果提示jenkins用户不可登录可以使用sudo -u jenkins bash。检查并进入SSH目录cd ~ ls -la .ssh/ # 查看是否已有密钥如果.ssh目录不存在可以稍后由ssh-keygen命令自动创建。生成ED25519密钥对比传统的RSA更安全、更快ssh-keygen -t ed25519 -C jenkinsdeploy-host-t ed25519指定密钥类型。-C jenkinsdeploy-host添加一个注释方便识别这里可以写任何描述。执行命令后会提示你输入保存密钥的文件名和密码短语Passphrase文件名直接回车使用默认位置~/.ssh/id_ed25519。密码短语强烈建议设置一个强密码短语。这会给私钥再加一层保护。即使私钥文件泄露没有密码短语也无法使用。Jenkins在配置时可以保存这个密码短语。查看生成的密钥cat ~/.ssh/id_ed25519.pub这会打印出公钥内容一串以ssh-ed25519开头的长文本。复制这整段内容我们下一步要用。3.2 第二步在远程服务器上配置公钥现在我们需要让目标服务器信任Jenkins服务器。登录到你的远程服务器192.168.1.100。登录并切换到目标用户这里我们用deploy用户ssh root192.168.1.100 # 或用其他有sudo权限的用户登录 sudo su - deploy确保SSH目录存在并设置正确权限权限错误是SSH密钥登录失败的常见原因mkdir -p ~/.ssh chmod 700 ~/.ssh touch ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys将公钥写入authorized_keys文件 将第一步中复制的公钥内容追加到~/.ssh/authorized_keys文件末尾。echo ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJL...你的公钥内容... jenkinsdeploy-host ~/.ssh/authorized_keys或者你也可以用编辑器如vim直接粘贴进去。3.3 第三步测试基础连接关键排错步骤在配置Jenkins之前强烈建议先在Jenkins服务器上以jenkins用户的身份手动测试SSH连接。这能提前暴露网络、权限、认证等问题。在Jenkins服务器上切换回jenkins用户执行ssh -i ~/.ssh/id_ed25519 deploy192.168.1.100-i指定使用的私钥文件。如果密钥有密码短语会提示你输入。输入正确的密码短语。如果成功你会登录到远程服务器的deploy用户命令行。输入exit退出。常见问题与解决Permission denied (publickey)最常见。99%的原因是远程服务器上~/.ssh/authorized_keys文件的权限不对或者公钥内容粘贴有误多了空格、换行。请严格按照第二步检查权限700和600并核对公钥内容。Connection timed out网络不通或远程服务器SSH服务未开启ubuntu server 22.04.5 lts 开启ssh这类问题。检查防火墙如firewalld、ufw是否放行了22端口。Host key verification failed首次连接时SSH会询问是否信任远程主机密钥。在自动化场景下我们需要让Jenkins自动接受。可以在测试时加上-o StrictHostKeyCheckingno参数仅限测试生产环境有安全风险或者在Jenkins配置中处理。3.4 第四步在Jenkins全局配置中添加SSH Server现在我们进入Jenkins的Web管理界面。安装插件确保已安装“Publish Over SSH”插件。这是最常用的SSH插件。进入“系统管理” - “插件管理”在“可选插件”中搜索安装。提示另一个常见插件是“SSH Pipeline Steps”它主要在Pipeline脚本中使用。Publish Over SSH插件功能更全面支持文件传输和命令执行且配置在全局更方便。配置SSH私钥进入“系统管理” - “系统配置”找到“Publish over SSH”部分。Key这是最核心的配置。点击“Add”按钮添加一个SSH Server。Name给你这个服务器连接起个名字如Production-Server。Hostname远程服务器IP或域名192.168.1.100。Username远程登录用户名deploy。Remote Directory远程工作目录。这是一个非常重要的配置。后续所有相对路径的操作如文件传输的目标路径、执行命令的当前目录都将基于此目录。通常设置为应用部署的根目录如/home/deploy/apps。确保deploy用户对该目录有读写权限。高级选项Port如果SSH端口不是默认的22在这里修改。Timeout连接超时时间默认即可。Disable exec如果勾选则此连接仅用于文件传输不能执行命令。我们不需要勾选。配置认证认证方式选择选择“Use password authentication, or use a different key”下面的“Advanced...”按钮。Passphrase / Password如果你生成密钥时设置了密码短语就在这里填入。如果你用的是密码认证也在这里填入远程用户的密码不推荐。Key将Jenkins服务器上~/.ssh/id_ed25519私钥的整个内容包括-----BEGIN OPENSSH PRIVATE KEY-----和-----END OPENSSH PRIVATE KEY-----复制粘贴到这里。获取私钥内容在Jenkins服务器上sudo cat /var/lib/jenkins/.ssh/id_ed25519路径根据你的实际用户home目录而定。测试连接填写完以上信息后点击右下角的“Test Configuration”按钮。如果一切配置正确你会看到绿色的“Success”提示并显示类似SSH Server Successfully connected.的信息。踩坑实录这里测试成功只代表Jenkins能用你提供的密钥和密码短语连接到服务器并完成认证。它并不验证Remote Directory是否存在或是否有权限。所以即使这里成功了后续文件传输仍可能因目录权限问题失败。保存点击页面底部的“保存”按钮。至此Jenkins全局的SSH Server连接就配置好了。这个配置可以在任何需要连接这台服务器的任务中引用。4. 在任务中实际使用SSH连接两种主流方式配置好了连接怎么用呢主要有两种方式在自由风格项目中使用和在Pipeline脚本中使用。4.1 方式一在自由风格项目中使用“Send files or execute commands over SSH”这是最直观的方式适合简单的部署流程。创建一个新的“自由风格”项目。在“构建”环节点击“增加构建步骤”选择“Send files or execute commands over SSH”。选择刚才配置的SSH Server在“SSH Server”下拉框中选择你之前配置的Production-Server。文件传输Transfers可以添加多个传输集。Source files需要传输的文件或目录相对于Jenkins任务Workspace的路径。支持通配符如target/*.jar。Remove prefix移除源路径的前缀。例如源文件是target/myapp-0.1.jar移除前缀target/后传输到远程的文件名就是myapp-0.1.jar。Remote directory这是基于全局配置里Remote Directory的相对路径。如果全局配置是/home/deploy/apps这里填写backend/那么文件最终会被传输到/home/deploy/apps/backend/。Exec command文件传输成功后在远程服务器上执行的命令。这是部署动作发生的地方。# 示例停止旧服务备份移动新文件启动服务 cd /home/deploy/apps/backend/ ./stop.sh 2/dev/null || true # 忽略停止失败 cp -f myapp-0.1.jar myapp-0.1.jar.bak.$(date %Y%m%d%H%M%S) # 假设文件已通过上一步传输过来 # 设置执行权限如果需要 chmod x myapp-0.1.jar nohup ./start.sh app.log 21 纯命令执行如果你不需要传输文件只想执行命令可以在“Transfers”中不配置任何源文件直接在“Exec command”里写命令即可。4.2 方式二在Pipeline脚本中使用sshCommand或sshPutPipeline流水线是更现代、更强大的方式部署流程代码化易于版本管理。首先确保安装了“Pipeline”和“SSH Pipeline Steps”插件。在Pipeline脚本中你可以使用sshCommand或sshPut步骤。但更常见的做法是使用sshagent来包装需要SSH连接的步骤它帮你管理密钥。pipeline { agent any stages { stage(Build) { steps { // 构建你的应用生成制品 sh mvn clean package } } stage(Deploy) { steps { // 使用 sshagent 包装部署步骤 sshagent([your-ssh-credentials-id]) { // 这里需要的是Jenkins中存储的SSH私钥凭据的ID // 1. 传输文件 (使用scp命令) sh scp -o StrictHostKeyCheckingno target/*.jar deploy192.168.1.100:/home/deploy/apps/backend/ // 2. 执行远程部署命令 sh ssh -o StrictHostKeyCheckingno deploy192.168.1.100 cd /home/deploy/apps/backend/ ./deploy.sh } } } } }关键点sshagent([your-ssh-credentials-id])这里的凭据ID需要在Jenkins的“凭据”系统中先添加。进入“系统管理” - “管理凭据” - “全局凭据” - “添加凭据”选择“SSH Username with private key”类型将私钥内容粘贴进去并设置一个ID如prod-server-key。然后在脚本中引用这个ID。在Pipeline中你拥有更大的灵活性可以编写复杂的逻辑比如根据构建分支决定部署到哪台服务器或者在执行命令前进行更完善的健康检查。5. 避坑指南那些我踩过的坑和解决方案配置过程看似顺利但实际运行中总会遇到各种问题。下面是我总结的几个高频“坑点”。5.1 坑一权限问题——从“Permission denied”到“Operation not permitted”这是SSH相关问题的万恶之源表现形式多样。场景1Jenkins用户无法读取私钥文件现象Jenkins日志报错Permission denied (publickey)但手动测试连接成功。根因Jenkins进程通常是jenkins用户对私钥文件/var/lib/jenkins/.ssh/id_ed25519没有读取权限。解决sudo chown jenkins:jenkins /var/lib/jenkins/.ssh/id_ed25519 sudo chmod 600 /var/lib/jenkins/.ssh/id_ed25519同样检查.ssh目录权限是否为700。场景2远程服务器目标目录无写权限现象Jenkins测试连接成功但文件传输失败日志提示权限错误。根因全局配置中的Remote Directory或任务中配置的相对目录deploy用户没有写入权限。解决登录远程服务器检查并修改目录权限。sudo mkdir -p /home/deploy/apps sudo chown -R deploy:deploy /home/deploy/apps sudo chmod 755 /home/deploy/apps # 或根据实际情况调整场景3远程命令执行权限不足现象连接和文件传输都成功但Exec command里的脚本执行失败例如无法重启系统服务需要sudo权限。解决推荐配置sudo免密码在远程服务器的/etc/sudoers文件中使用visudo命令编辑为deploy用户添加特定命令的免密码执行权限。deploy ALL(ALL) NOPASSWD: /bin/systemctl restart myapp.service然后在Jenkins的命令中sudo systemctl restart myapp.service。使用更强大的用户如果安全要求允许可以让Jenkins直接使用具有所需权限的用户如root连接。但这通常不是最佳实践。5.2 坑二环境变量与路径问题——命令“not found”现象在Jenkins中执行的远程命令提示bash: some-command: command not found但手动SSH登录后执行同样的命令却成功。根因Jenkins通过SSH执行命令时使用的是非交互式、非登录式Shell。它不会加载用户profile如~/.bash_profile,~/.bashrc中的环境变量导致PATH等设置失效。解决在命令中使用绝对路径这是最可靠的方法。不要用java -jar而要用/usr/local/java/bin/java -jar。在命令中显式设置环境变量export PATH/usr/local/bin:$PATH /path/to/your/script.sh修改远程服务器的SSH配置不推荐影响全局在/etc/ssh/sshd_config中设置PermitUserEnvironment yes并在对应用户的~/.ssh/environment文件中定义变量。这比较麻烦且有安全考量。5.3 坑三连接超时与中断——网络不稳定或长任务现象文件传输大文件时中断或执行一个耗时很长的命令如数据库备份时连接被断开。根因SSH连接有超时设置或者网络抖动。解决调整Jenkins SSH插件超时在全局SSH Server配置的“高级”选项里增加“Timeout”的值单位毫秒。使用nohup或tmux/screen执行长任务让命令在后台运行不依赖SSH会话。nohup ./long-running-script.sh script.log 21 # 或者使用tmux tmux new-session -d -s deploy-task ./long-running-script.sh在服务器端调整SSH守护进程配置/etc/ssh/sshd_configClientAliveInterval 60 ClientAliveCountMax 10这会让服务器每60秒向客户端发送一次保活信号最多10次无响应才断开连接。5.4 坑四主机密钥验证StrictHostKeyChecking现象首次连接时失败日志提示Host key verification failed。根因SSH客户端会验证服务器的主机密钥防止中间人攻击。在自动化中需要处理这个问题。解决按推荐度排序最佳实践将远程主机密钥预先添加到Jenkins服务器的known_hostssudo -u jenkins ssh-keyscan -H 192.168.1.100 /var/lib/jenkins/.ssh/known_hosts这样既安全又免除了交互提示。在Jenkins任务中禁用严格检查仅用于测试或受控内网在自由风格项目的“Exec command”中为scp或ssh命令添加-o StrictHostKeyCheckingno参数。在Pipeline中也可以在sh步骤的命令里添加。警告这会降低安全性使连接容易受到中间人攻击。生产环境慎用。6. 进阶应用与最佳实践当你掌握了基础的SSH连接后可以尝试以下进阶用法让自动化部署更稳健、更高效。6.1 结合“Environment Injector”插件使用环境变量你可能会注意到热词里有jenkins可用环境变量。Jenkins有很多内置变量如BUILD_NUMBER,JOB_NAME我们也可以自定义。在部署时我们经常需要根据不同的环境测试、生产或构建参数来改变部署目标或配置。安装“Environment Injector”插件。在任务配置中找到“构建环境”部分勾选“Inject environment variables to the build process”。你可以在这里定义键值对例如DEPLOY_ENVproduction。在后续的“Send files over SSH”的“Exec command”中就可以直接使用这些变量了在Shell中通过$DEPLOY_ENV访问。这可以实现一套脚本多环境部署。6.2 实现回滚机制自动化部署必须包含回滚方案。一个简单的思路是在传输新版本文件前先将远程服务器上的当前版本文件备份到特定目录并以时间戳或构建号命名。“Exec command”中的部署脚本应该具备健康检查功能。例如启动新服务后循环调用一个健康检查接口如/health如果连续多次失败则自动执行回滚脚本。回滚脚本的内容就是停止当前失败的服务从备份目录恢复上一个版本的文件然后启动旧版本服务。这可以通过在“Exec command”中编写一个复杂的Shell脚本来实现并将该脚本本身也通过Jenkins传输到服务器然后执行它。6.3 与Docker结合对接docker jenkins的最佳实践方式在现代部署中应用很可能被封装在Docker容器里。此时Jenkins通过SSH连接到服务器后执行的命令就变成了Docker命令。一个典型的流程Jenkins构建应用生成Docker镜像并推送到私有镜像仓库。通过SSH连接到生产服务器。执行远程命令# 拉取最新镜像 docker pull my-registry.com/myapp:latest # 停止并删除旧容器 docker stop myapp-container || true docker rm myapp-container || true # 运行新容器注入环境变量、挂载卷等 docker run -d --name myapp-container -p 8080:8080 \ -e SPRING_PROFILES_ACTIVEprod \ -v /app/config:/config \ my-registry.com/myapp:latest # 清理无用镜像 docker image prune -f这种方式下服务器上只需要安装Docker无需关心Java、Node.js等具体运行环境部署和回滚拉取旧版本镜像都变得极其简单。6.4 配置多台服务器与分组在“Publish over SSH”插件配置中你可以添加多个SSH Server。对于集群部署你可以为每台服务器单独配置一个条目在任务中依次选择执行。使用“SSH Plugin”的扩展功能如果插件支持或者编写Pipeline脚本循环遍历一个服务器列表进行部署。对于gitlab 一个代码仓库有多个服务这种微服务场景你可能需要为每个服务配置独立的部署脚本和服务器列表这正体现了Pipeline脚本化的优势。配置Jenkins SSH连接远程服务器就像给自动化部署这辆赛车装上了方向盘和油门。它看似只是基础的一步却直接决定了后续所有自动化流程的稳定性和可靠性。从我个人的经验来看花时间把密钥认证、权限、环境变量这些基础打牢远比后期频繁救火要划算得多。记住自动化是为了提高效率而不是制造更多隐藏的、定时爆发的问题。每次配置完务必像我们第三步那样从Jenkins用户的角度做一次完整的手动测试模拟整个部署流程这能帮你提前发现90%的配置问题。