らくとん倶楽部
ラクトンC10(γ-デカラクトン)とラクトンC11(γ-ウンデカラクトン)の香りに魅了された日々の備忘録

【Jenkins Declarative Pipeline】並列処理(パラレル処理)の実装方法

【Jenkins Declarative Pipeline】並列処理(パラレル処理)の実装方法

Jenkinsでは如何に処理を高速化するかがひとつの成功のカギであり、高速化には処理の並列化が極めて有効です。並列化できるところはどんどん並列化していきましょう。

ここではJenkinsのジョブ実装方式のひとつDeclarative Pipelineにおける並列処理の記述方法を説明します。また、Declarative Pipelineの「後処理」を実現する「postセクション」において、並列処理が利用できない問題を明らかにし、「postセクション」を使用せずに並列処理を実現した「後処理」の実装案を提案します。

Jenkins Declarative Pipelineにおける並列処理の記述方法

3つ並列プロセスから構成させるプロセスAと2つの並列プロセスからなるプロセスBを作成するとします。図で表すとこんな感じです。ちなみにこの図はJenkinsの新しいGUIであるBlue OceanのPipeline表示画面から持ってきました。

並行化した処理をBlue Oceanで見た場合

並行させたい処理をstageセクションとして定義し、それをparallelセクションで囲めばできあがりです。

pipeline {
    agent any
    stages {
        stage('Process A') {
            parallel {
                stage('Process A1') {
                    steps {
                        // ここに並列処理A1を記述します
                        sleep 5
                    }
                }
                stage('Process A2') {
                    steps {
                        // ここに並列処理A2を記述します
                        sleep 5
                    }
                }
                stage('Process A3') {
                    steps {
                        // ここに並列処理A3を記述します
                        sleep 5
                    }
                }
            }
        }
        stage('Process B') {
            parallel {
                stage('Process B1') {
                    steps {
                        // ここに並列処理B1を記述します
                        sleep 5
                    }
                }
                stage('Process B2') {
                    steps {
                        // ここに並列処理B2を記述します
                        sleep 5
                    }
                }
            }
        }
    }
}

簡単ですね。これをStage Viewで見ると以下のように各処理がシーケンシャルに表示され、非常に見ずらいです。処理が並行化されているかどうかはここからは伺い知る事は残念ながら出来ません。

並行化した処理をStage Viewで見た場合

これが、Blue Oceanだとご覧の通り。

並行化した処理をBlue Oceanで見た場合

これはわかりやすいです。さらにこのBlue Oceanだと、どこの処理が実際に実行中なのかが一発でわかるようになっています。実行中の処理は青のリングがクルクル回って表示されています。

実行中の処理をBlue Oceanで見た場合

Jenkins Declarative Pipelineにおける後処理はpostセクションに記述

Jenkins Declarative Pipelineにはpostセクションという非常に強力で便利な記述方法があります。postセクションに記述した処理は、前段のStageセクションに記述した処理の成功・失敗にかかわらず実行されるので後処理を記述するのに最適です。もう少し正確に書けば、postセクションの中に以下のサブセクションを書く事で自由に後処理を制御することが出来ます。

  • always
    前回の結果や今回の結果に関わらず常に実行される
  • changed
    前回の結果と今回の結果が異なる時に実行される
  • fixed
    前回の結果がFAILURE・UNSTABLEで、今回の結果がSUCCESSだった場合のみ実行される
  • regression
    前回の結果がSUCESSで、今回の結果がFAILURE・UNSTABLE・ABORTEDだった場合のみ実行される
  • aborted
    今回の結果がABORTED(手動による中断)だった場合のみ実行される
  • failure
    今回の結果がFAILUREだった場合のみ実行される
  • success
    今回の結果がSUCCESSだった場合のみ実行される
  • unstable
    今回の結果がUNSTABLEだった場合のみ実行される
  • cleanup
    ビルドの状態に関わらず、上記セクションの全てが評価(実施)された後に実行される
pipeline {
    agent any
    stages {
        stage('Process A') {
            parallel {
                stage('Process A1') {
                    steps {
                        // ここに並列処理A1を記述します
                        sleep 5
                    }
                }
                stage('Process A2') {
                    steps {
                        // ここに並列処理A2を記述します
                        sleep 5
                    }
                }
                stage('Process A3') {
                    steps {
                        // ここに並列処理A3を記述します
                        sleep 5
                    }
                }
            }
        }
    }
    post {
        always {
            // ここに後処理Bを記述します
            sleep 5
        }
        failure {
            // ここに後処理Cを記述します
            sleep 5
        }
    }
}

よくサンプルとしてあげられる用法として、changedまたはfailureセクションにメール送信の処理を記述してビルドの結果を通知するといったものがあります。

    post {
        failure {
            mail to: "username@domain",
                subject: "${env.JOB_NAME} #${env.BUILD_NUMBER} [FAILURE]",
                body: "Build URL: ${env.BUILD_URL}\n\n"
        }
    }

このpostセクションはStage Viewでは「Declarative: Post Actions」として表示されます。

Stage ViewにおけるPostセクションの見え方

一方Blue Oceanではpostセクションは一切表示されません。postセクション実行中は時計だけが進んでいくように見えます。

Blue OceanにおけるPostセクションの見え方

