我不想允许相同类型(相同存储库)的两个作业在同一节点上并行运行。
如何在Jenkinsfile中使用groovy做到这一点?
Answers:
https://stackoverflow.com/a/43963315/6839445中提供的答案已被弃用。
当前禁用并发构建的方法是设置选项:
options { disableConcurrentBuilds() }
此处提供了详细说明:https : //jenkins.io/doc/book/pipeline/syntax/#options
您获得了disableConcurrentBuilds属性:
properties properties: [
...
disableConcurrentBuilds(),
...
]
然后,工作将等待年长的人先完成
另一种方法是使用可锁定资源插件:https : //wiki.jenkins-ci.org/display/JENKINS/Lockable+Resources+Plugin
您可以根据需要定义锁(互斥锁),也可以将变量放在名称中。例如,防止多个作业在构建节点上同时使用编译器:
stage('Build') {
lock(resource: "compiler_${env.NODE_NAME}", inversePrecedence: true) {
milestone 1
sh "fastlane build_release"
}
}
因此,如果您想防止每个节点同时运行同一分支的多个作业,则可以执行以下操作
stage('Build') {
lock(resource: "lock_${env.NODE_NAME}_${env.BRANCH_NAME}", inversePrecedence: true) {
milestone 1
sh "fastlane build_release"
}
}
来自:https : //www.quernus.co.uk/2016/10/19/lockable-resources-jenkins-pipeline-builds/
inversePrecedence: true
创建时的含义是lock
什么?
我认为,解决此问题的方法不止一种。
lock
步骤。Execute concurrent builds if necessary
。node
或label
为每个项目。1
?Execute concurrent builds if necessary
从Jenkinsfile
?
自2004年以来,“节流并发构建插件”现在支持管道throttle-concurrents-2.0
。现在,您可以执行以下操作:
在下面对管道开火两次,一次又一次,然后您会看到。您可以通过双击“立即构建”或从parallel
另一个作业的步骤中调用它来手动执行此操作。
stage('pre'){
echo "I can run in parallel"
sleep(time: 10, unit:'SECONDS')
}
throttle(['my-throttle-category']) {
// Because only the node block is really throttled.
echo "I can also run in parallel"
node('some-node-label') {
echo "I can only run alone"
stage('work') {
echo "I also can only run alone"
sleep(time: 10, unit:'SECONDS')
}
}
}
stage('post') {
echo "I can run in parallel again"
// Let's wait enough for the next execution to catch
// up, just to illustrate.
sleep(time: 20, unit:'SECONDS')
}
从管道阶段视图,您将能够体会到这一点:
但是,请注意,这仅适用于node
块内的throttle
块。我确实有其他管道,首先分配一个节点,然后执行一些不需要节流的工作,然后再做一些需要节流的工作。
node('some-node-label') {
//do some concurrent work
//This WILL NOT work.
throttle(['my-throttle-category']) {
//do some non-concurrent work
}
}
在这种情况下,该throttle
步骤不能解决问题,因为该throttle
步骤是该node
步骤内部的步骤,而不是相反的步骤。在这种情况下,锁定步骤更适合任务
安装Jenkins可锁定资源插件。
在管道脚本中,将零件包装在锁块中,并为该可锁定资源命名。
lock("test-server"){
// your steps here
}
使用您要锁定的任何资源的名称。以我的经验,它通常是一个测试服务器或测试数据库。
如果您像我的团队一样,那么您会喜欢使用用户友好的参数化Jenkins Jobs,这些脚本会分阶段触发管道脚本,而不是保留所有声明性/常规的内容。不幸的是,这意味着每个管道构建占用2个以上的执行器插槽(一个用于管道脚本,另一个用于执行触发的作业),因此死锁的危险变得非常现实。
我到处都在寻找解决这个难题的方法,并且disableConcurrentBuilds()
只能防止同一作业(分支)运行两次。它不会使不同分支的管道构建排队等待,而不是占用宝贵的执行器插槽。
对我们来说,一个棘手的(但非常出奇的优雅)解决方案是将主节点的执行程序限制为1,并使流水线脚本坚持使用(并且仅使用),然后将本地从属代理连接到Jenkins,以便照顾所有的人其他工作。
一种选择是使用Jenkins REST API。我研究了另一种选择,但似乎这只是具有管道功能的一种。
您应该编写脚本以轮询Jenkins以获取当前正在运行的作业的信息,并检查是否正在运行相同类型的作业。为此,您应该使用Jenkins REST API,这些文档可以在Jenkins页面的右下角找到。示例脚本:
#!/usr/bin/env bash
# this script waits for integration test build finish
# usage: ./wait-for-tests.sh <jenkins_user_id> <jenkins_user_token_id>
jenkins_user=$1
jenkins_token=$2
build_number=$3
job_name="integration-tests"
branch="develop"
previous_build_number=build_number
let previous_build_number-=1
previous_job_status=$(curl -s http://${jenkins_user}:${jenkins_token}@jenkins.mycompany.com/job/mycompany/job/${job_name}/branch/${branch}/${previous_build_number}/api/json | jq -r '.result')
while [ "$previous_job_status" == "null" ];
do
previous_job_status=$(curl -s http://${jenkins_user}:${jenkins_token}@jenkins.mycompany.com/job/mycompany/job/${job_name}/branch/${branch}/${previous_build_number}/api/json | jq -r '.result')
echo "Waiting for tests completion"
sleep 10
done
echo "Seems that tests are finished."
我在这里使用过bash,但是您可以使用任何语言。然后只需在您的Jenkinsfile中调用此脚本:
sh "./wait-for-tests.sh ${env.REMOTE_USER} ${env.REMOTE_TOKEN} ${env.BUILD_NUMBER}"
因此它将等待作业完成(不要与集成测试提及相混淆,这只是作业名称)。
另请注意,在极少数情况下,当两个作业彼此等待时,此脚本可能会导致死锁,因此您可能希望在此处实施一些最大重试策略,而不是无限等待。
在“ Throttle Concurrent Builds”插件支持管道之前,一种解决方案是有效地运行具有您工作所需标签的主执行程序。
为此,请在Jenkins中创建一个新节点,例如连接到localhost的SSH节点。您也可以使用命令选项来运行slave.jar / swarm.jar,具体取决于您的设置。给该节点一个执行程序,并给它一个标签,例如“ resource-foo”,并给您的工作分配这个标签。现在一次只能执行一个标签为“ resource-foo”的作业,因为只有一个执行程序带有该标签。如果将节点设置为尽可能多地处于使用状态(默认值),并将主执行器的数量减少一个,则它的行为应与期望的完全相同,而不更改总执行器。