ぱろっと・すたじお

技術メモなどをまったりと / my site : http://parrot-studio.com/

Jenkins CIでRSpecを自動実行する

今回は「Jenkins CI」のお話


http://jenkins-ci.org/


きっかけはGunma.web #4でのLTでした


Gunma.web #4 (on 2011/02/12) まとめ - ぱろっと・すたじお


Jenkins CI(旧Hudson)の話を最初に聞いたのはデブサミ2009?だったと思いますが、
本気で使おうと思ったのはこのLTを聞いて、いくつか質問したときです
(RakeやGitでも使える、的な話)


あと、WEB+DB PRESSでも(テスト関連ツールとして)紹介されていました


WEB+DB PRESS Vol.61

WEB+DB PRESS Vol.61


このVol.61はRails3のテスト手法だけで十分価値があるにもかかわらず、
先日のデブサミ2011で紹介されていた「Titanium」の話や、
話題のScala/Clojureの話まで載ってるので、ぜひ買ってください(`・ω・´)


で、Jenkinsは要するに「自動で何かをしておいてくれる」ツールでして、
今回は「commitしたらテスト」とか「定時テスト」を自動でやってもらい、
ダメだったらメールで通知をもらう・・・という環境を作りました


構築手順そのものは何も難しいことはないので、
後半に「何につまずいたか」をメモしておきます...φ(・ω・`)

環境

  • CentOS5.5(64bit)
  • Ruby1.9.2
    • Rakeはもちろん、RSpec2.xも導入済み
  • OpenJDK6
    • JenkinsはJavaで動ごく
    • warファイルを扱うが、Tomcatのようなコンテナは不要
      • Jenkinsの中に小さなコンテナが含まれるため
  • rakeでspecが実行できる

構築


基本はwarファイルをダウンロードしてきて実行すればいいのですが、
RHEL/CentOS向けにrpmファイルが用意されてますので、
そちらを使うのが簡単です


http://pkg.jenkins-ci.org/redhat/


サイトではyumを使った方法が紹介されていますが、
rpmで導入した場合も /etc/yum.repos.d/jenkins.repo が作られます


ただ、これだとyum実行時に毎回Jenkinsのリポジトリを見にいくことになるため、
それが気に入らない場合は「enable=0」を追加しておいて、
yum実行時に「--enablerepo=jenkins」とした方がいいかもしれません


次に、「/etc/sysconfig/jenkins」にある設定ファイルをいじります
とはいえ、せいぜい変えるのは「JENKINS_PORT」くらいではないかと
「8080」を使ってなければ何も変えなくてOKです


後は起動するだけです
お好みで自動起動の登録も

# service jenkins start
# chkconfig jenkins on


以降は全てブラウザで操作できます
「http://サーバ名:設定ポート」にアクセスすると、
メイン画面が表示されます


まずやることはプラグインの導入です
「Jenkinsの管理 -> プラグインの管理 -> 利用可能」とたどると、
ずらっとプラグイン一覧が出てきますΣ(゚Д゚;≡;゚д゚)


「GitでpushしたコードをRakeで実行する」のが目的なので、
以下のプラグインを入れました

  • git plugin
  • rake plugin
  • ruby plugin


インストールと再起動が終わったら、
「Jenkinsの管理 -> 設定」からGitやRuby、メールの設定を行います


驚いたのが、Ruby/RakeプラグインがRVM*1に対応していることですΣ(・ω・ノ)ノ
RVMの管理PATHを渡すとたぶんRubyを自動で認識してくれそうな予感


今回のサーバはRVMを入れてないし、入れる気もないので、
RubyのインストールPATHをそのまま設定しました


あと、Gitが特殊なPATHに入っている場合、
GitのPATHも設定が必要かもしれません
実行するjenkinsユーザでgitが実行できればOKです

ジョブの設定


これでJenkinsを使う準備ができたので、
今度は「新規ジョブの作成」を行います


いろいろなタイプがあるようですが、
今回の場合は「フリースタイル・プロジェクトのビルド」でOKです
ここでつけた名前がジョブの格納PATHに使われます
(/var/lib/jenkins/jobs/ジョブ名)


後は「何をやってもらうか」を設定していくわけですが、
私が設定したのは以下の項目です

ソースコード管理システム


今回の場合は迷うことなく「Git」を指定します
「URL of repository」にリポジトリの場所(HTTP/HTTPS/Local)を指定します


SSHでアクセスしている場合、jenkinsユーザでアクセスできないとダメです
私はこのパターンに引っかかったので、
開発環境からローカルのリポジトリにpushすることに(後述)

ビルド・トリガ


cronのような書式で、「いつジョブを起動するのか?」を指定します
私が設定したのは以下の二つ

  • SCMをポーリング -> */5 10-19 * * 1-5
    • 平日の10時から19時の間、5分おきにリポジトリをチェック
  • 定期的に実行 -> 15 8 * * 1-5
    • 平日の朝8:15に実行


