プロジェクトでは Jenkins でビルド職人をやることが結構あります。Jenkins のジョブは Web UI でポチポチ設定するのが伝統でしたが、最近はビルドパイプラインを DSL で書けるようになって Infrastructure as Code 化が進んでいます*1。
ここ数年は Docker コンテナでアプリをリリースすることが増えており、コンテナイメージのビルド・破棄というステップがパイプラインに入ってきます。
以前作った Spring Boot の REST API のコンテナ化アプリを題材にパイプラインを構築してみました。
このサンプルでは、docker-compose で Spring Boot の jar ファイルをコンテナに COPY して起動し Mongo DB のコンテナと連携させています。
パイプラインは以下のようなステップで流します。
- ソースコードのチェックアウト (git clone)
- パッケージング (maven package)
- ビルド
- 単体テスト
- jar ファイル生成
- コンテナビルドと起動 (docker-compose up)
- 結合テストの実行
- コンテナの停止と破棄 (docker-compose down)
アプリの単体テストはコンテナビルド前に実行し、結合テストはコンテナを起動してエンドポイントに対して E2E のテストを実行します。
pipeline { agent { node {label 'jnlp_agent'} } stages { stage('checkout') { // git clone steps { checkout([$class: 'GitSCM', branches: [[name: '*/master']], userRemoteConfigs: [[url: 'https://github.com/kondoumh/sb-sample-service.git']]]) } } stage('package') { steps { // build, unit test, package sh './mvnw package' } } stage('build and run container') { steps { // build and run container sh 'docker-compose up -d' sleep 60 } } stage('container integration test') { steps { // e2e test with curl echo 'conteiner integration test' sh 'curl -X POST "http://localhost:18888/api/user/" -H "accept: */*" -H "Content-Type: application/json" -d "{ \"id\": 1, \"name\": \"Mike\"}"' sh 'curl -X GET "http://localhost:18888/api/usr/1" -H "accept: */*"' } } } post { always { // shutdown container sh 'docker-compose down' } } }
DSL なので Groovy 知らなくても大体読めると思います。agent {}
宣言で実行する Jenkins agent を指定します*2 。stages
内の stage
が順次実行されます。post { always{} }
に書かれた処理は stages の途中でエラーが発生しても必ず実行されます。stage は並列実行などもできます。
docker-compose でコンテナをビルド実行すると Spring アプリケーションの起動に時間がかかるため、sleep を入れてます。
結合テストは Java で書いてちゃんと assert すべきですが、簡単な動作確認を curl で書いて済ませました。
実行は Blue Ocean のモダンな画面でモニタリングできます*3。
Blue Ocean の画面でパイプラインを編集可能なプラグインもあるようです。
今回のように Docker コマンドを shell で叩いてもいいのですが Pipeline Plugin の DSL で書けるようにしてくれるプラグインもあります。
イメージの取得ビルド、コンテナ内のプログラム実行、ジョブ終了後のコンテナ破棄をやってくれます。ただし、docker-compose には対応していないようです。残念。
Jenkins のエージェント自体もコンテナで動かすことができて、公式のイメージを利用できます。
https://hub.docker.com/r/jenkinsci/slave
Jenkins ではプラグインを使う必要がありますが、最近の CI ツールはネイティブにコンテナイメージを扱えるものが主流になっています。 Jenkins も Jenkins X というプロジェクトで、クラウドネイティブ化を目指しています。