yak shaving life

遠回りこそが最短の道

Jenkins Pipelineで特定の処理をDockerコンテナ上で実行する書き方3つ

Jenkinsfileを書いていて、一部の処理だけDockerコンテナ上で動かすにはどうすれば良いか調べたところ、なんか色々出てきたのでメモっておく。Jenkinsfile、たまにしか書かないのですぐに全てを忘れてしまう。

Jenkins 2系、Declarative Pipelineを想定してます。使いたいDockerイメージはDocker Hubあたりにホストしてあるものとします。

1. agentを指定する

stage の中でagentを指定できるので、必要な処理を含むstageのagentにdockerを指定しましょう。こんな感じ。

stage('Docker Pattern 1') {
    agent {
        docker {
            image 'image_tag'
        }
    }
    steps {
        // some process
    }
}

公式だとこの辺に書いてあります。Using Docker with Pipeline

ここではpipelineレベルのagentがnoneになっていますが、他のstageのagentを指定する必要がなければanyにしておきましょう。

2. withDockerContainer で処理をラップする

Docker Pipeline Plugin の機能らしい。

stage('Docker Pattern 2') {
    steps {
        withDockerContainer('image_tag') {
            // some process
        }
    }
}

stepsの中に書けるので、1. のパターンよりも細かい粒度で指定できる感じ。

3. docker.image().inside で処理をラップする

こう。

stage('Docker Pattern 3') {
    steps {
        script {
            docker.image('image_tag').inside {
                // some process
            }
        }
    }
}

この書き方はScripted Pipelineでしか使えないので、Declarative Pipeline内で使うためにはscript {}で囲う必要があります。

こちらは Using Docker with Pipeline のSidecar Patternあたりに書いてあるような書いてないような。ここではもっと高度な内容が書いてありますが、上記のようにシンプルに使うこともできるということです。

結局どれを使えばいいのか

よくわからん。

3.のパターンはScripted Pipelineで色々複雑なことをするためのモノなので、シンプルなDeclarative Pipelineで使う必要はなさそう。

1.と2.の違いはなんだろうか。Console Outputでログを見ると、1〜3全てで[Pipeline] withDockerContainerと表示されていて、同じコマンドが走っている。(唯一2.の場合だけdocker inspectを実行していないようだがどうでも良さげ)つまり内部的には同じ?ちょっとソースとかまで追う気にはなれないな…。

個人的には、公式ドキュメントに1.が載ってるんだから1.でやればいいのかな、くらいの認識で1.の書き方をしている。あとは1.だとオプションを色々指定したりDockerfileからbuildしたりというのが簡単にできるのでオススメです。現場からは以上です。