なんかかきたい

プログラミングなどの個人的なメモやサークル「ゆきいろパラソル」の情報を載せてます

【読み物】2022年にJenkinsのジョブ管理を自動化するには時代が追いついていない

完全に理解したから何もわからないに突入したので2022年現在の状況をまとめておこうと思います。 Jenkins自動化完全に理解したの人向けのメモなので、Jenkinsfileをまだ触ったことがない、ちょっと触っていて便利かもって人向けではないです。

先に結論だけ書いておくと、個人的にはジョブが少ないなら JCasC + jobDSL + Jenkinsfile のパターンで管理できると思います。 ただし、Jenkinsfileは一度評価しないとパラメータやトリガーなどが設定されず、JenkinsfileとjobDSLは機能が競合するため、癖のある運用になる点は注意が必要です。簡単な方法として、jobDSLでジョブを作成する際に triggers を設定し、jobDSLのジョブ実行後に自動的にJenkinsfileのジョブをトリガーする方法があります。可能であればJenkinsfile側では when を設定しておき、 UpstreamCause の場合にジョブ実行を早期終了すると良いでしょう。

このやり方は以前も書いた通りで、Jenkins自体を小さく保つことでインスタンスのアップグレードなどの管理面やコードレビューの責務を分解できる点でも有利なので、可能であればこの方法は (多少の癖はあるものの) 有効であろうと思われます。

しかしながら、この方法はジョブの数が増えると運用上厳しい点が出てきます。 Jenkinsfile を管理しているリポジトリを SCM Trigger して、jobDSLのジョブを起動、ジョブを全部更新 + Jenkinsfile を設定すると、Jenkinsfileで設定された設定は jobDSL によって上書きされてしまいます。これは例えばパラメータ付きビルドやcronを設定しているジョブで問題になることはよく知られています。ワークアラウンドとしては前述したジョブを仮で実行する方法しかありません。

stackoverflow.com

これはひどいと思われるかもしれませんがこれが実態です。諦めてください。

IssueとしてはJenkinsfileを実行せずに評価して反映する機能の要望などがありますが、2022年時点では提供されていません。

issues.jenkins.io

This is a major problem, a hole, in the pipeline feature. The workaround is lame: run the pipeline after modifying the jenkinsfile (in source control); kill the job as soon as Jenkins has processed the updated jenkinsfile which seems to happen right after it pulls the code at the start of the job; then run again.

というわけで、現状は前述の方法しかないです。上記のIssueにはできない理由がもう少し詳しく書かれており、簡単には解決しなさそうに見えます。

関連する類似のIssueは他にもありますが同じく未解決です。Jenkinsfileの運用に問題があるのは広く知られていますが解決はしていません。

issues.jenkins.io

Jenkisfileにはもう一つ大きな問題があります。Jenkinsfileはジョブを宣言的に定義しますが、自身のジョブを初回に登録する方法を提供しません。 言い換えればジョブはJenkinsfileの外で登録する必要があります。 同じくJenkinsfileは評価されなければ自身のジョブを定義できないわけですから、これは不便です。 jobDSLプラグインはジョブを宣言的に管理するプラグインで、これを使ってジョブを定義し、Jenkinsfileを設定すればジョブ定義自体は行うことができます。一部そのような紹介をしているブログ記事などがあり、これは一見便利なように思えますが、先に書いたようにjobDSLプラグインは強力な宣言的管理を行うため、Jenkinsfileによるジョブ定義はjobDSLの実行により上書きされてしまいます。そのため、jobDSLを実行したら改めてJenkinsfileを評価する必要があります。これも前述の通りです。

stackoverflow.com

jobDSLがJenkinsfileと協調動作をすればいいではないかという意見もありますが、話はそう簡単ではないでしょう。そもそもjobDSLはjobDSLの外の変更を完全に追跡はできませんし、おかしな話と思います。

issues.jenkins.io

さて、話を戻しましょう。上記の方法でJenkinsfileの実行を分岐し、実行しないモードをなんらかの方法 (例えば上記のパラメータを使う例) で提供したとして、ジョブを実行しなければなりません。空実行とはいえ、jobDSL実行後にはジョブの数ぶんだけJenkinsfileを評価するためジョブを実行することになります。ジョブの数が増えるとこのJenkinsfileの評価のため多くのジョブを実行する必要が出てきます。

それでは、全てのジョブを評価せず、Jenkinsfileが変更されたジョブだけJenkinsfileを評価すればよいと思うことでしょう。 しかし話はそう単純ではありません。

jobDSLは強力な宣言的ジョブ管理機能を持っています。jobDSLはプログラム的ではなく、宣言的にジョブ管理をしているため、部分的な反映をサポートしていません。jobDSLスクリプトはgroovyとして評価されるため、ifなどのロジックでジョブ定義を分岐できると思うかもしれませんが、ifで分岐をしても、ジョブの宣言が消えるにすぎず、これは結果としてジョブの削除と等価です。(分岐によって宣言が消える)

jobDSLは強力な宣言的ジョブ管理機能により、groovyで簡潔にジョブを定義できますが、部分的な反映のようにプログラム的な操作には適していません。この方式を考えるのであれば jobDSL でのジョブ定義は諦めるしかないでしょう。

今の時点での私の考えは、Jenkinsfileのジョブ登録は jobDSL を使わず、 groovy スクリプトでジョブ登録をプログラム的に行うしかないと考えています。これは一見後退しているように思われますが、元々のジョブも本体はJenkinsfileに定義があるため、ほぼ骨組みだけの簡単なジョブ定義になるため、実際にはそこまで可読性を下げることはありません。そもそもこのジョブは通常JCasCの中に定義するため、多くのJenkins利用者はあまり意識することはないでしょう。

この方式を取る場合、登録したジョブを実行する処理もgroovyで記述するのが良いでしょう。

それで、本題になりますが、このジョブをgroovyから実行するという情報がめちゃくちゃ探しづらかったので、これだけコードを書いておきます。

gist.github.com

他の部分もサンプルコードを交えて説明できるといいのですが、LTとかで話せるといいんですかね。場がないんだわってわけですが。

とりあえず Jenkins を k8s 上で運用して、ジョブ管理も自動化できそうな感じになっているので、まあいいかって感じなんですが、2022年にもなってなんでJenkinsやってるのって思ってるでしょ?Jenkinsって便利なんですよね。SAML認証プラグインもあるし運用的には。後発のプロダクトもJenkinsと比較して良いかというと必ずしもそうじゃないわけです。なるほどですね。