如何在Jenkins sshCommand插件中使用Jenkins变量?
我通过Maven构建war包,并用Jenkins的ssh Publisher插件将构建产物发送到测试服务器,以下代码运行正常,生成的war文件名包含VERSION和BUILD_NUMBER变量:
stage('Deploy develop build to Test Server') { when { branch 'develop' } steps { // sends war file to test_server dir("${WORKSPACE}/ag.mycompany.feature/target/") { sshPublisher( alwaysPublishFromMaster: true, continueOnError: false, failOnError: true, publishers: [ sshPublisherDesc( configName: "test_server", transfers: [sshTransfer(sourceFiles: "vc-admin_${VERSION}_${BUILD_NUMBER}_dev.war", remoteDirectory: '/wars/main_vc_admin/develop')], verbose: true ) ] ) } } }
接下来我尝试在远程服务器中复制该文件到其他目录,并通过docker-compose构建Docker镜像。通过withCredentials可以正常连接远程服务器,测试sudo命令(如docker ps)也能正常运行,但无法将VERSION、BUILD_NUMBER等Jenkins变量传递给sshCommand。另外,我看到网上的示例都在script{...}块中使用withCredentials和sshPublisher,所以我在声明式流水线中也用了script块,但不知道如何在声明式流水线中创建远程变量,相关代码如下:
stage("build docker containers") { when { branch 'develop' } steps { script{ withCredentials([sshUserPrivateKey(credentialsId: 'test_server', keyFileVariable: 'test_user', passphraseVariable: '', usernameVariable: 'test_user')]) { // code block def remote = [ : ] remote.name = "MY_TEST_SERVER" remote.host = "1.1.1.1" remote.user = "user" remote.password = "pass" remote.allowAnyHosts = true remote.identityFile = test_user remote.pty = true sshCommand remote: remote, command="cp /home/user/wars/main_vc_admin/develop/vc-admin_${VERSION}_${BUILD_NUMBER}_dev.war /home/user/main-vc-deployment/backend/vc-admin.war" sshCommand remote: remote, sudo: true, command: "docker-compose --file /home/user/main-vc-deployment build && docker-compose --file /home/user/main-vc-deployment run -d" } } } }
请问有什么方法可以将这些Jenkins变量传递给sshCommand?
有几种可靠的方式可以将Jenkins流水线中的变量传递给远程服务器的sshCommand:
1. 利用Groovy双引号字符串插值
Groovy的双引号字符串会自动解析内部的变量,你当前的写法本身是可行的,但要确保:
VERSION和BUILD_NUMBER在当前流水线作用域内可访问(比如BUILD_NUMBER是Jenkins内置全局变量,VERSION需提前通过readMavenPom等步骤从pom.xml读取并赋值)- 命令字符串用双引号包裹,确保Groovy完成变量插值后再发送到远程服务器
示例:
sshCommand remote: remote, command: "cp /home/user/wars/main_vc_admin/develop/vc-admin_${VERSION}_${BUILD_NUMBER}_dev.war /home/user/main-vc-deployment/backend/vc-admin.war"
2. 传递为远程环境变量
先将Jenkins变量导出为远程服务器的环境变量,后续命令直接引用这些变量,适合需要多次使用变量的场景:
// 先在远程会话中导出变量 sshCommand remote: remote, command: "export JENKINS_VERSION=${VERSION} && export JENKINS_BUILD=${BUILD_NUMBER}" // 远程命令中用\${}避免Groovy提前插值,让远程shell解析变量 sshCommand remote: remote, command: "cp /home/user/wars/main_vc_admin/develop/vc-admin_\${JENKINS_VERSION}_\${JENKINS_BUILD}_dev.war /home/user/main-vc-deployment/backend/vc-admin.war"
3. 单引号字符串拼接
如果担心双引号的插值冲突,可以用单引号包裹命令主体,再通过字符串拼接插入Jenkins变量:
sshCommand remote: remote, command: 'cp /home/user/wars/main_vc_admin/develop/vc-admin_' + VERSION + '_' + BUILD_NUMBER + '_dev.war /home/user/main-vc-deployment/backend/vc-admin.war'
额外说明:声明式流水线中的远程变量
你在script块中定义remote变量的方式是正确的——声明式流水线中所有脚本式逻辑都需要放在script块内。另外注意不要硬编码密码,建议通过withCredentials安全获取:
withCredentials([ sshUserPrivateKey(credentialsId: 'test_server', keyFileVariable: 'TEST_KEY_FILE', usernameVariable: 'TEST_USER'), string(credentialsId: 'test_server_password', variable: 'TEST_PWD') ]) { def remote = [ : ] remote.name = "MY_TEST_SERVER" remote.host = "1.1.1.1" remote.user = TEST_USER remote.password = TEST_PWD remote.allowAnyHosts = true remote.identityFile = TEST_KEY_FILE remote.pty = true // 后续执行sshCommand }
内容的提问来源于stack exchange,提问作者senko

