Jenkins如何在多个标签之间选择pipeline agent?
How does Jenkins choose a pipeline agent between multiple labels?
我有一个 Jenkins 管道,我想 运行 在 参数指定的代理或 master
上。实现这个的管道代码是:
pipeline {
agent { label "${params.agent} || master" }
...
}
我从以下帖子中推测,||
运算符需要在(双)引号内:
https://serverfault.com/questions/1074089/how-to-apply-multiple-labels-to-jenkins-nodes
当我运行这份工作时,似乎总是运行在master
。
当我在 agent
语句中切换 ${params.agent}
和 master
的顺序时,它似乎仍然总是 运行 on master
.
如果我从 agent
语句中删除“ || master
”,那么 params
指定代理上的作业 运行s。
问题: 我观察到 Jenkins“更喜欢”master
是巧合,还是语法有问题导致 Jenkins 默认为 master
?
有没有办法让 Jenkins 更喜欢 not-master 以便我可以测试 agent
语句的有效性?
h pipeline/job 有一个受信任的代理列表,更多的工作在代理上成功,代理位于列表的顶部,pipeline/agent 将从列表中选择顶部代理。
如果你的pipeline已经运行在master上好几次都成功了,即使你给另一个agent选择,pipeline总是先选择最信任的agent
所以,当 Jenkins 遇到这条线时
agent { label "${params.agent} || master" }
它将执行以下操作之一:
- 在与该标签匹配的节点之一上安排您的工作;或
- 卡住,直到有一个节点匹配该标签,或者直到中止。
关于选项 1,没有 gua运行tee 它会做一个 round-robin,一个 运行dom 选择,或者更喜欢一些节点而不是其他节点,等等. 实际上,当几个节点匹配时,Jenkins 会优先选择 运行 你过去的管道的节点。这是一个合理的行为——如果该节点上已经有一个工作区,一些操作(如 git checkout
)可能会发生得更快,从而节省时间。
关于选项 2,这也是一种合理的行为。我们实际上使用它来安排 non-existing 标签上的作业,同时操纵标签以生成匹配的标签。
所以,您的语法没有任何问题,Jenkins 的行为符合设计。
如果你想实现一些自定义规则——比如“总是尝试不同的节点”,或者“尽可能少地使用 master
”——你必须编写代码。
管道示例(注意我还没有检查过):
import hudson.model.Hudson
properties([
parameters([
string(name: 'DEPLOY_ON', defaultValue: 'node_name',
description: 'try to run on this node, or master'),
])
])
resulting_node_name = ''
pipeline {
agent { node { label 'master' } }
stages {
stage ('Do on master') {
steps {
script {
resulting_node_name = params.DEPLOY_ON
// note: this gets node by name, but you can get by label if you wish
def slave = Jenkins.instance.getNode(resulting_node_name)
if (slave == null) {
currentBuild.result = 'FAILURE'
}
def computer = slave.computer
if (computer == null || computer.getChannel() == null || slave.name != params.DEPLOY_ON) {
println "Something wrong with the slave object, setting master"
resulting_node_name = 'master'
}
printSlaveInfo(slave)
computer = null
slave = null
}
}
}
stage('Do on actual node') {
agent { node { label resulting_node_name } }
steps {
script {
println "Running on ${env.NODE_NAME}"
}
}
}
}
}
@NonCPS
def printSlaveInfo(slave) {
// some info that you can use to choose the least-busy, best-equipped, etc.
println('====================')
println('Name: ' + slave.name)
println('getLabelString: ' + slave.getLabelString())
println('getNumExectutors: ' + slave.getNumExecutors())
println('getRemoteFS: ' + slave.getRemoteFS())
println('getMode: ' + slave.getMode())
println('getRootPath: ' + slave.getRootPath())
println('getDescriptor: ' + slave.getDescriptor())
println('getComputer: ' + slave.getComputer())
def computer = slave.computer
println('\tcomputer.isAcceptingTasks: ' + computer.isAcceptingTasks())
println('\tcomputer.isLaunchSupported: ' + computer.isLaunchSupported())
println('\tcomputer.getConnectTime: ' + computer.getConnectTime())
println('\tcomputer.getDemandStartMilliseconds: ' + computer.getDemandStartMilliseconds())
println('\tcomputer.isOffline: ' + computer.isOffline())
println('\tcomputer.countBusy: ' + computer.countBusy())
println('\tcomputer.getLog: ' + computer.getLog())
println('\tcomputer.getBuilds: ' + computer.getBuilds())
println('====================')
}
我有一个 Jenkins 管道,我想 运行 在 参数指定的代理或 master
上。实现这个的管道代码是:
pipeline {
agent { label "${params.agent} || master" }
...
}
我从以下帖子中推测,||
运算符需要在(双)引号内:
https://serverfault.com/questions/1074089/how-to-apply-multiple-labels-to-jenkins-nodes
当我运行这份工作时,似乎总是运行在master
。
当我在 agent
语句中切换 ${params.agent}
和 master
的顺序时,它似乎仍然总是 运行 on master
.
如果我从 agent
语句中删除“ || master
”,那么 params
指定代理上的作业 运行s。
问题: 我观察到 Jenkins“更喜欢”master
是巧合,还是语法有问题导致 Jenkins 默认为 master
?
有没有办法让 Jenkins 更喜欢 not-master 以便我可以测试 agent
语句的有效性?
h pipeline/job 有一个受信任的代理列表,更多的工作在代理上成功,代理位于列表的顶部,pipeline/agent 将从列表中选择顶部代理。
如果你的pipeline已经运行在master上好几次都成功了,即使你给另一个agent选择,pipeline总是先选择最信任的agent
所以,当 Jenkins 遇到这条线时
agent { label "${params.agent} || master" }
它将执行以下操作之一:
- 在与该标签匹配的节点之一上安排您的工作;或
- 卡住,直到有一个节点匹配该标签,或者直到中止。
关于选项 1,没有 gua运行tee 它会做一个 round-robin,一个 运行dom 选择,或者更喜欢一些节点而不是其他节点,等等. 实际上,当几个节点匹配时,Jenkins 会优先选择 运行 你过去的管道的节点。这是一个合理的行为——如果该节点上已经有一个工作区,一些操作(如 git checkout
)可能会发生得更快,从而节省时间。
关于选项 2,这也是一种合理的行为。我们实际上使用它来安排 non-existing 标签上的作业,同时操纵标签以生成匹配的标签。
所以,您的语法没有任何问题,Jenkins 的行为符合设计。
如果你想实现一些自定义规则——比如“总是尝试不同的节点”,或者“尽可能少地使用 master
”——你必须编写代码。
管道示例(注意我还没有检查过):
import hudson.model.Hudson
properties([
parameters([
string(name: 'DEPLOY_ON', defaultValue: 'node_name',
description: 'try to run on this node, or master'),
])
])
resulting_node_name = ''
pipeline {
agent { node { label 'master' } }
stages {
stage ('Do on master') {
steps {
script {
resulting_node_name = params.DEPLOY_ON
// note: this gets node by name, but you can get by label if you wish
def slave = Jenkins.instance.getNode(resulting_node_name)
if (slave == null) {
currentBuild.result = 'FAILURE'
}
def computer = slave.computer
if (computer == null || computer.getChannel() == null || slave.name != params.DEPLOY_ON) {
println "Something wrong with the slave object, setting master"
resulting_node_name = 'master'
}
printSlaveInfo(slave)
computer = null
slave = null
}
}
}
stage('Do on actual node') {
agent { node { label resulting_node_name } }
steps {
script {
println "Running on ${env.NODE_NAME}"
}
}
}
}
}
@NonCPS
def printSlaveInfo(slave) {
// some info that you can use to choose the least-busy, best-equipped, etc.
println('====================')
println('Name: ' + slave.name)
println('getLabelString: ' + slave.getLabelString())
println('getNumExectutors: ' + slave.getNumExecutors())
println('getRemoteFS: ' + slave.getRemoteFS())
println('getMode: ' + slave.getMode())
println('getRootPath: ' + slave.getRootPath())
println('getDescriptor: ' + slave.getDescriptor())
println('getComputer: ' + slave.getComputer())
def computer = slave.computer
println('\tcomputer.isAcceptingTasks: ' + computer.isAcceptingTasks())
println('\tcomputer.isLaunchSupported: ' + computer.isLaunchSupported())
println('\tcomputer.getConnectTime: ' + computer.getConnectTime())
println('\tcomputer.getDemandStartMilliseconds: ' + computer.getDemandStartMilliseconds())
println('\tcomputer.isOffline: ' + computer.isOffline())
println('\tcomputer.countBusy: ' + computer.countBusy())
println('\tcomputer.getLog: ' + computer.getLog())
println('\tcomputer.getBuilds: ' + computer.getBuilds())
println('====================')
}