【Jenkins】Pipelineジョブを使ってみよう ~ 応用編 ~

CI/CD
congerdesignによるPixabayからの画像

はじめに

こんにちはSREエンジニアのMakiです。
この記事ではJenkins Pipelineジョブの使い方応用編として、パラレル処理のやり方や、対話形式での入力などのやり方を紹介していきます。
少し高度なパイプラインを書こうかなと考えている人の参考になれば幸いです。

【Jenkins】Pipelineジョブを使ってみよう ~ 応用編 ~

シナリオ

上記で作成した猫の画像をダウンロードするジョブ(フリースタイルジョブとパイプラインジョブ)をパラレルで実行します。このときに対話式で実行するかの確認を求めるようにする。

Pipelineジョブを作成する

前回と同様ジョブを作成します。
ジョブの名前は parallel_download_kitten_image_pipeline
とします。

設定の入力

設定は省略します。
必要に応じて 古いビルドの破棄 など設定しましょう。

スクリプト作成

型を作る

pipelineの型を埋めていきます。

  • nodeはslave1
  • stageは "Confirm download kitten image"と"Parallel download kitten image"の二つを用意しておきます。
  • postブロックは cleanWs のみ設定しておきます。
pipeline{
    agent{
        label "slave1"
    }
    stages{
        stage("Confirm download kitten image"){
            steps{
                echo "========executing A========"
            }
        }

        stage("Parallel download kitten image"){
            steps{
                echo "========executing A========"
            }
        }
    }
    post{
        always{
            cleanWs()
        }
    }
}
Confirm download kitten image

stage Confirm download kitten image の中身を実装していきます。

やりたいことの確認

  1. 次のステージに進む前に対話式で実行の確認をできるようにしたい。
  2. 承認ステージをスキップしたい場合に対応できるようにしたい。

この二つを実現していきます。

1. 次のステージに進む前に対話式で実行の確認をできるようにしたい。

まず一つ目の対話式での確認ですが、inputというステップを使います。
また、input を使うときは入力がされないままジョブが滞留するということを防ぐためにtimeouteというステップと併用します。

  • 1時間何もなかったらタイムアウトする設定を作ります。

pipeline20

timeout(time: 1, unit: 'HOURS') {
    // some block
}
  • 対話のメッセージを設定します。

pipeline21

input 'download kitten image?'
  • inputはtimeout の内側のブロックに記載します。
timeout(time: 1, unit: 'HOURS') {
    input 'download kitten image?'
}
  • これをstepsの中に書きます。
pipeline{
    agent{
        label "slave1"
    }
    stages{
        stage("Confirm download kitten image"){
            steps{
                timeout(time: 1, unit: 'HOURS') {
                    input 'download kitten image?'
                }
            }
        }

        stage("Parallel download kitten image"){
            steps{
                echo "========executing A========"
            }
        }
    }
    post{
        always{
            cleanWs()
        }
    }
}

2. 承認ステージをスキップしたい場合に対応できるようにしたい。

続いて二つ目の承認ステージをスキップしたい場合に対応できるようにしていきます。

パラメータにスキップするオプションを定義し、条件に当てはまるときはスキップするという方針で実装します。

使うのは parameterswhen を使います。

前回まではジョブの設定でparameterを組みましたが、実はpipelineの中で定義することも可能です。
今回は真偽値のパラメータをSKIP_CONFIRM_DOWNLOADという名前で定義してそれをフラグとして利用することにします。

pipeline22

parameters {
  booleanParam defaultValue: false, description: 'チェックを入れた場合ダウンロードの確認をスキップします。', name: 'SKIP_CONFIRM_DOWNLOAD'
}
  • parameteragentと同じ階層に記載します。
pipeline{
    agent{
        label "slave1"
    }

    parameters {
        booleanParam defaultValue: false, description: 'チェックを入れた場合ダウンロードの確認をスキップします。', name: 'SKIP_CONFIRM_DOWNLOAD'
    }

    stages{
        stage("Confirm download kitten image"){
            steps{
                timeout(time: 1, unit: 'HOURS') {
                    input 'download kitten image?'
                }
            }
        }

        stage("Parallel download kitten image"){
            steps{
                echo "========executing A========"
            }
        }
    }
    post{
        always{
            cleanWs()
        }
    }
}
  • 次にwhen ブロックを使ってstageの実行制御していきます。

SKIP_CONFIRM_DOWNLOADがtrueではないときに実行するという条件で設定します。

pipeline23