ところで、後処理にはどのような処理を定義しますか?Jenkinsで評価しようとしているシステムによって当然ながら異なりますが、一つのシステムが複数のサブシステムで構成されているような場合、以下のような処理を後処理として定義するのが典型的です。

  • サブシステムの停止
  • サブシステムのログ収集

n個のサブシステムがあれば、n個分のサブシステムの停止処理、n個分のログ収集処理を実施しなければなりません。停止処理に10秒、ログ収集に30秒かかったとして、これをシーケンシャルに実施すれば(10+30)×n秒もかかってしまいます。n=5の場合だと実に200秒、3分20秒です。これを並列処理させれば40秒で済むのですから、こういった後処理ほど並列処理が有効なものは無いでしょう。

ではさっそくpostセクションに記述した後処理を並列化させましょう‥‥と言いたいところですが、実はそう簡単にはいきません。

Jenkins Declarative Pipelineにおけるpostセクションに並列処理は書けない

postセクションに記述する後処理ほど並列処理が適した処理は無いにもかかわらず、postセクション内にparallelセクションを用いた並列処理を記述する事は出来ません。もしかしたら今後のJenkinsのバージョンアップでサポートされるようになるかもしれませんが、現時点(Ver2.124)ではpostセクション内にparallelセクションを書くと怒られてしまいます。

Jenkins Declarative Pipelineにおける後処理を並列処理にしたい場合

そこで後処理を通常のstageとして記述してしまいましょう。

後処理を通常のstageとして記述した場合

普通にこのように後処理Bを定義すると、処理Aでなんらかの異常が発生しFAILUREとなった場合や、手動で処理を中断しABORTEDとなった場合、「Stage 'Process B' skipped due to earlier failure(s)」と出て後処理B(B1/B2)は実行されません。

そこで処理Aの異常(例外)をtry・catchで捕捉する事にします。try・catchはDeclarative Pipelineでサポートされているわけではなく、Declarative Pipelineの一世代前のScripted Pipelineでサポートされていた記述方法です。しかしながら、Declarative Pipelineではscriptセクションで囲んだ範囲であれば従来のScripted Pipelineの記法がそのまま使用することが出来ます。気づいたらscriptセクションだらけで、Declarative Pipelineと言いつつ実体はScripted Pipelineとなっているケースも多々あるようですが、そこはあまり気にせず、実現したい事が出来れば良しということで、実装を進めていきましょう。

なお、try・catchで異常(例外)を捕捉してしまうと、Jenkinsが異常に気付く事が出来ずに、ビルドの実行結果が常にSUCCESSになってしまいます。そこで、異常(例外)を捕捉したら手動で「currentBuild.result = 'FAILURE'」としておきます。

pipeline {
    agent any
    stages {
        stage('Process A') {
            steps {
                script {
                    try {
                        // ここに処理Aを記述します
                        sleep 5
                    } catch (Exception e) {
                        currentBuild.result = 'FAILURE'
                    }
                }
            }
        }
        stage('Post Process B') {
            parallel {
                stage('Post Process B1') {
                    steps {
                        // ここに後処理B1を記述します
                        sleep 5
                    }
                }
                stage('Post Process B2') {
                    steps {
                        // ここに後処理B2を記述します
                        sleep 5
                    }
                }
            }
        }
    }
}

この実装方法の欠点

いい事尽くめに見えるこの後処理実装方法ですが、ひとつ欠点があります。それは処理を手動で中止しABORTED状態になった時、Stage Viewでは成功したように見えてしまう点です。本来は以下の画面のように、処理Aが中断により失敗して後処理Bが実行されたようなStage Viewとなるのが望ましいのですが、

処理を中止した場合のStage View

try・catchで異常(例外)を捕捉すると、処理Aも成功を意味する緑色で表示されてしまいます。でも安心して下さい。画面左側のビルドステータスやBlue Oceanでは正しく中断を意味するグレー色で表示されるので、こちらを参照すれば間違える事は無いでしょう。そもそもJenkinsの成否をStage View画面で判断することは皆さんしないと思うので、あまり影響は無いとは思いますが、一応念のため。ちなみに処理AにおいてABORTEDではなくFAILUREになった場合はこれまでと同様、ちゃんと赤く表示されます。

継続的インテグレーションに欠かせないツールであるJenkins。その導入から運用管理までを解説した定番書として大好評の『Jenkins実践入門』が、ついに2系に対応しました。生みの親である川口耕介氏監修のもと、近年の開発環境の変化に合わせて内容を一新。インストールなどの基本から、JUnitによるテストといった内容はもちろんのこと、さまざまなソースコード管理システムとの連携やおすすめプラグインの紹介、さらには認定試験についても説明します。チームの一員として上手に迎えるための実開発のポイントがわかります。
Amazonで購入 楽天で購入
Amazonで購入 楽天で購入
らくとん
作成日 2018年05月24日 23時12分
更新日 2019年04月25日 00時23分
6535文字
Twitter Facebook はてなブックマーク Pocket
■ 関連記事
らくとん倶楽部らくとん倶楽部
Author: らくとん
Jenkinsのコンソール出力はデフォルト状態では「色の無い世界」で全く味気がありません。このコンソール出力に様々な色を付けたり、太字にしたり、色を反転させたりと非常にカラフルにしてコンソール出力の視...