前者は「新しいcommitがあったら実行」で、
後者は「定時に強制実行」ということです

ビルド


ビルドとは「実行の主体」のことです
今回の場合でいえば「Rakeでspecを実行する」ということになります

cd $WORKSPACE;/usr/bin/rake jenkins:spec


「$WORKSPACE」は実行時に「/var/lib/jenkins/jobs/ジョブ名/workspace」に変換されます
「jenkins:spec」は「spec:all」とやってることは同じですが、
Jenkinsの環境に合わせたhelperをrequireするようにしてます(後述)

ビルド後の処理


実行が終わったら何をするか、です
実行の成功・失敗はブラウザで確認できますが、
「E-mail通知」を設定しておけば、エラー時にメールが飛んできます


他にもいろいろ処理がありますので、
実際に確認してみてください


実行


最後に、「ビルド実行」を選んで一度動作させてみてください
結果はログや「コンソール出力」から確認できます


Rake実行の結果、青いランプが点灯したら、
後は放置するだけです
commit -> pushしてspecが通らなければメールが来ます



個人的に詰まったポイント


・・・とまあ、手順だけ書くとわりと簡単なんですが、
実際にはかなり手間取りました(´-ω-)


せっかくなので、その内容をメモしておきます
特に興味がなければスルーしてください

Ruby1.9.2のインストール失敗


現在メインサーバとテストサーバがあるのですが、
リポジトリはメインサーバにあります


なので、メインサーバでJenkinsを使えばいいのですが、
メインサーバは1.8.7/Rails2で動いているため、
1.9.2/Rails3で動く開発中のシステムは動作しません


設定にRVMがあるくらいなので、それでやろうと思ったら、
なぜか「rvm install 1.9.2」したときmakeでこけるのですΣ(・ω・ノ)ノ


しかも、ソースをダウンロードしてmakeしても同じ場所で落ちるので、
どうもメインサーバの何かが壊れてるんだと思いますが、
無茶なupgradeを繰り返した関係でこれ以上いじりたくないのです


結局、最初からRuby1.9.2/Rails3で動いているテストサーバを使いました

Gitリポジトリ環境


ということで、テストサーバがメインサーバのリポジトリにアクセスすればいいんですが、
SSH接続しか構築してない上、SSH接続に鍵を使っています


となると、jenkinsユーザ向けにSSH鍵環境を作らなければならず、
いろいろ問題が出そうなので、テストサーバにもリポジトリを作り、
開発機からそちらにpushする作業フローにしました


最初は「2カ所にpushとか面倒・・・(´-ω-)」と思ったのですが、
「Jenkinsでspec実行して通ったものだけメインにpush」と考えると、
わりと合理的な気もしてきます

specの環境依存


一番時間がかかったのが、Jenkinsとまるで関係ないspecの問題です


今やっているいくつかのシステムのうち、
Railsに依存しないAPIのコードをJenkinsに適用してみたのですが、
これがJenkins環境で全く動きませんΣ(゚Д゚)ガーン


そもそも、このAPIのspecはRSpecを覚えたばかりの頃に書いたので、
「specを書いて通すこと」が目的になっている上、
環境に依存しまくりで、開発機でしか通らないコードになっていたのです


それこそ、RDGCのspecはspecそのものは汚いですが、
「どこでも実行可能」という点で圧倒的に優れています
複数の人で開発していればもうちょっと考えたと思うのですが・・・


ということで、落ちた箇所を片っ端から外に切り出し、
ひたすらspecのリファクタリングを行った結果
「一応」通るように修正できましたが、丸一日かかりました(´・ω・`)


specの思想的にまずい記述も多々あるのですが、
さすがに一から書き直すには膨大すぎましたし、
一応とはいえ正常に動作しているコードですからね・・・


さすがに後から始めたRails3側のspecはそれよりましですし、
さっきのRails3テスト手法を参考に、
わりと綺麗なspecが書けているので、こっちはすぐ構築できるかと
(このあたりの話はまた機会があれば・・・)




というわけで、今回は「Jenkins CI」を構築した話でしたが、
自動実行する仕組みはJenkinsに限らずいろいろあります


ただ、Jenkinsは開発言語等に依存しないことや、
豊富なプラグインによっていろいろできるという点で、
実に汎用的な仕組みだと思います


特に、テストの数が多くなるほど、
部分的なテストで済ませて全体のテストを忘れがちになるので、
代わりに自動でやってくれるというのはかなり便利です


「自動で時間がかかる何かをしたい」というときにはたいてい使えると思いますので、
ぜひ一度試してみてくださいね(`・ω・´)ノ

*1:良ければ前に私が書いた記事を(´・ω・)っ http://d.hatena.ne.jp/parrot_studio/20110117/1295253527