09

職人作業を Jenkinsfile にした

もう新しくもない話になるが、 Jenkins 2 になってから、Jenkinsfile というDSLで記載したファイルにビルドパイプラインの定義をスクリプトとして記述することができるようになっている。 テキストで書けるようになることでバージョン管理による差分の検出・追跡が可能になる。Infrastructure as Code のトレンドがあった影響だとは思うが、まあJenkins自体が重量級なのでどうなのか。と思うところはあるが、ないよりは断然良い。

自分の所属先ではパッケージ型のプロダクトを持っており、以前よりそのビルドやリリースのためにJenkinsは利用している。新しいリリースを計画するたびに以前のジョブをいくつかコピーしながら新しいリリース向けのビルドジョブを作成し、それらをつなげてリリースパイプラインにしていた。 これらのインフラは作ったのも自分なので、何となく毎回なにが必要なのかはわかってはいるのだが、いまいち定型化できないし説明も難しい感じがしていた。とりあえずリリースにあたってやる必要のあることを整理する目的で、今回の一連のビルドの一部(特にリリースに関する部分)をJenkinsfileにした。

Jenkinsfile自体2通りの書き方があるらしい。Declarative PipelineとScripted Pipelineといって前者はあくまで宣言的に記述していくのに対して後者はGroovyスクリプトを混ぜ込めるというか、Groovyとして評価されるっぽい?一応前者は pipeline の宣言がルートにあり、後者はそうではないということになっているらしいのだが、この区別はほんとにそうなのかよくわからない。というか、特に興味がないのであまりこれらの違いに関して理解していない。 というのも、Declarative Pipelineでは柔軟なビルドパイプラインの定義が難しいと感じたため、結構Groovyスクリプトを書いてしまっている。例えばDeclarativeでは繰り返しの定義や、データに従ってコンフィグが変化するビルドを定義することができない、もしくは難しい。自分の要求としては、成果物全体の姿は決まっているが、例えばパッチリリースだった場合は成果物の一部、必要な部分のみに限ってリリース対象となるため、リリース毎にリリース対象を決め、その定義に従って適当に必要な部分だけパイプラインが流れるようになってくれないと面白くない。 リリース対象の増減でパイプラインの定義を書き換える必要があるのであれば、事故のもとにもなるだろうしSCMが使えるとはいえメリットが薄れる。

これをループなしで実現するのはちょっと難しいと思われた。また確認はしていないのだが、おそらく処理の共通化が容易ではないように思われる。可能な方法としては以下のような手段が取れそうなのだが

  • ジョブを分けて、共通的なジョブは個別のジョブの下流に置く
  • Groovyスクリプトを切り出して、動的に読み込む処理を書く

ただ前者の場合、成果物がジョブのワークスペースにできると思うので、いろいろなバージョンの成果物がひとところに集まるのであれば微妙。後者の場合・・・というか、結局Groovyから逃げるなということではないのか。 そう理解をして、結局今回取っている方針は、

  • 1ファイルにリリースパイプラインのほぼすべてを記述する(単純な個別ビルドは別途定義してあって基本としてはそこから成果物を収集する)
  • 可変部分はヘッダに定数的なオブジェクトを作ってそこに定義できるようにする。
  • 次回リリース時には、ファイルはまるまるコピーしてヘッダ部分のみリリースに必要な内容に書き換えてパイプラインを作成する。

処理の共通化はしていない。してもよいのだが、共通化したファイルがどこにあれば適切なのかいまいち判断できなかったことと、過去のリリースは現在のリリースと関係ないし、共通化した処理を修正したら過去のビルドも治ってほしいということもないように思われるので毎回コピーでも許容できそうに思われたため。

JenkinsfileはSCMに放り込むのだが結局Jenkinsのビルドジョブは作る必要があるあたり微妙なのだが。Gitを使えばもうちょっと自動的にやれそうな雰囲気を感じてはいる。今のところSVNなのであまり確認できていない。 (まあでもJenkinsファイルのリポジトリだけGitにしてしまえば試せるかもしれない。)

というわけで、職人作業はほぼGroovyスクリプトになった。実際にうまく運用できるかは次回以降のリリースでも確認する必要がある。

で今のところ、 Declarative Pipeline のメリットを見いだせていない。