【CI奮闘記】第10章:パイプラインでMavenのビルドを行う!


はじめに

前回のブログでは、JenkinsのフリースタイルジョブでMavenのビルドを行う方法説明しました。
前回のブログはこちら
今回は実際にJenkinsパイプラインを用いてMavenのビルドを行う方法を説明します。

登場人物

吉田:転職したてのエンジニア。前職では積極的にCIやCDという事に取り組みながら開発をしていた。

服部:配属1年後の新人。CIやJenkinsについては言葉は聞いたことがある程度。もともと開発で今回初めて環境周りを扱う事になった。

パイプラインでMavenのビルドを行う!

フリースタイルジョブの限界

前回はフリースタイルジョブでMavenのビルドを定期実行する方法を説明したわね。

はい!ビルドのフリースタイルジョブを作成したので、そのあとにテストのジョブ、デプロイのジョブと作成していけば3つの開発プロセスを自動化できそうです!

当然そうやっても実現はできるんだけど、フリースタイルジョブで構築すると次のような弱点があるの。

GUIによる管理のみとなってしまう

これは初心者にとっては良い事ではありますが、管理するとなると問題となります。いつ誰が変更したかといった変更履歴を追うことができません。また、同じ設定をほかのジョブに流用しようとしても1つずつGUIで設定していくことになり、大規模に展開することは困難です。

複雑なワークフローを定義することが難しい

順に開発フローを定義したジョブを実行していくだけであれば問題ないですが、たとえば条件分岐や入力を待機して承認後再開する、といったワークフローの定義はフリースタイルジョブでは困難です。

ジョブの管理が煩雑になる

フリースタイルジョブの場合、1つのジョブに割り当てる処理は基本的には1つです。そのため、「ビルド」「静的解析」「単体テスト」「デプロイ」という開発フローを自動化しようとした場合、4つのジョブを作成します。開発対象が10プロジェクトになると40のジョブを管理することになり、Jenkinsのダッシュボード管理に時間がとられてしまいます。

途中からの再実行ができない

1時間かかるビルドを行い、その後テストを実施するといったジョブがあったとします。このテストが誰かがファイルを開いていたといったテスト以外の外的要因によって異常終了した場合、テストから再実施しようと思ってもフリースタイルジョブの場合は困難です。

こう聞くとフリースタイルジョブはツールの実行といった単純なものであれば良さそうですが、開発フローを定義するには大変そうですね。

そこで登場するのが、今回のテーマのパイプラインよ!

パイプラインとは

パイプラインはJenkinsのバージョン2.0から利用できるようになったジョブの種類ね。JenkinsのジョブをApache Groovy をベースにしたコードで定義できるようになったの。

コードで定義ということはJenkinsのジョブをSCMで管理できるんですか?

そう。製品のコードと同じようにSCMで管理が可能よ。なので変更履歴を追えるし、コードなのでほかのジョブに流用することのハードルも下がったわ。

if文のような条件分岐も書けるんですか?

条件分岐だけでなくてさっきあげた入力待機も可能ね。例えば開発リーダーの承認を待機して承認後特定の環境にデプロイする、といったこともできるわ。

確かに重要な環境にデプロイする際は、きちんとテストが通っているのを確認してからデプロイできると良さそうですね。

それ以外にもパイプラインのメリットはあるので表にまとめてみたわ。

項目利点
耐久性Jenkinsコントローラーを再起動してもパイプラインは実行を続ける
一時停止可能停止して人間の入力または承認を待機できる
多目的現実世界の複雑な CI/CD に関する要件をサポート (フォーク、ジョイン、ループ、並列化など)
拡張性パイプライン定義のためのドメイン固有言語のカスタム拡張をサポート
その他プロジェクト数を減らす、メンテナンスがより簡単、プロジェクト構成の分散、コードによる簡単な指定

パイプラインでMavenのビルドを行う

先日フリースタイルジョブで実行したMavenのビルドを今度はパイプラインで書いてみましょう。

新規ジョブ作成でパイプラインというやつを選択すればいいんですね?

それでもいいんだけど、今回はGitea(自己ホスト型のGit サービス)を使っているので「Multibranch Pipeline」という方を使いましょう。

了解です。名前を入れて、、、設定画面に遷移しました。

じゃあBranch Sourcesセクションに接続情報を入れていきましょうか。

完了しました。ほかに入力するところはありますか?

今回は実行するだけなので大丈夫かな。それでこの「Build Configuration」の項目を見て欲しいの

「Jenkinsfile」ですか?

そう。さっきパイプラインはコードで記載するといったわよね。このJenkinsfileにパイプラインのコードを書いていくというわけ。Jenkinsfileがパイプラインの本体と言えるわね。

了解しました。いきなりコードを書くといってもどうすれば良いかわかりませんが。。。

大丈夫。宣言型パイプラインを使えば仕組みに則って記載していくだけである程度のパイプラインが書けるわ。

パイプラインの種類

パイプラインには現在2種類のパイプラインの記載方法があります。

  • スクリプトパイプライン
  • 宣言型パイプライン