when {
  not {
    environment name: 'SKIP_CONFIRM_DOWNLOAD', value: 'true'
  }
}
  • when ブロックはstageブロック内の最初に記載します。
pipeline{
    agent{
        label "slave1"
    }

    parameters {
        booleanParam defaultValue: false, description: 'チェックを入れた場合ダウンロードの確認をスキップします。', name: 'SKIP_CONFIRM_DOWNLOAD'
    }

    stages{
        stage("Confirm download kitten image"){
            when {
                not {
                    environment name: 'SKIP_CONFIRM_DOWNLOAD', value: 'true'
                }
            }

            steps{
                timeout(time: 1, unit: 'HOURS') {
                    input 'download kitten image?'
                }
            }
        }

        stage("Parallel download kitten image"){
            steps{
                echo "========executing A========"
            }
        }
    }
    post{
        always{
            cleanWs()
        }
    }
}

このあたりでVSCodeの Pipeline Linter でシンタックスエラーがないか確認してみます。

※ Pipeline Linter について わからない方は前回の記事を御覧ください↓
https://tielec.blog/index.php/sre/ci-cd/jenkins/pipeline-basic/#toc6

linterの使い方

Ctrl + Shift + P > Validate Jenkinsfile を実行

pipeline24

Jenkinsfile successfully validated. が表示されればOKです。

pipeline25

これでConfirm download kitten imageのステージの実装が完了しました。


Parallel download kitten image

続いてParallel download kitten imageのステージを実装します。
ただ、ジョブを二つパラレルで実行しても面白くないのでScripted Pipelineの書き方を使ってみます。

やりたいこと

  1. 日付をjson形式で取得できるAPIを利用し、今日の日付を返す関数を作る。
  2. 取得した日付を用いてダウンロードする画像のファイル名を準備する。
  3. 日付が入ったファイル名をジョブのパラメータとし kitten_image_generatorkitten_image_generator_pipelineの二つを並列実行する。

1. 日付をjson形式で取得できるAPIを利用し、今日の日付を返す関数を作る。

関数の定義はpipelineブロックの外側で定義することができます。

  • getTodayFromJsonApiという名前で関数を作ります。
    def getTodayFromJsonApi(){
    sh 'curl -f -o date.json "http://date.jsontest.com"'
    json = readJSON file: 'date.json'
    echo "TODAY is ${json.date}"
    return json.date
    }

関数はこのように定義することができます。
やっていること

  • sh ステップの中で日付をjson形式表示するAPIをキックしdate.jsonというファイルに吐き出す。
  • readJson というステップを用いてファイルを読み込みjsonという変数に値を格納する。
  • return で日付を返す。

変数の中身は以下のようなデータが格納されています。

{
    date: "11-26-2019",
    milliseconds_since_epoch: 1574773459376,
    time: "01:04:19 PM"
}
  • これをパイプラインに記載します。
pipeline{
    agent{
        label "slave1"
    }

    parameters {
        booleanParam defaultValue: false, description: 'チェックを入れた場合ダウンロードの確認をスキップします。', name: 'SKIP_CONFIRM_DOWNLOAD'
    }

    stages{
        stage("Confirm download kitten image"){
            when {
                not {
                    environment name: 'SKIP_CONFIRM_DOWNLOAD', value: 'true'
                }
            }

            steps{
                timeout(time: 1, unit: 'HOURS') {
                    input 'download kitten image?'
                }
            }
        }

        stage("Parallel download kitten image"){
            steps{
                echo "========executing A========"
            }
        }
    }
    post{
        always{
            cleanWs()
        }
    }
}

def getTodayFromJsonApi(){
    sh 'curl -f -o date.json "http://date.jsontest.com"'
    json = readJSON file: 'date.json'
    echo "TODAY is ${json.date}"
    return json.date
}

2. 取得した日付を用いてダウンロードする画像のファイル名を準備する。

Decralative pipelineの中でScripted Pipelineのような書き方をする場合はscriptブロックを使います。scriptブロックの中では関数の呼び出しや、変数の変更など柔軟な書き方ができます。Groovyの知識が必要となるのは主に、このscript ブロックを使いたいときになります。

script{
    def today = getTodayFromJsonApi()
    def image = "kitten-image-${today}.jpg"
}

このようにscriptブロックの中で関数の呼び出しや変数の定義を行うことができます。

3. 日付が入ったファイル名をジョブのパラメータとし "kitten_image_generator" と "kitten_image_generator_pipeline"の二つを並列実行する。

まずはパラレル実行はparallelステップを使います。
書き方がちょっと特殊なのでいかにテンプレートを用意します。

