ノード当たりのJenkinsパイプラインの停止


それは、ジェンキンズの中断パイプライン仕事が壊れていることがわかります.少なくとも、ノードごとに実行されるパイプラインジョブの数を制限することはできませんthrottling plugin , にもかかわらず、その機能はフリースタイルの仕事のために存在します.代わりに、我々は使用して周りの作品を設定することができますlockable resources plugin .
まず最初に、ジェンキンズに対するthrottlingとロックの違いについて話しましょう.実用性のために2つのことの間の概念的な違いを理解するのはいつも良いことです.

  • ロックは、ジョブがジェンキンズの外部リソースを排他的に使用する必要がある場合に使用されます.ジョブは、そのリソースにロックをかける.ジョブがロックを解除するまで、同じリソースを使用する必要がある他のジョブがブロックされます.リソースはグローバルに定義されているので、すべてのJenkinsエージェントは同じリソースプールにアクセスできます.

  • RumttlingはJenkins自体で同じ(または同様の)ジョブの同時実行を制限するために使用されます.解凍設定はグローバルに、またはエージェントごとに適用することができます.したがって、各エージェントが個別に実行することができない特定のジョブの数を制限することができます.
  • どちらの戦略も同時に実行できるジョブ(またはジョブのカテゴリー)のコピー数を制限します.彼らはどのように使用することができますが重複して自然に多くのです.制限が評価され適用される方法には、いくつかの低いレベルの違いがありますが、重要な概念的な違いは以下の通りです.

  • 絞られたジョブはジェンキンズ自身のリソースでスケールできます.

  • 外部リソースとロックジョブのスケール.
  • 私が1つのデータベースサーバだけを持っているならば、より多くのジェンキンズエージェントを加えることは私により多くの仕事を走らせません;これはロックの場合です.私が直接1つのデータベースを各々のJenkinsエージェントにインストールするならば、より多くのエージェントを加えることは私により多くの仕事を走らせます;これは絞りの仕事です.
    問題は以下の通りです:ノードあたりのスロットリングは、実際にはパイプラインジョブのために動作しません.オプションはJenkins UIに存在しますが、実際には何もしません.があるan open ticket 興味があれば、それについて.I even tried opening a PR to fix it , しかし、私が試した実装では、未解決のエッジケースがあり、マルチブランチパイプラインでは全く動作しません.
    私が解決した回避策は、手動でロック可能なリソースをエージェントの数でスケールするように強制します.私はこれがちょうど回避策であると考えます、なぜならば、それは彼らが設計されない何かをするためにロックを乱用しているので、より脆弱で、私の側のより多くのメンテナンスを必要としています.しかし、少なくともそれは動作します.
    私の目標は、ノード上で一度に2を実行するのに異常に高いメモリ要件でジョブを制限することです.ノードはすぐに8“普通”のジョブを実行することができるので、それは執行者の数を下げる価値がない.私にできることは、ノードごとに2つのロック可能なリソースを定義することです.マスターノードと1つのエージェントがあれば、4つのロック可能なリソースを意味します.
    リソースリソース名
    高記憶マスターマスター
    高記憶マスターマスター
    高記憶について
    高記憶について
    重要な部分は、1つのノードで、すべての私の「高いメモリスロット」が同じラベルを持っているということです.この制限の対象となるパイプラインジョブでは、そのラベルに一致するリソースを要求します.
    String runningNode = env.NODE_NAME ?: 'master'
    lock(label: "high-memory-${runningNode}", quantity: 1) { ... }
    
    The quantity Jenkinsがそのラベルですべてのリソースをロックするのを防ぐために引数が必要です.以来env.NODE_NAME は、node{} 環境、私たちがノード環境にいないなら、私たちが「マスター」またはコントローラノードで動いていると仮定するためにフォールバックを設定します.(私が知っている限りでは、この仮定は本当ですが、パイプラインがどのようにして確実に実行されるかについては十分に知りません.このデザインは、あるならnode{} ブロックしてくださいlock{} ブロック.
    これには非常に重要な欠点があります.
  • 私の場合、メモリ機能が高いのはグローバルな共有ライブラリの一部であることが幸運です.ですから、このロックを一度コード化することができます.そうでなければ、この制限を尊重するために、個々のジョブがこのロックを実装することを保証しなければなりません.
  • 同様に、この実装はマスターノードの名前を仮定します.これが多くの仕事の間で複製されるならば、それは変化する痛みです.現在のノードを得るより堅牢な方法があるかもしれませんが、私が見つけたものはすべて、コントローラのための空のストリングを返します.
  • ある場合、これは簡単に中断することができますnode{} 内部のブロックlock{} , 以来、あなたの仕事が実際に実行されている場所とは異なるノード上のスロットのいずれかをロックを終了する可能性があります.
  • ジョブがロックを要求するために実行を開始しなければならないので、リソースを解放するのを待つ間、どんな待機している仕事も実行者を占有していなくて座っています.
  • 新しいエージェントが追加されると、手動でこれらの“throttled”ジョブの新しいスロットを追加する設定を更新する必要があります.
  • それは、私の特定のセットでこれらの欠点のどれも重要な懸念であるということです.throttlesは、ノードごとに動作した場合、これらのほとんどを避けることができました.
  • RotttlesはJenkinsfileの内部ではなくジョブ定義自体の一部として定義できます.管理者として、複数のチームが共有するサーバ上のすべてのジョブのスロットをより簡単に調整することができます.
  • ジョブのために定義されたthrottlesは、ジョブが起動しないようにすることができます.
  • 新しいエージェントが追加されると、設定された変更は必要ありません.なぜなら、throttlesは、新しいエージェントが特定の数のthrottledジョブを取ることができることを自動的に知っているからです.
  • スロットの代わりにロックを使用する1つの良い利点は、独立して各ノードでどのように多くのスロットが利用できるかを調整できることです私が欲しいならば、私はもう一つのノードと4つのスロットで2つのスロットを定めることができます.また、特定のエージェントにロック可能なリソースが存在するかどうかを確認できるヘルパーメソッドを記述することもできます.
    import jenkins.model.Jenkins
    private Boolean isNodeThrottled(String nodeName) {
        def lockable = Jenkins.getInstance().getPlugin('lockable-resources')
        if (lockable != null) {
            def limiter = lockable.getResources().find {
                it =~ "high-memory-${nodeName}-.*"
            }
            return limiter != null
        }
        return false
    }
    
    この関数は、上記のテーブルで設定した名前付けパターンに一致するリソースがあるかどうかを調べます.ない場合は、false このノードがスローされないことを示す.これは8つの実行者を持つエージェントに対して8つの別々のリソースを定義することから私たちを救う.私の高いメモリ例では、効果的に無限のメモリを持つノードがあれば、これは意味をなすだけです.
    ロックと停止の概念的な違いが何であるかに関係なく、正しいアプローチが何であるかについて決定するために重くされる必要がある賛否両論がたくさんあります.スロットのプラグインは、実際には、パイプラインを停止するためのいくつかの機能を持っているので、それはあなたの特定のユースケースのためのスロットはまだ正しい方法であることがあります.私にとって、lockableなリソースとしてスロットを定義することは、私が必要とする機能を得る方法でした.