LoginSignup
41
41

More than 5 years have passed since last update.

Jenkinsで高速にbundle installする方法

Last updated at Posted at 2014-10-26

はじめに

JenkinsでRailsのテストやってますか?
肥大化するテストを高速実行するためにテストを複数のJobに分割するというのは有効な手段です。しかし、Railsのテストを行うためにはbundle installによるGemのセットアップが必須です。分割したJobが一斉にbundle installするとトータルでのテスト実行時間は極端に低下してしまいます。
ここでは、時間のかかるbundle installを高速に行うための解説を行います。

なぜbundle installは遅いのか?

bundle installコマンドを叩くことで、bundlerはrubygems.orgから関連ライブラリをダウンロードしローカルにインストールします。しかし、GemによってはC言語で書かれたコードをコンパイルする事がありインストールに時間がかかります。また、複数Jobが一気にrubygems.orgへ問い合わせることでテスト環境のネットワーク帯域も圧迫されます。

Gemfile.lockに変更がなければbundle installは高速じゃん?

gitのbranchが1つしかなければ、あまり問題は無いような気がします。しかし、私のプロジェクトでは開発者が好きなタイミングでbranchを指定してJenkinsを実行できるようになっています。もちろんbranchが違えばGemfile.lockが異なる可能性も考えられます。

キャッシュすることは可能か?

Gemのインストール先はbundleコマンドの--pathオプションで指定することができます。

$ bundle install --path=vendor/bundle

ここで指定したpathはGemfileがあるディレクトリと同じ場所の.bundle/configに書かれます。

---
BUNDLE_PATH: "vendor/bundle"
BUNDLE_DISABLE_SHARED_GEMS: '1'

と、いうことは.bundle/configのBUNDLE_PATHを直接書き換えることができれば、各JobでbundlerがインストールしたGemを共有することができそうです。

シェルスクリプトを作ってみた

RUBY_VERSION=`cat .ruby-version`
GEM_SHA1=`openssl sha1 Gemfile.lock | sed -e s/SHA1\(Gemfile.lock\)=.//`
BUNDLE_PATH=$HOME/bundle_box/$RUBY_VERSION/$GEM_SHA1
if [ -e $BUNDLE_PATH ]; then # すでにbundleが存在すればPATHを書き換え
  mkdir -p .bundle
  cat << EOT > .bundle/config
---
BUNDLE_PATH: "$BUNDLE_PATH"
BUNDLE_DISABLE_SHARED_GEMS: '1'
EOT
else
  bundle install --jobs=2 --path=vendor/bundle
  GEM_SHA1=`openssl sha1 Gemfile.lock | sed -e s/SHA1\(Gemfile.lock\)=.//`
  BUNDLE_PATH=$HOME/bundle_box/$RUBY_VERSION/$GEM_SHA1
  if [ ! -e $BUNDLE_PATH ]; then #bundleが存在しなければmvしてPATHを書き換え
    mkdir -p $HOME/bundle_box/$RUBY_VERSION
    echo $BUNDLE_PATH
    mv vendor/bundle $BUNDLE_PATH
    cat << EOT > .bundle/config
---
BUNDLE_PATH: "$BUNDLE_PATH"
BUNDLE_DISABLE_SHARED_GEMS: '1'
EOT
  fi
fi

ポイントはRubyのバージョンとGemfile.lockのSHA1ハッシュ値でGemの保存場所を切り分けている点です。
このスクリプトをJenkinsのJobでbundle installしている箇所に記述すれば、2回目以降はGemがインストールされることはありません。しかも、各Job共通でGemを使いまわすことができます。
なお、今回はRUBY_VERSIONはローカルの.ruby-versionファイルを利用していますがJenkins側で値をセットして自由なRubyバージョンでテストさせてもいいかもしれません。

さいごに

Jenkinsによるテストを高速化することでプログラムのリリースサイクルが向上し開発者のテンションも上がります。時間がかかっている箇所を探して積極的に高速化に取り組みましょう。

41
41
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
41