在使用 Jenkins 做持续集成的时候,我们经常会通过ssh
连接到远程主机来进行一些操作。因为所有的操作都是脚本自动运行的,所以我们通常会使用免密登录。那么在Jenkinsfile
中我们如何来实现呢?
Jenkinsfile 配置免密登录
看到之前项目中的Jenkinsfile
是这样写的,在环境变量里定义了ssh private key
,如下:
environment {
DEPLOY_SSH =
'''
-----BEGIN RSA PRIVATE KEY-----
......
-----END RSA PRIVATE KEY-----
'''
}
然后在脚本中这样写:
set -e
mkdir -p ~/.ssh
echo "$DEPLOY_SSH" >> ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
echo "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
ssh root@192.168.0.110 "mkdir -p /data/website"
rsync -rvR ./ root@192.168.0.110:/data/website
也就是说把ssh private key
写到 Jenkins 脚本运行环境里的id_rsa
文件中,以达到ssh
远程免密连接的效果。但是这样带来一个很严重的问题,我们连接到远程服务器的ssh private key
暴露在源代码中了,任何人都可以获取到该ssh private key
连接到服务器去做一些操作。
所以这种方式是不可行的。因为之前 Jenkins 在项目中主要起的作用是发布代码到测试环境,所以大家都不并不在意这个问题。但是生产环境,这种操作是绝对禁止的。
那么,我们在Jenkinsfile
中怎么去连接到远程服务器呢?其实 Jenkins 提供了各种 ssh 插件可以帮助我们完成的,配合它的 Credentials 管理,我们可以把这种敏感信息隐藏起来,开发人员是接触不到的。比如: SSH Agent Plugin
SSH Agent Plugin 的使用
通过 SSH Agent Plugin 我们可以提供一个SSH credentials
去进行构建,步骤如下:
1. 安装 SSH Agent Plugin
2. 添加一个凭证
在 Jenkins 主页面有个凭据
的菜单,点进去可以新增一个凭据
然后我们选择SSH Username with private key
,依次填入表单信息。
- ID:该凭证的唯一标识,最好不填让系统自动生成
- Description:描述很重要,比如该凭证是用于登陆到哪个服务器
- Username:凭证的使用者,默认是 jenkins
- Private Key:连接到目标服务器的 private ssh key
创建完毕后,在凭据界面我们会看到新生成的凭据
3. 在 Jenkinsfile 中使用
接下来,我们就要在Jenkinsfile
文件中利用SSH Agent Plugin
来使用该凭证了。这个插件比较奇怪的地方是在插件的自述文件以及 github 的 README 中都没写到怎么去使用。最后倒是在 pipeline 的教程中找到了有关于它的使用。
node {
sshagent (credentials: ['deploy-dev']) {
sh 'ssh -o StrictHostKeyChecking=no -l cloudbees 192.168.1.106 uname -a'
}
}
这个是脚本式流水线的写法,在声明式流水线中也是一样的,只不过是写在steps
里面。deploy-dev
就是前面我们生成的Credential Id
steps {
sshagent (credentials: ['deploy-dev']) {
sh 'ssh -o StrictHostKeyChecking=no -l cloudbees 192.168.1.106 uname -a'
}
}
StrictHostKeyChecking
在上面的sh
语句中,我们发现一个很重要的参数StrictHostKeyChecking
。之前没有使用SSH Agent Plugin
的一个很重要原因就是不知道需要加上这个参数,导致直接连接的时候会被拒绝。那么这个参数的作用是什么呢,下面我们来讲解一下。
SSH 公钥检查
在使用 SSH 连接到远程主机的时候,会检查主机的公钥。如果是第一次连接该主机,会显示该主机的公钥摘要,提示用户是否信任该主机。我们需要输入yes
才可以连接到远程主机,并且会把该主机的公钥追加到~/.ssh/known_hosts
文件中。当再次连接到该主机时,就不会再提示该问题了。
The authenticity of host '192.168.210.128 (192.168.210.128)' can't be established.
ECDSA key fingerprint is SHA256:NWbwTrGB+hWDGVd8kDaZXyvZybruyGDP848ejoHTKUU.
Are you sure you want to continue connecting (yes/no)?
这样会导致一个问题,如果我们用 Jenkins 跑自动化任务,是没有输入yes
这个过程的,任务会因此中断。所以我们需要做到连接新主机时,不进行公钥确认。
连接新主机,不进行公钥确认
我们上面提到的StrictHostKeyChecking
配置就可以实现当第一次连接到主机时,自动接受新的公钥。它有两种使用方式:
- 一种就是修改
ssh
的配置文件:/etc/ssh/ssh_config
或~/.ssh/config
,在里面加入下面的语句:
Host *
StrictHostKeyChecking no
我们之前脚本的这句话就是为了达到这个目的
echo "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
- 另一种就是在
ssh
的命令中使用-o
参数
ssh -o StrictHostKeyChecking=no root@192.168.210.128 "ls -l"
rsync 中如何设置 StrictHostKeyChecking
在上面的脚本中,我们还用到了 rsync 来做一些文件的同步,它也需在命令中登陆到远程服务器,同样会有公钥确认的问题。
虽然它的参数列表里面并没有指定StrictHostKeyChecking=no
的参数,但是它提供了一个-e
参数,可以指定所要使用的远程 shell 程序,默认为 ssh。
所以我们的命令可以这样来写:
rsync -rvRe "ssh -o StrictHostKeyChecking=no" ./ root@192.168.210.128:/data/web/
参考:
1.Jenkins设置SSH免登录访问远程服务器
2.ssh StrictHostKeyChecking
3.rsync(一):基本命令和用法