IT story

동일한 유형의 두 파이프 라인 젠킨스 작업이 동일한 노드에서 병렬로 실행되는 것을 어떻게 방지합니까?

hot-time 2021. 1. 5. 19:15
반응형

동일한 유형의 두 파이프 라인 젠킨스 작업이 동일한 노드에서 병렬로 실행되는 것을 어떻게 방지합니까?


동일한 유형 (동일한 저장소)의 두 작업이 동일한 노드에서 병렬로 실행되지 않도록하고 싶습니다.

Jenkinsfile 내부에서 groovy를 사용하여 어떻게 할 수 있습니까?


disableConcurrentBuilds 속성에 있습니다.

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

그런 다음 작업은 이전 작업이 먼저 완료되기를 기다립니다.


https://stackoverflow.com/a/43963315/6839445에 제공된 답변 은 더 이상 사용되지 않습니다.

동시 빌드를 비활성화하는 현재 방법은 옵션을 설정하는 것입니다.

options { disableConcurrentBuilds() }

자세한 설명은 https://jenkins.io/doc/book/pipeline/syntax/#options에서 확인할 수 있습니다.


또 다른 방법은 Lockable Resources 플러그인을 사용하는 것입니다 : 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/


이 문제에 대한 접근 방식은 하나 이상이라고 생각합니다.

관로

  • 다른 답변에서 제안한 것처럼 최신 버전의 Lockable Resources Plugin 및 해당 lock단계를 사용하십시오 .
  • 동일한 프로젝트를 빌드하는 경우 :
    • 선택을 취소하십시오 Execute concurrent builds if necessary.
  • 다른 프로젝트를 빌드하는 경우 :
    • 다른 설정 node또는 label각 프로젝트에 대해.

젠킨스

  • 노드의 실행기 수를 1?

플러그인


선언적 파이프 라인 구문에서 옵션 블록을 사용하는 예 :

pipeline {

  options { 
    disableConcurrentBuilds() 
  }

...
}

이제 " Throttle Concurrent Builds Plugin "은 throttle-concurrents-2.0. 이제 다음과 같이 할 수 있습니다.

// Fire me twice, one immediately after the other
// by double-clicking 'Build Now' or from a parallel step in another job.
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
    }
}

In this case the throttle step doesn't solve the problem because the throttle step is the one inside the node step and not the other way around. In this case the lock step is better suited for the task


Install Jenkins Lockable Resources Plugin.

In your pipeline script wrap the part in the lock block and give this lockable resource a name.

lock("test-server"){
    // your steps here
}

Use the name of whatever resource you are locking. In my experience its usually a test server or test database.


If you're like my team then you like having user-friendly parameterized Jenkins Jobs that pipeline scripts trigger in stages, instead of maintaining all that declarative/groovy soup. Unfortunately that means that each pipeline build takes up 2+ executor slots (one for the pipeline script and others for the triggered job(s)) so the danger of deadlock becomes very real.

I've looked everywhere for solutions to that dilemma, and disableConcurrentBuilds() only prevents the same job (branch) from running twice. It won't make pipeline builds for different branches queue up and wait instead of taking up precious executor slots.

A hacky (yet surprisingly elegant) solution for us was to limit the master node's executors to 1 and make the pipeline scripts stick to using it (and only it), then hook up a local slave agent to Jenkins in order to take care of all other jobs.


One of the options is to use Jenkins REST API. I researched for another options, but seems that this is only one available with pipelines functionality.

You should write script which polls Jenkins for info of current jobs running and check whether job of same type is running. To do this you should use Jenkins REST API, documentation you may find in the right bottom corner in your Jenkins page. Example script:

#!/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."

I've used bash here, but you may use any language. Then just call this script inside of your Jenkinsfile:

sh "./wait-for-tests.sh ${env.REMOTE_USER} ${env.REMOTE_TOKEN} ${env.BUILD_NUMBER}"

So it will wait until job completion (don't be confused with integration-test mentions, it's just job name).

Be also aware that in rare cases this script may cause deadlock when both jobs are waiting for each other, so you may want to implement some max retry policies here instead of infinite waiting.


Until the "Throttle Concurrent Builds" plugin has Pipeline support, a solution would be to effectively run one executor of the master with a label that your job requires.

이를 위해 Jenkins에 새 노드 (예 : localhost에 연결하는 SSH 노드)를 만듭니다. 설정에 따라 명령 옵션을 사용하여 slave.jar / swarm.jar을 실행할 수도 있습니다. 노드에 실행자 하나와 "resource-foo"와 같은 레이블을 지정하고 작업에도이 레이블을 지정하십시오. 이제 레이블 "resource-foo"의 작업은 한 번에 하나만 실행할 수 있습니다. 해당 레이블을 가진 실행자는 하나만 있기 때문입니다. 노드를 가능한 많이 사용하도록 설정하고 (기본값) 마스터 실행기 수를 하나씩 줄이면 전체 실행기를 변경하지 않고 원하는대로 정확하게 작동해야합니다.

참조 URL : https://stackoverflow.com/questions/36454130/how-do-i-prevent-two-pipeline-jenkins-jobs-of-the-same-type-to-run-in-parallel-o

반응형