Jenkins Shared Libraryで快適 Jenkins 生活?


Jenkins Shared Library で快適 Jenkins 生活?

この記事は ACCESS Advent Calendar 2018、第 15 日目の記事です。
今日も元気にCIぶん回す@bols_blueです。

Jenkins Shared Librariesとは

Jenkins 2.0 になって新たに Jenkins Pipeline が使えるようになり、レポジトリに Jenkinsfile をおくだけでビルドの設定ができるようになりました。
り GitHub Organization Plugin と組み合わせればいちいち Jenkins の画面を開かなくてもレポジトリの検出、ジョブの作成、プルリクエスト毎のビルドジョブの作成、ビルドの設定・実行をやってくれるので便利になったと思います。

しかし、メンテナンスの問題は依然として存在していて、運用が長くなれば同じような Jenkinsfile が増えていきます。
ここで

  • プラグインの修正で動作が変わった
  • 過去の自分の作った Jenkinsfile が自分で見ても微妙…

といったような事になると全部のレポジトリの Jenkinsfile を直して回ると行った Jenkins 修行僧によるお遍路が発生してしまいます。

「お遍路はもう嫌だ!!!」 と叫ぶ羽目になる前に使っとくと良いと思います。
まぁ、私は手遅れでこれから Shared Library 置き換えるお遍路の旅が始まるぜよ…

Jenkins の Declarative Pipeline で Shared Library を使ってみようとおもいます。

Shared Library を書いてみる

公式のサンプルからディレクトリ構成の解説

ソースコードの構成は下記の様な構成にできます。
できますというのもかんたんなステップを作るだけであればvarsだけで十分です。

+- src                     # Groovy ソース
|   +- org
|       +- foo
|           +- Bar.groovy  # for org.foo.Bar class
+- vars
|   +- foo.groovy          # 'foo' のステップ
|   +- foo.txt             # 'foo' のステップのヘルプ
+- resources               # resource files (external libraries only)
|   +- org
|       +- foo
|           +- bar.json    # リソースファイル

公式のサンプルコードをそのままやっても芸がないの+jenkinsの中でshellである程度実装している人向けにちょっと修正してリソースの中にあるシェルスクリプトを読み出して実行するサンプルを作ります

リソースの中にあるシェルスクリプトを読み出して実行するサンプル

ディレクトリ構成は以下のようになっています。

├── resources
│   └── jp
│       └── lnc
│           └── jenkins
│               └── libs
│                   └── my_shell.sh
└── vars
    └── runMyShell.groovy

vars以下のファイルはファイル名の先頭は小文字です。
必須ではないですが正しく認識されないケースがあるので気をつけてください。

runMyShell.groovy
def call() { 
   def myShell = libraryResource 'jp/lnc/jenkins/libs/my_shell.sh' 
   return sh(myShell) 
} 
my_shell.sh
ls
ls -la

以上です。
簡単ですね。

Shared Library のセットアップ

Shared Library はプラグインと違って公式の配布に頼らなくてもgitやsvnなどのSCMから直接配布することができます。

利用するライブラリにJenkinsからアクセスが可能であればJenkinsの設定画面から追加することができます。
以下のような設定画面から設定できます。
公開してあるレポジトリを利用する場合は図中の2つの項目を設定すればセットアップは完了です。

各設定項目は以下のようになっています。

設定項目名 設定内容 画像での表示
Name ライブラリ名です。@Libraryでインポートする識別子です。 bols-blue-org
Default version @Library でバージョンを指定しない場合に使われるブランチ、またはタグを指定します。 master
Load implicitly オンにすると @Library で明示的にインポートしなくても呼び出しが可能になります OFF
Allow default version to be overridden @Library で読み込む場合にバージョンの指定を許可するか。オフの場合、常にDefault versionで指定したバージョンが使われます ON
Include @Library changes in job recent changes ONにするとライブラリ内の変更がビルドのチェンジセットに含まれます。 ON
Retrieval method ライブラリを取得するためのSCMの設定です git

これでセットアップは完了なので Jenkinsfile を書いていきます
まずは全体です

Jenkinsfile
@Library('bols-blue-org') _

pipeline {
    agent {
        docker { image 'node:7-alpine' }
    }
    stages {
        stage('Test') {
            steps {
                runMyShell()
            }
        }
    }
}

下記のコードでライブラリをロードしています。
このとき[email protected]などという形でタグやブランチを指定できます。

@Library('bols-blue-org') _

この記事とはあまり関係ないですがdocker image上で実行します。

    agent {
        docker { image 'node:7-alpine' }
    }

ステージとステップの定義を行いstepsでrunMyShellのカスタムステップを実行します。

    stages {
        stage('Test') {
            steps {
                runMyShell()
            }
        }
    }

引数がない場合は呼び出し時に()をつけないとエラーになりますので気をつけましょう。

以上の設定で実行してみましょう。

できました。
これで色んな所に点在してしまったshellやJenkinsfileを一元管理できますね。

終わりに

bitbucketやgitlabがSCMとCI環境を含んだ環境を提供し始めて段々とCIサーバー単品で構築、運用の場が減っていくのかなと感じる昨今ですがJenkinsの記事です。

参考
公式のパイプラインの概要(英語)
公式のshared-librariesのドキュメント(英語)
公式のDeclarative Pipelineのシンタックス(英語)
公式の他のプラグインから提供されるステップのドキュメント(英語)

もう少し実用的な例(通知をパイプラインからshared-librariesに置き換える)

Jenkins2のPipline参考リンク集