大事记 - Jenkins 脚本部署报错 “Host key verification failed”
作者:互联网
// 这本是一个不应该出现的问题...
问题描述:
有一台用来部署项目的 Jenkins 服务器,然后新开了一台应用服务器,需要通过 Jenkins 将打包后的代码部署到应用服务器
但由于权限控制,我不知道两边服务器的密码,应用服务器(记为 dev.server)也只能通过跳板机访问
而 Jenkins 服务器(记为 jenkins.server)我没有任何办法访问,只能访问搭建好的 Jenkins 页面
在这样的背景下, 如果在 Jenkins 脚本中通过 ssh 直连应用服务器
ssh deploy@dev.server
就会出现 Host key verification failed 错误
分析原因:
其实原因很简单,通过 ssh 访问服务器是需要携带认证信息的,比如用户和密码,或者通过公钥免密登录
但这两个方案都不适用,因为我既不知道应用服务器的密码,也无法拿到 Jenkins 服务器的公钥
解决方案:
于是一次迂回大作战打响了
第一回合:Jenkinsfile 携带私钥
由于问题的本质是认证失败,我便打算通过 Jenkins credentials 来处理
首先在 Jenkins 中创建一个类型为 SSH Username with private key 的全局凭据
并将应用服务器的私钥粘贴进去
cat /root/.ssh/id_rsa
// 完整流程可以参考《Jenkins----凭据管理之配置ssh私钥》
然后需要调整 Jenkinsfile 脚本,用 withCredentials 方法将需要凭据的部分给包起来
比如我原本的脚本是:
stages { stage('Init ssh server'){ steps { sh "ssh ${env._HOST_NAME} 'mkdir -p ${env._DEPLOY_PATH}'" } } }
加入凭据之后就是:
stages { stage('Init ssh server'){ steps { withCredentials(bindings: [ sshUserPrivateKey(credentialsId: 'jenkins-ssh-key-xxxx', keyFileVariable: 'SSH_KEY_XXX') ]) { sh "ssh ${env._HOST_NAME} 'mkdir -p ${env._DEPLOY_PATH}'" } } } }
// 建议使用 Jenkins 的片段生成器
配置好之后,我再次回放脚本
在我期待的目光下,Console Output 又抛出那个熟悉错误 Host key verification failed
第二回合:尝试配置免密登录
withCredentials 的方案失败之后,我再次梳理了一下整个流程,还是决定配置免密登录
我先用自己的电脑来测试,获取到本地的公钥
cat ~/.ssh/id_rsa.pub
然后通过跳板机进入应用服务器,打开 authorized_keys 文件(若无则创建)
vi ~/.ssh/authorized_keys
然后将本地公钥粘贴到应用服务器 authorized_keys 的末尾
如果知道应用服务器的密码,上述过程还可以简化为一行命令:
ssh-copy-id user@hostname
运行之后需要输入对应用户的密码,然后就会把本地的公钥追加到 authorized_keys
此外还需要调整 ssh 的配置文件以及访问权限,详细配置可以参考《服务器配置免密码密钥登录》
不过运维已经完成了应用服务器的基本配置,在修改了 authorized_keys 之后,我就能在本地链接应用服务器了
眼见本地连接成功,我急忙腆着脸去找 Jenkins 服务器的管理员,费了好多口舌,他终于把 Jenkins 服务器的公钥给我了
随后我将 Jenkins 服务器的公钥也配到应用服务器的 authorized_keys 中,再次回放脚本
然而,结果依然是 Host key verification failed
同样的配置,为什么本地能正常访问,Jenkins 服务器却无法访问呢?
决战:本地直连 Jenkins 服务器
我想了许久,也没有想通本地与 Jenkins 服务器的差异
最后把心一横,决定想办法连上 Jenkins 服务器看看
可运维始终不肯开放跳板机权限,在我束手无措的时候,突然想到 Jenkinsfile 本身就是在 Jenkins 服务器上跑脚本
那么... 我岂不是可以通过 Jenkins 脚本,将我本地的公钥添加到 Jenkins 服务器的 authorized_keys 中,实现本地到 Jenkins 服务器的免密登录?
于是我在 Jenkins 脚本中添加了这一行命令:
sh "echo 'ssh-rsa xxxxxx' >> ~/.ssh/authorized_keys"
其中的 'ssh-rsa xxxxxx' 就是我本地公钥 id_rsa.pub
脚本跑完之后,我在本地使用 ssh 访问 Jenkins 服务器:
ssh root@jenkins.server
没有让我输入密码,这说明免密登录配置成功了。但有以下提示:
这个提示并不陌生, 首次连接服务器时都会有这个确认信息
确认之后,这个远程服务器的信息就会记录到本地的 ~/.ssh/known_hosts 中
我突然想到,Jenkins 服务器也是第一次访问应用服务器,会不会也有这个确认过程?而在脚本中无法确认,所以就会报错
此时我已经连上了 Jenkins 服务器,并且在应用服务器的 authorized_keys 中添加了 Jenkins 服务器的公钥
接着我在 Jenkins 服务器上,再次尝试通过 ssh 访问应用服务器,果然出现了上面的确认提示!
我双手颤抖着输入 yes,随后回到 Jenkins 部署页面,回放脚本
这次一路畅通,没有出现任何报错。看到脚本执行成功的绿色标记,我长舒了一口气
再来回溯整个问题,其实就是 known_hosts 导致的。如果解决了 known_hosts 的问题,使用 withCredentials 也是可以的
最后补充一篇《SSH之known_hosts文件》作为参考~
标签:公钥,keys,failed,Host,报错,ssh,Jenkins,服务器,应用服务器 来源: https://www.cnblogs.com/wisewrong/p/16539155.html