问题:
在将 Jenkinsfile 中声明的变量传递给sh
ssh 并在远程主机上执行的命令时,变量内容不会保留在远程主机上。
内置的 Jenkins 变量在本地和远程主机上都能很好地保留。我定义的变量在本地可以正常工作,但无法在远程主机上转换。
虽然这个问题引用了 Docker,但实际上是 100% 基于 Jenkins 管道的,因为它可以应用于任何有或没有 Docker 的示例。
背景:
我正在尝试根据当前构建标签动态创建一个图像名称并将该名称放入变量中。
然后我将该变量传递给sh
远程 Docker 主机的步骤并使用定义的名称运行构建步骤。
Jenkinsfile 适用部分的片段...
// The below stage just echo's out some stuff into a file dockerimgname.jenkins.out
stage ('Construct Img name') {
sh '''echo ${BUILD_TAG} | awk '{print tolower($0)}' | sed 's/jenkins-//' > dockerimgname.jenkins.out'''
}
// This stage reads that file from previous stage and puts the value into variable.
// The variable is echo'd locally which works perfectly. Then ssh is called to execute command on remote host. That's where the variable value doesn't work.
stage ('Build Target Container') {
def jobBaseName = readFile 'dockerimgname.jenkins.out'
echo "${jobBaseName}"
sh 'ssh -i ~/ssh_keys/key.key user@somehost "cd /dockerdata/build/${BUILD_TAG} && docker build -t localrepo/${jobBaseName}:${BUILD_NUMBER} ."'
}
通常我会假设它没有变量,因为它是远程主机...然而奇怪的是,它在远程主机上转换${BUILD_NUMBER}
并${BUILD_TAG}
正常工作。为什么不行${jobBaseName}
?(它在远程主机上显示为空/null)。
答案1
由于不能保证各个阶段将在同一个执行器节点上运行(除非您将各个阶段包装在同一个node
块中),因此使用文件在阶段之间共享信息将不可靠。相反,请使用变量:
def jobBaseName
stage ('Construct Img name') {
jobBaseName = sh(
script: "echo ${BUILD_TAG} | awk '{print tolower($0)}' | sed 's/jenkins-//'",
returnStdout: true,
)
}
stage ('Build Target Container') {
sh "ssh -i ~/ssh_keys/key.key user@somehost 'cd /dockerdata/build/${BUILD_TAG} && docker build -t localrepo/${jobBaseName}:${BUILD_NUMBER} .'"
}
顺便说一句,我还建议使用sshAgent
Jenkins 的内置凭证存储来管理 SSH 密钥,而不是手动将标志传递-i
给 SSH。