Jenkins入門【2.0対応】 - オープンソースCIツール(5)
Jenkins 2の新機能「Pipeline」を使ってみよう
―― “Pipeline as Code”:パイプラインをコードで記述する ――
何をやっているか分からない「Jenkinsおじさん」の作業を見える化しよう。Jenkins 2に新搭載されたPipelineを使えばパイプラインをコードで記述できるようになる。その基本的な使い方を解説。
Jenkins 2に搭載された新機能の目玉として、今までPipelineプラグイン(※第3回で解説したBuild Pipelineプラグインとは別物である)として提供されていたPipeline(以下、パイプライン)が標準搭載されたことが話題となっている。今回はこのパイプライン機能について掘り下げて解説していきたい。
Jenkinsおじさん
「Jenkinsおじさん」という言葉を聞いたことはあるだろうか? これはJenkinsを運用管理してくれている人をロゴにあしらわれている紳士に例えて表現した言葉だ。恐らくJenkinsが活発に利用されているチームに1人はJenkinsおじさんが存在し、陰ながら安定動作を支えてくれていることと思う。
さて、最新のJavaScriptフレームワークを操るフロントエンドエンジニアや、大量のアクセスを高速に処理することに情熱を燃やすサーバーサイドエンジニアと比較して、Jenkinsおじさんの存在は地味だ。高速にCI(継続的インテグレーション)を回し、価値をユーザーに届ける役割の重要性は、他のエンジニアたちと変わらないはずなのになぜだ!?
その答えは、「作業の不透明さ」にあると筆者は考える。GitHubなどによるプルリクベースのソーシャルコーディングが主流となった昨今では、GUIベースの設定を行うJenkinsは他人から見ると「何をやっているか分からない」のだ。
ジョブ(Job)をスクリプトで定義するパイプライン(Pipeline)
そこで登場するのが、今回のテーマとなっているパイプラインである。GUIでのパイプライン設定は簡単に行える半面、次のデメリットが存在する。
- 履歴管理ができない: 「ジョブの内容を変更したら動かなくなった」というパターンなら分かりやすい。しかし厄介なのは「ジョブの内容を変更したら動作が不安定になった」というパターンだ。GUIで設定した内容は履歴管理することはできない。正確に元の状態に戻すことは難しいはずだ。
- 内容のチェックができない: 「ビルドスクリプトの記述でミスして、テストが通らなくなった」という程度であればチームメンバーに謝れば許してもらえそうだが、「デプロイ手順を間違えた」となれば(稼働中のサービスにも影響が及ぶ可能性があるので)話は別だ。重要な変更であれば複数人の目でチェックを行うべきだが、GUIでは変更点が分かりづらく、複数人でのチェックは難しいはずだ。
- 設定のコピーが難しい: 似たようなプロジェクトのビルドを構築する際も、GUIの場合は目視で内容をコピーしなければならない。
これらの問題を解消するためには、ジョブの定義をスクリプトで記述する必要があるのだ(Pipeline as Code)。
簡単なビルドパイプラインの構築
それではビルドパイプラインを構築する簡単なジョブをスクリプトで記述してみよう。
新規ジョブの作成
Jenkinsのトップ画面の左側にあるメニューから[新規ジョブ作成]をクリックし、ジョブの作成画面を開く(図1)。次にジョブの名前を入力して、作成するジョブの種類には[Pipeline]を選択する。
スクリプトの入力
パイプラインの作成画面が開いたと思う。その画面下部にある[Script]欄に、図2(もしくは後掲のリスト1)に示すスクリプトを入力し、[保存]ボタンを押す。
このスクリプトでは、2つのステージを定義して、それぞれで「sh ○○」というコマンドを実行している。スクリプトの書き方について詳しくは後述する。
パイプラインの実行
それでは取りあえず、入力したスクリプトを実行してみよう。実行方法は通常のジョブと同じで図3の1の手順で行える。
ビルドの進行状況がリアルタイムに表示されているのが確認できるはずだ(図3の2)。また、通常のジョブと同じく、[ビルド履歴]から実行結果も見ることができる(図4)。
スクリプトの解説
1
2
3
|
node {
stage 'メッセージの表示'
sh 'echo Hello Pipeline.'
stage '日付の表示'
sh 'date'
}
|
- 1実行するノードを指定できる。指定しない場合は、この例のように何も書かない。ノードを指定する際は、次のように引数でノード名を渡す。
Groovy(Pipeline script)node('slave') {……略……} - 2ステージを指定する。1つのノードの中にいくつでも書くことができる。ステージごとに実行時間や実行結果が表示される。
- 3
sh
に続けて実行したいコマンドを書く。
いかがだろうか? 実行したいコマンドをstage
ごとに記述していけばよいので簡単かと思う。
Railsプロジェクトのビルドパイプラインの構築
次のサンプルは、ユニットテストから、インテグレーションテスト、Herokuへのデプロイまでのビルドパイプラインをスクリプトで記述したものだ。なおここでは、前述の「簡単なビルドパイプラインの構築」と同じ手順でパイプラインとなるジョブを新規作成し、そのジョブにこのスクリプトを入力したものとする(※後述の説明で、このパイプラインとスクリプトを再利用する)。
1
2
3
4
5
6
7
|
node('master') {
stage 'Checkout'
git url: '/Users/yamamotokazuhisa/circle'
stage 'Prepare'
env.PATH = '/usr/local/bin:$HOME/.rbenv/shims:$HOME/.rbenv/bin:$PATH'
sh 'eval "$(rbenv init -)"'
sh 'rbenv local 2.3.1'
stage 'Prepare test'
sh "bundle install"
sh "bundle exec rake db:migrate"
sh "bundle exec rake db:test:prepare"
stage "Unit test"
sh "bundle exec rspec spec/*/*_spec.rb"
stage "Integration test"
sh "bundle exec rspec spec/*/*.feature"
stage "deploy"
sh '''if ! git ls-remote heroku; then
git remote add heroku git@heroku.com:secure-spire-18515.git
heroku keys:add -y
fi'''
sh "git push heroku master"
sh "heroku run rake db:migrate "
}
|
- 1
master
ノードを使用するように設定。 - 2
git
からソースを取得する設定。 - 3
rbenv
を利用可能にする設定を行い、Ruby 2.3.1を選択している。 - 4プロジェクトに必要なgemのインストールおよびテスト用DBを作成している。
- 5ユニットテストを実行している。
- 6インテグレーションテストを実行している。
- 7herokuにプロジェクトをアップロードしている。
git@heroku.com:secure-spire-18515.git
の部分は環境ごとに読み替えてほしい。
Jenkins 2登場前までは、第3回で解説したようにGUI画面でジョブを分割してパイプラインを設定していた。これと比較して、新しいパイプライン機能では、リスト2に示したように、1つのファイルで複数のジョブの内容を管理できるので便利だ。
GitHubでスクリプトの管理を行う
動作の確認ができたら、スクリプトをGitHubで管理しよう(※スクリプトをGitリポジトリで管理する理由は、後述の「まとめ」で説明する)。以下ではその設定手順を説明する。
GitHubへスクリプトの登録を行う
前述の「Railsプロジェクトのビルドパイプラインの構築」で作成したスクリプト(リスト2)を、「Jenkinsfile」という名前でテキストファイルとして保存し、リスト3のようにコマンド実行してGitHubにpush
しよう(GitHubでのプロジェクトの作成方法の説明は割愛する)。
$ vi Jenkinsfile
$ git init
$ git add .
$ git commit -m 'Initial commit.'
$ git remote add origin git@github.com:kazuhisa/jenkins_pipeline.git
$ git push origin master
|
JenkinsからGitHubのスクリプトを参照する
Jenkinsで、前述の「Railsプロジェクトのビルドパイプラインの構築」で作成したパイプラインの設定画面を開き、[Pipeline]タブの項目を次のように変更する。
- 1[Definition]を「Pipeline script from SCM」(※SCM=Source Code Management。ソースコード管理から取得したパイプラインスクリプト)に変更する。
- 2[SCM]を「Git」に変更する。
- 3[Repository URL]に、GitHubで取得できるClone用URLをセットする。ここでは(SSHではなく)HTTPSを使用している。
- 4今回、[Credentials]は指定しないが、プライベートなGitHubリポジトリを利用している場合は、適切な公開鍵を指定しよう。鍵の登録は[Jenkinsの管理]から[認証情報の管理]を選択することで設定できる。
- 5取得するブランチ名を指定する。通常は「master」だが、プルリクエストされた
Jenkinsfile
の動作確認を行うときは変更しよう。 - 6[Pipeline DSL Reference]の右の[?]をクリックすると、スクリプト内で利用できる命令を見ることができる。軽く流し読みしておくことをお勧めする。
以上の設定を行うことで、ジョブの実行時にGitHubからJenkinsfile
(=スクリプト)を取得して、その内容を実行してくれるようになる。
まとめ
Jenkinsで実行するスクリプトをJenkinsfile
で管理することにより、冒頭に解説したデメリットが解消されたと思う。
- 履歴管理ができない: Gitによる履歴管理が可能となった。
- 内容のチェックができない: GitHubのプルリクエストを利用することで第三者のチェックを通過したコードのみ適用されるようになった。
- 設定のコピーが難しい: GUIではなくテキストベースでジョブの内容を管理するためコピーが容易になった。
コードベースでジョブを管理することで 、一般的なアプリケーション開発と同じようにジョブを構築できるようになった。もうJenkinsおじさんを「裏方」と呼ぶ人はいないはずだ。Jenkins 2のパイプライン機能をしっかり活用し、チームのメンバーと共に開発を加速していこう。
以上で本連載は完結だ。今後もまた、大きなアップデートのタイミングなどで、改訂や追記を行う予定である。
1. Jenkinsをインストールして使ってみよう[Mac/Linux/Windows]
継続的インテグレーションツール「Jenkins」の使い方を基礎から解説する連載がスタート。初回は、Jenkinsの概要とインストール手順、簡単なジョブの登録方法を説明する。
2. Jenkinsでテストを実行してみよう+Rubyテストの基礎(RSpec&Turnip使用)
Jenkinsを使って小さなテストを自動実行して、開発スピードを飛躍的に向上させよう。また、MacでのRuby/Rails環境の構築方法から、テストフレームワーク「RSpec」とインテグレーションテスト環境「Turnip」を使ったテストの書き方までを解説する。
3. Jenkinsでアプリケーションをデプロイしてみよう
継続的インテグレーションの手順のうち、デプロイに焦点を当てて、テストの実行から、GitによるHeroku環境へのデプロイまでを自動化する方法を解説。Mac向けのGrowlを使って実行結果を通知する方法も説明。
4. Jenkins+Vagrantでテストを分散しよう
テストの分散は、環境を分けたい場合や速度を上げたい場合に役立つ。Vagrantで複数マシンのテスト環境を構築し、Jenkinsから複数マシンにまたがるテストジョブを実行してみよう。また、お勧めの便利なプラグインも紹介する。