CI始めました

Welcome to Jenkins CI! | Jenkins CI

なんとなく Java はメンドイという思い込みで避けていたんだけど、先週末にちょっと思い立って Jenkins のインストールを試してみた。Debian で試したところものすごく簡単だったので職場にも起こしてみることにした。

DebianにJenkinsをインストール

Debian 6 にJenkinsをインストール - cactusman日誌

を参考に。

まずインストールはとても簡単。各種パッケージシステム用にパッケージが用意されてるから。

自分は Debian を使ったんだけど、上のエントリと java のパッケージが違う以外は

apt-key add
apt-get update
apt-get install

でイケた。これだけで、

  • jenkins ユーザーの作成
  • daemon の起動スクリプトと必要な設定

が展開されるので、あとは

/etc/init.d/jenkins start

するだけ。ここら辺とてもよく Debianize されてる印象。

Debian + Jenkins の考え方

  • jenkins ユーザーでプロセスが動いて
  • jenkins ユーザーのホームディレクトリ以下に各種情報が集まっていく(そういう設定ファイルが自動でセットされる)

ので、この jenkins ユーザーの扱いがキモになる。

インストール後にやったこと

  • jenkins ユーザーのホームディレクトリ変更
    • デフォルトは /var/lib/jenkins 以下になるんだけど、ここはそんなに容量用意してなかったので、別ディスクに移動
    • jenkins の設定ファイルと /etc/passwd のホームディレクトリ設定の両方変えておく1
  • rbenv 環境を用意して jenkins ユーザーは rbenv を通して ruby を起動するように .bash_profile を設定
    • 今はアプリ一つだけど将来的に増えた際にバージョンが合ってない可能性を考慮して2

※ jenkins ユーザーでの作業は su と source で行いました。ログインできる必要ないので。

ジョブはとりあえず全部フリースタイルで

  • LLのジョブしかないのでフリースタイルで
    • rake spec を叩く sh スクリプト、自前のテストスイート実行の sh スクリプトを jenkins のジョブ設定画面から放り込んでおく。現在の jenkins 環境に特有の呼び出し方なのでこれはリポジトリには入れないでおく3

Rails アプリのビルドは以下を参考にした。

Testing Rails apps with Jenkins - komagata

rvm の gemset は使っていないのでもっとずっとシンプル。要するに bundle install, rake db:migrate, rake spec するだけ。

ちょっとハマったこと

  • ジョブ名にスペースを入れると workspace にそのまま反映されて、sh スクリプトやら make やらパスにスペースが入っている場合を考慮していないものが軒並み失敗する
    • スクリプトをいじるのは面倒なのでジョブ名を変更して対処
  • メモリ不足でスコンスコン落ちる
    • rake spec で全部一度に処理しようとするとメモリが不足して jenkins が落ちる

なんとか節約する。

省メモリ Rails アプリ CI

  • spec:* を一つずつジョブに分割
  • 一つだけ SCM をポーリング
  • こいつをトリガにして別なジョブを次々に起こす

Jenkins 用語で言う上流、下流プロジェクトで対処する。

当然ディスクも手間も食うけど、一気に実行してメモリが足りないという状況は回避できる。CI サーバ落ちたら意味ないので苦肉の策。

PHP は Debian 6 の 5.3 のまま使う

実際は 5.1 が production のバージョンなんだけど、5.3 への移行を考えたうえでの CI の導入なので、Debian 6 の標準パッケージである PHP 5.3 をそのまま使うことにした。

本当は PHP についても phpfarm でも使って複数バージョンを動かせるようにするのも手なんだけど、面倒なのでやってない。

workspaceのディレクトリレイアウトに依存したsetup

PHP のアプリが特定のディレクトリツリーを利用しており、この準備を早く確実なものにするために setup 用のスクリプトを用意している。

ビルド用 sh スクリプトの中で $WORKSPACE という変数を使うと workspace のパスを得ることができるので、例えば他のジョブの workspace にある何かを使うといったこともできる。

テストが独立していなかった

rake spec を分割したところ動かない spec がいくつか出てきた。急ぐときは直接 bundle exec rspec spec/**/*.rb で動かしつつ、全体の rake spec は落ちないように注意しながら進めていたんだけど、spec:* 単位で分割したらあちこち落ちて、かつその修正に意外に時間を取られてしまった。

最初の頃は stub すごいと思って喜んで使って、最近は fixture, fixture replacement も適切に使った方がいいよねと考えながら spec を書いてるんだけど、fixture, fixture replacement を使ったときのテストの独立性がちゃんと確保できていなかったらしい。

まだまだ精進が必要だ。

あと期待していること

これでとりあえずの目的は達成できた。今のところ全自動でちゃんとビルドできるものは多くないのでジョブも少ない。ただ今後はもう少し活用できるんじゃないかと思っている。

外部ジョブの監視

Jenkins には XML の POST でジョブの結果を受け付ける機能がある。これは Jenkins の動いているホスト上で直接何かを実行していなくてもジョブの結果だけを扱えるということだ。

例えばあるホストの cron の記録をメールではなく XML にして Jenkins に POST すれば成功、失敗を記録でき、失敗のときだけメールを飛ばすということが可能になる。以前から cron のメールが多すぎてロクに見ないことを問題に感じていたので、これで少し扱いやすくできないかなーと目論んでいる。

p.s. ユニットテスト始めました から6年半か…。ずいぶん経ったな。

  1. 実際には一通り設定し終わってから容量の問題に気づいたのでちょっと苦労した。先にちゃんと設計しよう。 

  2. やはり rbenv rehash を忘れますね… 

  3. 入れて呼ぶ方がビルドスクリプトもバージョン管理できるから良いと書かれてるけど 

More