web-dev-qa-db-ja.com

同じタイプの2つのパイプラインジェンキンスジョブが同じノードで並行して実行されるのを防ぐにはどうすればよいですか?

同じタイプ(同じリポジトリ)の2つのジョブが同じノードで並行して実行されないようにしたいのです。

Jenkinsfile内でgroovyを使用してこれを行うにはどうすればよいですか?

55
sorin

DisableConcurrentBuildsプロパティに到達しました:

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

その後、ジョブは古いものが先に終了するのを待ちます

40
hypery2k

https://stackoverflow.com/a/43963315/6839445 で提供されている回答は非推奨です。

並行ビルドを無効にする現在の方法は、オプションを設定することです。

options { disableConcurrentBuilds() }

詳細な説明はここにあります: https://jenkins.io/doc/book/pipeline/syntax/#options

34
M0nt3c1t0

別の方法は、ロック可能なリソースプラグインを使用することです。 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/

29
Matt Hamilton

この問題に対するアプローチは複数あると思います。

パイプライン

  • 他の回答で提案されているように、最新バージョンの Lockable Resources Plugin およびそのlockステップを使用します。
  • 同じプロジェクトをビルドする場合:
    • Execute concurrent builds if necessaryのチェックを外します。
  • 異なるプロジェクトをビルドする場合:
    • プロジェクトごとに異なるnodeまたはlabelを設定します。

ジェンキンス

  • ノードのエグゼキューターの数を1に制限しますか?

プラグイン

13
luka5z

宣言的なパイプライン構文でオプションブロックを使用する例:

pipeline {

  options { 
    disableConcurrentBuilds() 
  }

...
}
12
Bryji

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')
}

パイプラインステージビューから、これに感謝することができます。

enter image description here

ただし、これは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ステップは問題を解決しません。この場合、 ロックステップ はタスクにより適しています

9
Mig82

Jenkinsのインストール ロック可能なリソースプラグイン

パイプラインスクリプトで、部分をロックブロックでラップし、このロック可能なリソースに名前を付けます。

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

ロックしているリソースの名前を使用します。私の経験では、通常はテストサーバーまたはテストデータベースです。

6
raitisd

あなたが私のチームのようであれば、宣言的/グルーヴィーなスープをすべて維持するのではなく、スクリプトを段階的にトリガーするユーザーフレンドリーなパラメーター化されたJenkins Jobsが好きです。残念ながら、各パイプラインビルドは2つ以上のエグゼキュータースロット(パイプラインスクリプト用とトリガーされたジョブ用)を占有するため、デッドロックの危険性が非常に大きくなります。

私はそのジレンマの解決策をどこでも探しましたが、disableConcurrentBuilds()は同じジョブ(ブランチ)が2回実行されるのを防ぐだけです。さまざまなブランチのパイプラインビルドを作成せず、貴重なエグゼキュータースロットを占有する代わりに待機します。

私たちにとってのハッキング(まだ驚くほどエレガントな)ソリューションは、マスターノードのエグゼキューターを1に制限し、パイプラインスクリプトがそれ(そしてそれだけ)を使用することに固執し、すべてを処理するためにローカルスレーブエージェントをJenkinsに接続することでした他の仕事。

4
JohannSig

オプションの1つは、Jenkins REST AP​​Iを使用することです。私は別のオプションを調査しましたが、これはパイプライン機能で利用可能なものの1つに過ぎないようです。

現在実行中のジョブの情報についてJenkinsをポーリングするスクリプトを作成し、同じタイプのジョブが実行されているかどうかを確認する必要があります。これを行うには、Jenkins REST AP​​I、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}"

そのため、ジョブが完了するまで待機します(統合テストの記述と混同しないでください。単なるジョブ名です)。

また、まれに、このスクリプトが両方のジョブが互いに待機しているときにデッドロックを引き起こす可能性があるため、無限待機の代わりにここで最大再試行ポリシーを実装することもできます。

2

「スロットルコンカレントビルド」プラグイン パイプラインサポート までは、解決策は、ジョブに必要なラベルを使用してマスターの1つのエグゼキューターを効果的に実行することです。

これを行うには、Jenkinsで新しいノードを作成します。たとえば、localhostに接続するSSHノードです。セットアップに応じて、コマンドオプションを使用してslave.jar/swarm.jarを実行することもできます。ノードに1つのエグゼキューターと「resource-foo」のようなラベルを付け、ジョブにもこのラベルを付けます。ラベル "resource-foo"のジョブは一度に1つしか実行できません。これは、そのラベルを持つエグゼキュータが1つしかないためです。ノードを可能な限り使用するように設定し(デフォルト)、マスターエグゼキューターの数を1つ減らすと、エグゼキューターの合計を変更することなく、希望どおりに正確に動作するはずです。

1
mrooney