Pipelineを利用するなら心に留めておくべきベストプラクティスがあります。次のリストは、Jenkinsプラグインをより効率的かつ効果的に利用するのに役立つ重要なベストプラクティス10個の概要です。
1. パイプライン定義をSCMに保存する
以前からJenkinsを使っているのであれば、おそらくFreestyleジョブを使っているのではないでしょうか。それは、Jenkins UI内でジョブを設定するのに慣れているということです。Pipelineジョブ内でパイプラインを定義することもできますが、実際はそうするべきではありません。なぜでしょうか。ジョブ定義をGitなどのSCMに保存するのがベストプラクティスだからです。ジョブ内にジョブ定義を保存した場合、予期しない副作用がある変更をジョブに加えてしまう可能性があります。ジョブ定義をSCMに保存し、開発フローとしてプルリクエストの使用を必須にすると、すべての変更の監査証跡を残すことができます。最近のGitプロバイダーを利用しているなら、変更を運用環境にマージする前に、拡張コメントを使用してチームの他のメンバーと議論することもできます。
ソースコードと同じリポジトリにJenkinsfileを配置することのもう一つの効能は、コードのメンテナーもコードのビルド、デリバリー、デプロイメントプロセスをメンテナンスできることです。
2 宣言的構文を使用してパイプライン定義を作成する
まず、過去の事実を述べます。スクリプト構文は2014年12月前後にリリースされました。2017年2月、宣言的構文が導入されました。宣言的構文がリリースされるまでは、スクリプト構文を使用するしかありませんでした。しかし、これ以降、マトリクスなど多数の新機能は宣言的構文でのみ提供されています。
3.共有ライブラリを利用する
WebページでインラインのJavaScriptを使用していたころを覚えていますか?宣言的パイプラインで”script”タグを使うようになったら、それはJavaScriptの場合と同じ道に向かっているという憂慮すべきサインです。”script”タグしか方法がないと判断したら、”script”タグを使うのではなく、共有ライブラリにカスタムステップを作成し、宣言的パイプラインの中でステップを使うべきです。
4.共有ライブラリを(間違った方法で)使わない
ちょっと、どういうことでしょうか。先ほど、共有ライブラリを使うべきだと言ったばかりなのに、今度は共有ライブラリをつかわないようにと言うのです。何があったのでしょうか。多くの人は共有ライブラリをプログラミングプロジェクトのように扱うようになります。ここに注意すべき点があります。スクリプト構文も宣言的構文も、CIタスクだけを実行するためのもので、汎用プログラミング言語としては意図されていません。Jenkinsコントローラーのパフォーマンスの問題は、元をたどれば、スクリプト構文および共有ライブラリの誤用で、すべての処理がエージェントではなくJenkinsコントローラー自体で実行されているために発生していることがよくあります。
5.宣言的構文+共有ライブラリを使う意味がない場合にだけスクリプト構文を使用する
ここまでで、スクリプト構文を使うのがこわくなってしまったかもしれません。それでいいのです。それが目論見でした。ただし、スクリプト構文が味方になってくれる状況もあります。例えば次のような場合です。ジョブの並列実行を最大化するため、エージェントとして利用できる可能性がある膨大な数のマシンにアクセスするジョブがあるとします。ただし、このジョブは最初にマシンが現在エージェントとして利用可能かどうかを確認しなければなりません。これを宣言的構文で行うのは不可能です。しかし、スクリプト構文でなら可能です。
Jenkinsパイプラインを作成する際の簡単な指針は次のとおりです。
- 常に宣言的構文から始めます。
- 宣言的構文で良くないことをし始めたら、つまりscriptタグを使うようになったら、共有ライブラリを導入します。
- 宣言的構文+共有ライブラリでだめなら、そこでスクリプト構文を選択します。
6.エージェント内でinputを使用しない
エージェント内のステージにinputステートメントを挿入することは可能ですが、間違いなくそうすべきではありません。
なぜでしょうか。input要素はパイプラインの実行を中断して承認を(自動であれ手動であれ)待ちます。当然、承認には時間がかかる場合があります。いっぽう、エージェントはワークスペースと負荷の高いJenkinsエグゼキューター(これは入力を待つ間保持しておくには貴重なリソースです)のロックを取得して保持します。ですから、inputはエージェントの外に記述しましょう。
pipeline { agent none stages { stage('Example Build') { agent { label "linux" } steps { sh 'echo Hello World' } } stage('Ready to Deploy') { steps { input(message: "Deploy to production?") } } stage('Example Deploy') { agent { label "linux" } steps { sh 'echo Deploying' } } } }
7.input を timeout で囲む
パイプラインには特定のステップを簡単にタイムアウトさせる仕組みがあります。ベストプラクティスとして、常に input をタイムアウトで囲むことを検討するべきです。
なぜでしょうか。パイプラインを適切にクリーンアップするためです。input をタイムアウトで囲むと、特定の時間内に承認されなかった場合にクリーンアップ(中止)されます。
pipeline { agent none stages { stage('Example Build') { agent { label "linux" } steps { sh 'echo Hello World' } } stage('Ready to Deploy') { options { timeout(time: 1, unit: 'MINUTES') } steps { input(message: "Deploy to production?") } } stage('Example Deploy') { agent { label "linux" } steps { sh 'echo Deploying' } } } }
8.すべての処理をエージェント内で行う
パイプラインの実質的な処理は、すべてエージェントで行うべきです。
なぜでしょうか。デフォルトでは、Jenkinsfileスクリプト自体は、ほんのわずかなリソースだけを使用するよう意図された軽量のエグゼキューターを使用して、Jenkinsコントローラー上で実行されます。Gitサーバーからコードをクローンしたり、Javaアプリケーションをコンパイルしたりといった実質的な処理は、Jenkinsの分散ビルド機能を利用してエージェントで実行するべきです。
パイプラインでの適切なやり方は、たとえば次のようになります。
sh 'bunch of work'
または
bat 'bunch of work'
ループや制御構造を記述したり、SQLデータベースなどの普通ではないものから直接読み取りを行ったり、ビジネス的判断を行う「コード」を記述するのは間違ったやり方です。
9.並列ステップでエージェントを獲得する
この理由は何でしょうか。パイプラインで並列処理を行うことの大きな利点の1つは「より多くの実質的な処理を行える」ことです(ベストプラクティス8を参照)。一般的に、パイプラインの並列ブランチ内でエージェントを獲得するようにすべきです。
10.スクリプトセキュリティの例外を避ける
理想的には、[Jenkins管理]の[In-process Script Approva]画面は、常に空であるべきです。
スクリプト承認、シグネチャ承認、クラスパスエントリ承認にエントリがある場合、Jenkinsコントローラーの安定性という観点からは良くない処理を行うジョブがあることを意味します。あなたがJenkins管理者で、ユーザーから何らかの承認を求められたら、断固としてノーと答え、承認の必要がないように処理を書き直すよう要求するべきです。
以上は、Jenkinsパイプラインの作成および設定時に従うべき多くのベストプラクティスのほんの一部です。
Jenkins Pipelineについてもっと学びたい場合は、このテクニカルガイドをダウンロードしてください。
(この記事は、CloudBees社 Blog 「Top 10 Best Practices for Jenkins Pipeline Plugin」2021年4月26日の翻訳です。)