Jenkins2.0のリリース当初はGroovy DSL構文を利用できるスクリプトパイプラインが利用できました。Groovy DSLの柔軟な記述によりそれまでのパイプラインの問題を解消でき、コードでパイプラインを定義できるようになりました。一方その柔軟な記述によって、ジョブの定義が複雑になったり、習得の難易度が高くなったりする傾向にありました。
この問題を解消するために導入されたのが宣言型パイプラインです。ある一定の構文が定義されており、構文として定義されているセクションごとに命令を記述することで、スクリプトパイプラインと比較してシンプルにコードを記載できるようになりました。
現在では宣言型パイプラインが推奨されていますので、これから新しく始める方は宣言型パイプラインで作成すると良いでしょう。本ブログでも宣言型パイプラインで記載をしていきます。

mavenをビルドするパイプラインはこのようになるわ。

pipeline {
   agent any
   stages {
     stage ('build') {
       steps {
         bat 'mvn clean package'
       }
     }
   }
 }

カッコ構造で階層化されているんですね!

こちらが宣言型パイプラインを作成する際に押さえておくべきキーワードとなります。

キーワード説明
pipeline宣言型パイプラインはpipelineブロックで囲む必要があります。
agent処理を実行するエージェントを指定します。pipelineの直下に記載したものはグローバルエージェントとなります。グローバルエージェントは必ず1つ指定しなければなりません。
stages1個以上のstageを含みます。pipelineブロックの中で必ず1つ指定します。
stage開発プロセスの各個別部分(ビルド、テスト、デプロイなど)を表します。プロセスにとって意味のある名前を付けます。
stepsstageの中で実行する1個以上のステップ(echo,bat, junitなど)を定義します。

このような構造になっており、それぞれのセクションごとに役割を定義していきます。これ以外にも様々なオプション等もあります。詳細を知りたい方はこちらのドキュメントもあわせてご確認ください。

Pipeline Syntax

https://www.jenkins.io/doc/book/pipeline/syntax/

このコードをJenkinsfileという名称で保存して、Gitea上に登録するわ。

先ほど設定の「Build Configuration」で指定したScript pathに配置すればいいんですね。

配置が完了したら、Jenkinsのパイプラインメニュー内の「Scan Multibranch Pipeline Now」をクリックすると保存したJenkinsfileを走査するわ。

成功したみたいです!

これでJenkinsfileがJenkins側に読み込まれてパイプラインが実行できるようになったわね。ジョブを見てみましょうか。

こんな風にstageごとに分けられてステータスが表示されるわ。
初めの「Declarative: Checkout SCM」はSCMからソースコードをチェックアウト。これは宣言型パイプラインであれば自動でチェックアウトしてくれるわ。その後の「build」が今回作成したmavenでビルドするstageね。

でもbuildが赤いですね。失敗しているみたいです。。。ログは、、、Mavenのコマンドがたたけていないようですね。

前回のフリースタイルジョブと同じようにパスが通ってないからね。今回はパイプラインのtoolsセクションを使いましょう。

正解。このtoolsセクションをさっきのパイプラインに追加するとこうなるわ。この内容に変更してまたパイプラインを実行してみましょう。

pipeline {
   agent any
   tools {
     maven "mvn3"
   }
   stages {
     stage ('build') {
       steps {
         bat 'mvn clean package'
       }
     }
   }
 }

「Declarative: Tool Install」が新しく表示されて、buildも成功しました!

このtoolsセクションを利用すると、ビルドするエージェントで特定のツールが利用できない状態であっても、パイプライン実行時に自動で利用できるようにしてくれるわ。ただし、Jenkinsの設定内のGlobal tools Configrationでの設定が必要なのであわせて覚えておいてね。

こちらは前回のCI奮闘記でJenkinsの管理 > Global Tool Configurationで設定済みの環境となります。設定していない場合、別途設定が必要となります。

了解しました。今のパイプラインはbuildステージだけですが、他のステージを追加できるんですよね。

もちろん!stagesセクション内にstageを複数書けるので、例えばこのように書けるわ。今回は説明のためにstepはechoにしているけど、実際はここにスクリプトを記載するイメージね。

pipeline {
   agent any
   tools {
     maven "mvn3"
   }
   stages {
     stage ('build') {
       steps {
         bat 'mvn clean package'
       }
     }
     stage ('test') {
       steps {
         echo 'テスト実施'
       }
     }
     stage ('deploy') {
       steps {
         echo 'デプロイ実施'
       }
     }
   }
 }

これが一つのパイプラインで開発フローを定義できるといっていたやつですね!

そうね。実行結果はこんな感じになるわ。

まとめ

パイプラインの実行イメージがだいぶつきました。

次回はほかの構文の説明や、このパイプラインをもっと使いやすくする方法について説明していくわね。

今回はパイプラインはどういったものなのか、どう実行するのかという点を説明しました。ただ、今回の例では現在はジョブを手動で実行しています。前回は定期実行について説明しました。定期実行でもある程度目的は達成できますが、CIを実現するためにはコードがSCMに登録された時点でパイプラインが自動で実行される方が望ましいです。

次回は条件分岐や入力待機といったもう少し複雑なパイプラインの構文や、パイプラインの起動方法について説明していきます。