parallel(
    "A":{
        echo '========executing A========'
    },
    "B":{
        echo '========executing B========'
    }
)

A、Bにはそれぞれわかりやすい名前を入れてください。

次に kitten_image_generator を呼び出す処理を書きます。
ジョブの呼び出しはPipelineSyntaxから作るとパラメータなどのサジェストがされるので便利です。

pipeline26

  • KITTEN_IMAGE_FILE_NAMEのパラメータには先ほど定義した image という変数を渡します
build job: 'kitten_image_generator', parameters: [string(name: 'KITTEN_IMAGE_FILE_NAME', value: image)]
  • 同様にkitten_image_generator_pipelineの呼び出し部分も作ります.
  • これらをscriptブロックに書いていく次のようなものが出来上がります。
script{
    def today = getTodayFromJsonApi()
    def image = "kitten-image-${today}.jpg"
    parallel(
        "kick freestyle job": {
            build job: 'kitten_image_generator', parameters: [string(name: 'KITTEN_IMAGE_FILE_NAME', value: image)]
        },
        "kick pipeline job": {
            build job: 'kitten_image_generator_pipeline', parameters: [string(name: 'KITTEN_IMAGE_FILE_NAME', value: image)]
        }
    )
}

これを Parallel download kitten image の中に記載したら完成です。

Linterでシンタックスエラーを確認するのもお忘れなく。

完成!!
こちらはすべて書き終わったあとのJenkinsFile です。

pipeline {
    agent {
        label "slave1"
    }
    parameters {
    booleanParam defaultValue: false, description: 'チェックを入れた場合ダウンロードの確認をスキップします。', name: 'SKIP_CONFIRM_DOWNLOAD'
    }
    stages {
        stage("Confirm download kitten image") {
            when {
                not {
                    environment name: 'SKIP_CONFIRM_DOWNLOAD', value: 'true'
                }
            }

            steps {
                timeout(time: 1, unit: 'HOURS') {
                    input 'Download kitten image?'
                }
            }
        }
        stage("Parallel download kitten image") {
            steps {
                script{
                    def today = getTodayFromJsonApi()
                    def image = "kitten-image-${today}.jpg"
                    parallel(
                        "kick freestyle job": {
                            build job: 'kitten_image_generator', parameters: [string(name: 'KITTEN_IMAGE_FILE_NAME', value: image)]
                        },
                        "kick pipeline job": {
                            build job: 'kitten_image_generator_pipeline', parameters: [string(name: 'KITTEN_IMAGE_FILE_NAME', value: image)]
                        }
                    )
                }
            }
        }
    }
    post {
        always {
            cleanWs()
        }
    }
}

def getTodayFromJsonApi(){
    sh 'curl -f -o date.json "http://date.jsontest.com"'
    json = readJSON file: 'date.json'
    echo "TODAY is ${json.date}"
    return json.date
}

Pipelineジョブを実行する

  • ビルド実行をおしてジョブを実行します。
    ※ 初回実行時はパラメータが読み込まれていないので パラメータ付きビルドではなくビルド実行になります。
  • Stage Viewにcursorを合わせるとメッセージがサジェストされます。
    pipeline27
  • Proceedを押すと処理が進みジョブが実行されます。
    pipeline28
  • Blue Oceanでパイプラインの様子を見てみます。
  • 画面左 Open Blue Ocean を開く
  • 最新のビルド番号を開く
    pipeline29

このようなパイプラインになりました。


  • 今度は確認をスキップして実行してみます。
    pipeline30
  • 確認が行われずに画像をダウンロードするステージへと進みました。
    pipeline31
  • 再度Blue Oceanで確認してみます。
    Blue Oceanでもスキップされていることが確認できます。
    pipeline32

Jenkins Pipelineジョブを使ってみよう ~ 応用編 ~の内容は以上です。お疲れ様でした。

まとめ

いかがでしたでしょうか。今回の記事ではJenkinsPipeline の応用編としてパラレル処理と対話式で入力処理のやり方について記載しました。質問やコメントとうございましたらぜひフィードバックお願いします。

関連ページ

おすすめ書籍


[改訂第3版]Jenkins実践入門 ――ビルド・テスト・デプロイを自動化する技術 (WEB+DB PRESS plus)

初めてJenkinsを学ぶ方におすすめです。


Jenkins

Jenkinsでできることについてもう少し詳しく学びたい方におすすめです。


サーバ/インフラエンジニアの基本がこれ1冊でしっかり身につく本

コメント

タイトルとURLをコピーしました