繁体   English   中英

如何防止相同类型的两个管道 jenkins 作业在同一节点上并行运行?

[英]How do I prevent two pipeline jenkins jobs of the same type to run in parallel on the same node?

我不想让相同类型(相同存储库)的两个作业在同一个节点上并行运行。

如何在 Jenkinsfile 中使用 groovy 来做到这一点?

https://stackoverflow.com/a/43963315/6839445中提供的答案已弃用。

当前禁用并发构建的方法是设置选项:

options { disableConcurrentBuilds() }

详细说明可在此处获得: https ://jenkins.io/doc/book/pipeline/syntax/#options

你得到了 disableConcurrentBuilds 属性:

properties properties: [
  ...
  disableConcurrentBuilds(),
  ...
]

然后工作将等待较旧的先完成

在声明性管道语法中使用选项块的示例:

pipeline {

  options { 
    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/

我认为解决这个问题的方法不止一种。

管道

  • 按照其他答案中的建议,使用最新版本的可锁定资源插件及其lock步骤。
  • 如果构建相同的项目:
    • Execute concurrent builds if necessary
  • 如果构建不同的项目:
    • 为每个项目设置不同的nodelabel

詹金斯

  • 将节点的执行者数量限制为1

插件

Throttle Concurrent Builds Plugin ”现在支持从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')
}

从管道阶段视图中,您将能够欣赏到这一点:

在此处输入图像描述

但是,请注意,这仅适用于throttle块内的node块。 我确实有其他管道,我首先分配一个节点,然后做一些不需要节流的工作,然后做一些需要节流的工作。

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 作业,而不是维护所有声明性/常规的汤。 不幸的是,这意味着每个管道构建占用 2+ 个执行器插槽(一个用于管道脚本,另一个用于触发的作业),因此死锁的危险变得非常真实。

我到处寻找解决该困境的方法,而disableConcurrentBuilds()只会阻止同一个作业(分支)运行两次。 它不会使不同分支的管道构建排队等待,而不是占用宝贵的执行器插槽。

对我们来说,一个 hacky(但令人惊讶的优雅)解决方案是将主节点的执行程序限制为 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”插件支持 Pipeline之前,一个解决方案是使用您的工作所需的标签有效地运行 master 的一个 executor。

为此,请在 Jenkins 中创建一个新节点,例如连接到 localhost 的 SSH 节点。 您还可以根据您的设置使用命令选项来运行 slave.jar/swarm.jar。 给节点一个执行者和一个像“resource-foo”这样的标签,并给你的工作这个标签。 现在一次只能运行一个标签为“resource-foo”的作业,因为只有一个带有该标签的执行者。 如果您将节点设置为尽可能多地使用(默认)并将主执行器的数量减少一个,那么它的行为应该完全符合预期,而不会更改总执行器。

转到节点配置并将执行者数量属性设置为 1。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM