maehachi08 Anything Blog

2014年04月26日
JenkinsでRailsアプリの継続的インテグレーション

今回のエントリーは、sample_app というRails4アプリケーションを使ってJenkinsで継続的インテグレーションをおこなうまでの設定備忘録です。

CIツールのJenkins

CI(継続的インテグレーション)とは、コンパイル、ビルド、テスト、デプロイなどを繰り返し行ってコードの品質改善や納期短縮を目指す開発手法です。そして、JenkinsはCIのジョブを定期的に実行し、実行結果をフィードバックしてくれる便利なツールなのです。

Jenkinsは、Git等のバージョン管理の最新コミットを定期的にポーリングして、更新を検知したタイミングでジョブを実行する等が可能です。

Javaインストール

JenkinsはJavaアプリケーションなので、Javaをインストールしておく必要があります。

注意点としては、GNU Compiler for Java(GCJ)のjavaがインストールされている場合はjenkinsが正しく起動しません。GNU Compiler for Java(GCJ)のjavaはyumで"java"とだけ指定した場合にインストールされる可能性があります。

yum install -y java-1.6.0-openjdk

javaバージョン情報が以下のように表示されればOKです。

# java -version
java version "1.6.0_30"
OpenJDK Runtime Environment (IcedTea6 1.13.1) (rhel-3.1.13.1.el6_5-x86_64)
OpenJDK 64-Bit Server VM (build 23.25-b01, mixed mode)

Jenkinsインストール

wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
yum install -y jenkins

インストールされるファイル

jenkinsをインストールして作成されるファイルやディレクトリを説明します。

File Description
/etc/init.d/jenkins 起動スクリプト
/etc/logrotate.d/jenkins log rotate設定ファイル
/etc/sysconfig/jenkins Jenkins設定ファイル
/etc/yum.repos.d/jenkins.repo jenkinsパッケージのレポジトリ設定
/usr/lib/jenkins/jenkins.war Jenkins本体。Jenkinsアップデートはこのファイルを置き換えることになる
/usr/sbin/rcjenkins SUSEディストリビューション用の起動スクリプト
/var/cache/jenkins 『/var/cache/jenkins/war』がドキュメントルートディレクトリ
/var/lib/jenkins jenkinsユーザのホームディレクトリ
/var/log/jenkins ログディレクトリ

上記情報は、CentOS6.5-x86_64上の『jenkins-1.560-1.1』での情報です。

jenkins起動

Jenkinsはデフォルト設定のままでも動作させることが可能です。

service jenkins start 

jenkinsがリッスンするポートの中で、『8080』がHTTPポート、『8009』がApache JServ Protocol version 1.3プロトコルを使用する場合のJenkinsのリッスンポートとなります。

# netstat -antp | grep $(cat /var/run/jenkins.pid )
tcp        0      0 :::8080                     :::*                        LISTEN      16044/java         
tcp        0      0 :::35291                    :::*                        LISTEN      16044/java         
tcp        0      0 :::41662                    :::*                        LISTEN      16044/java         
tcp        0      0 :::8009                     :::*                        LISTEN      16044/java 

Jenkinsダッシュボードへのアクセス

デフォルト設定のまま起動しているのでポート番号『8080』へアクセスします。

  • http:// <IPアドレス> :8080/

以下がトップページの画面です。

Apacheで待ち受けてプロキシさせる

ブラウザからアクセスしたいURLでApacheにアクセスがあった場合に、8080ポートへプロキシするように設定します。また、不特定多数の人にアクセスさせないために最低限の対応としてBASIC認証をかけます。

ポイントは、プロキシ先を8080ポートにすることで/etc/sysconfig/jenkinsには一切手を加えていません。

<VirtualHost *:80>
    ServerName jenkins.example.info

    ProxyPass         /  http://jenkins.example.info:8080/ nocanon
    ProxyPassReverse  /  http://jenkins.example.info:8080/
    ProxyRequests     Off
    AllowEncodedSlashes Off

    <Proxy http://jenkins.example.info:8080/>
        Order deny,allow
        Allow from all
    </Proxy>

    <Location)
        AuthType Basic
        AuthName "basic auth"
        AuthUserFile /etc/httpd/conf.d/jenkins_htpasswd
        Require user jenkins
    </Location>

</VirtualHost>

configtestを実行してエラーが出なければApacheを再起動します。

# service httpd configtest
Syntax OK

# service httpd restart
httpd を停止中:                                            [  OK  ]
httpd を起動中:                                            [  OK  ]

設定したURL http://jenkins.example.info/ へアクセスするとJenkinsのページが表示されるはず!

  • http://jenkins.example.info/

Jenkinsプラグインのインストール

Jenkins Webページへアクセスできるようになったところで、必要なプラグインをインストールします。

今回、インストールするプラグインです。

Plugin Description
Git Plugin JenkinsがGitを扱えるようにする
Rake plugin タスクでrakeを実行可能にする
rbenv plugin ジョブをrbenv環境で実行可能にする
Ruby metrics plugin SimpleCov(RCov)で生成したHTMLをJenkinsがパースすることを可能にする

[ TOP ] > [ Jenkinsの管理 ] > [ プラグインの管理 ] > [ 利用可能 ]タブ で必要なプラグイン横のチェックボックスにチェックを入れて、ダウンロードして再起動後にインストール をクリックします。

すると画面が変わってインストール状況が表示されます。

インストール完了後、ジョブがなければJenkinsを再起動するチェックボックスにチェックを入れると再起動プロセスに移行します。

再起動プロセス中にブラウザで Service Temporarily Unavailable エラーが表示されることがありますが、apacheを再起動してあげるとします。

ちなみに、プラグインがインストールされたかどうかを確認するには、Jenkinsダッシュボードから確認するか、/var/lib/jenkins/pluginsディレクトリ以下を確認することになります。

Jenkinsダッシュボードから確認するには、 [ TOP ] > [ Jenkinsの管理 ] > [ プラグインの管理 ] > [ インストール済み ]タブ を開きます。

または、Jenkinsサーバの/var/lib/jenkins/pluginsディレクトリ以下にプラグイン名のディレクトリが作られてますので、確認します。

# ls -ld /var/lib/jenkins/plugins/{git,rake,rbenv,rubyMetrics}
drwxr-xr-x 5 jenkins jenkins 4096  4月 16 01:23 2014 /var/lib/jenkins/plugins/git
drwxr-xr-x 4 jenkins jenkins 4096  4月 16 01:23 2014 /var/lib/jenkins/plugins/rake
drwxr-xr-x 4 jenkins jenkins 4096  4月 16 01:23 2014 /var/lib/jenkins/plugins/rbenv
drwxr-xr-x 7 jenkins jenkins 4096  4月 16 01:23 2014 /var/lib/jenkins/plugins/rubyMetrics

CVS用の認証情報の追加

今回はジョブ作成のソースコード管理にてGitを選ぶのでSSH鍵を登録する必要があります。

Jenkinsでは、SSH鍵登録は認証情報の管理というページで設定し、ジョブを作成する際には登録したSSH鍵の名称欄に設定した名前をプルタブから選ぶという手順になります。

Jenkinsをインストールするとjenkinsユーザが作成されます。

まず、sudoで変身ユーザにjenkinsユーザを指定してSSH鍵を生成します。ここではパスワード文字列に空文字を指定します。

sudo -u jenkins -H ssh-keygen -t rsa -N '' 

これで/var/lib/jenkins/.sshディレクトリにid_rsaid_rsa.pubが作成されました。

# ls -l /var/lib/jenkins/.ssh/id_rsa*
-rw------- 1 jenkins jenkins 1675  4月 21 20:25 2014 /var/lib/jenkins/.ssh/id_rsa
-rw-r--r-- 1 jenkins jenkins  413  4月 21 20:25 2014 /var/lib/jenkins/.ssh/id_rsa.pub

生成された/var/lib/jenkins/.ssh/id_rsa.pubの内容をBitbucket等のgitレポジトリホスティングサービスのSSH鍵として登録しましょう。ここは利用するサービスによって手順は異なるので詳細は割愛しますが、GithubとBitbucketの場合は以下のようなURLだと思います。

Bitbucketの場合: https://bitbucket.org/account/user/< ユーザ名 >/ssh-keys/
Githubの場合: https://github.com/settings/ssh

では、Jenkins上に使いたいSSH鍵を登録します。

[トップ] > [Jenkinsの管理] > [認証情報の管理]へ移動します。

Item Value
認証情報 SSHユーザ名と秘密鍵
スコープ グローバル
ユーザ名 jenkins
説明 ssh authentication user
秘密鍵 Jenkinsマスター上の~/.sshから

最後に[ 保存 ]をクリックすれば完了です。

rakeプラグインの設定

class="img-responsive" の設定を行います。

このエントリーでおさえておきたいポイントは3点です。

1点目の注意点としては、本項の設定を行わなかった場合、rakeコマンドパスが/usr/bin/rakeとなってしまうという点です。

後述するジョブ登録でInvoke Rakeという設定項目でrakeタスクを指定しますが、デフォルトではRake Version(Default)しか指定できません。(Default)を指定した場合、rakeコマンドパスが/usr/bin/rakeとなってしまいます。

2点目の注意点としては、本項で設定するパス情報についてはrbenv pluginの設定に合わせておく必要があるということです。

このエントリーを書くのにあたり、使用するサンプルアプリケーション『sample_app』はrbenvで管理するruby-2.1.0で動作させることを前提とし、前項でrbenv pluginもインストール済みです。

後述するジョブ登録でrbenv build wrapperというチェックボックスにチェックを入れることで、Jenkinsユーザの実行するrubyをrbenvでインストールすることが可能になります。この時、rakeコマンドパスは/var/lib/jenkins/.rbenv/shims/rakeであり、ruby-2.1.0をインストールした時のRUBY_HOMEは/var/lib/jenkins/.rbenv/versions/2.1.0となります。

[Jenkinsの管理] > [システムの設定] > [Rake]にてJenkinsのビルドで使用するrakeコマンドパスを指定します。

ここで3点目の注意点ですが、Rvm installation pathという設定項目はrakeコマンドパス(ここでは/var/lib/jenkins/.rbenv/shims/rake)を指定する箇所です。

Item Value
Rvm installation path /var/lib/jenkins/.rbenv/shims/rake
Ruby installation - name ruby-2.1.0
Ruby installation - RUBY_HOME /var/lib/jenkins/.rbenv/versions/2.1.0

今の段階ではRUBY_HOMEパスは存在しない(ジョブでrbenvがインストールされる)ので/var/lib/jenkins/.rbenv/versions/2.1.0 is not a directoryという赤字のメッセージが画面に表示されますが、気にせずに[ 保存 ]をクリックします。

これでRake Pluginの設定は終わりです。

RailsアプリケーションにRSpecのテストを書く

本項は既にRSpecテストを書いている場合は不要です。

1. rspec-railsの導入

Gemfileに以下の設定を記述します。

group :test, :development do
  gem "rspec"
  gem "rspec-rails"
end

gemモジュールをインストールします。

bundle install 

2. RSpecを使用するためのHelperクラスを生成

rails generate rspec:install 

3. entryモデルに対するSPECファイルを生成

rails generate rspec:model entry 

spec/models/entry_spec.rb にフィクスチャファイルのデータを読んでテーブルに保存するテストを書く。

require 'spec_helper'

describe Entry do

  fixtures :entries

  it { Entry.new.should be_a_new( Entry ) }

end

spec/fixtures/entries.yml にYAML形式でフィクスチャデータを記述する。

test_01:
  title: 'test'
  body: 'test'

3. entriesコントローラに対するSPECファイルを生成

rails generate rspec:controller entries 

spec/controllers/entries_controller_spec.rb にindexアクションにアクセスして結果を返すテストを記述する。

require 'spec_helper'

describe CuratesController do

  describe "GET index" do
    before do
      get :index
    end

    it do
      response.should be_success
    end
  end

end 

ジョブの登録する

Jenkinsでソースコードのテストを行うジョブを登録します。

[ TOP ] > [ 新規ジョブ作成 ]をクリックします。

ジョブの名前を入力し、ジョブのタイプを選択します。

今回のようにgitなどのレポジトリを監視し、トリガータイミングを設定してビルド・テストを実行する場合はフリースタイル・プロジェクトのビルドチェックボックスにチェックを入れてOKを押します。

詳細ページにて設定します。

Item Value
プロジェクト名 sample_app
古いビルドの破棄 - ビルドの保存日数 5
古いビルドの破棄 - ビルドの保存最大数 5
ソースコード管理 Git
Repository URL git@bitbucket.org:<ユーザ名>/sample_app.git
Credentials jenkins(ssh authentication user)
リポジトリ・ブラウザ bitbucketweb
URL https://bitbucket.org/<ユーザ名>/sample_app
ビルド・トリガ SCMをポーリング
スケジュール H/5 * * * *
ビルド環境 rbenv build wrapper
The Ruby version 2.1.0
Ignore local version checked
ビルド - シェルの実行 export PATH="/var/lib/jenkins/.rbenv/bin:$PATH" eval "$(rbenv init -)" bundle install
ビルド Invoke Rake
Rake Version ruby-2.1.0
Tasks db:setup
ビルド Invoke Rake
Rake Version ruby-2.1.0
Tasks spec
ビルド後の処理 E-mail通知
宛先 sample@sample.com

以上を設定し、[ 保存 ]をクリックします。

手動でジョブを実行してみる

[ トップ ] > [ sample_app ] > [ ビルド実行 ] をクリックします。

暫くするとプロジェクトページトップの左下にあるビルド履歴という欄に実行履歴が表示されます。今回が初回だったので#1となっています。

上記イメージの例でいうと、#1 2014/04/26 13:23:00という文字にマウスカーソルをあわせると右側に印が表示されます。をクリックし、コンソール出力を選択するとJenkinsがジョブで実行したコマンド結果を確認することが出来ます。テストが失敗する場合などはコンソール出力を確認することで原因特定に繋げることも可能です。