Ruby
Rails
RSpec
docker
wercker

werckerでのビルド時間短縮のためにやった2つのこと

More than 1 year has passed since last update.

はじめに

僕が所属するプロジェクトでは、CIツールとしてwerckerを使ってます。
テストの実行からコードの反映までを、githubへのプッシュをトリガーにして行ってくれるのでとても便利だなーと思うのですが、少し時間がかかるようになってきました(だいたい50分くらい)

ビルド->デプロイ
という流れで処理が実行されます。
ビルドのパイプラインでは、基本的にテストコードの実行(bundle exec rspec)を行っていて、デプロイではcapコマンドを叩いてコードの反映を行っています。

今回着目したのはビルドのパイプラインです。

時間は50分のうちの20分を占めるのですが

  • werckerでは同時に実行できるパイプラインが2つまでという制約
  • ビルドはプルリクエスト状態のすべてのブランチで実行されること

から、ビルド待ちの渋滞ができてしまって、「デプロイしたいけどできないお・ω・」
という状態になってしまっていました。
実行待ちのビルドを停止していって、やっとデプロイしたいリボジトリのビルドが動き始めるという...

時間がかかる要因

ビルドという作業の内訳をもう少し細かく確認していくと

  1. werckerのboxのセットアップ
  2. bundle install
  3. 足りてないツールのインストール、バージョンのアップデート
  4. npm install
  5. gulpの実行でjsファイルをコンパイル
  6. rspecの実行
  7. 出力の保存

というタスクが実行されていました。
それぞれで使っている時間はマチマチだったのですが、毎回ボトルネックになっていたのが3, 4, 6の処理でした。
そのあたりの改善を中心に行いました。

足りてないツールのインストールとバージョンのアップデート(Dockerイメージの作成)

オリジナルのboxを作成することで解決を試みました。
werckerではDockerHubに保存したイメージを利用できることからDockerイメージを作成します。

ベースはruby:2.1.7のイメージを使って必要なツールをインストールしていきます。

$docker run -i -t ruby:2.1.7 /bin/bash

シェルが立ち上がるので、ツールをインストールしていきます。
apt-getを使ってひたすらコマンドを叩いていきます。

必要なツールのインストールが終わったらimageを作成します。exitでコンテナから抜け出します。

$docker pa -a
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                     PORTS               NAMES
1c3f9a438bae        ruby:2.1.7              "/bin/bash"              13 minutes ago      Exited (0) 2 minutes ago                       pedantic_hamilton

先程作成したコンテナがいるので変更をコミットします。

$docker commit 1c3f9a438bae my-ruby-env

これで修正を加えたコンテナのイメージが作成されました。
docker imagesコマンドで確認できると思います。

続いてDockerhubへアップロードします。

$docker tag my-ruby-env g_ryotaro/my-ruby-env
$docker login
ログイン情報の入力を求められるので、入力
$docker push g_ryotaro/my-ruby-env

これでDockerhubに自分のオリジナルイメージがアップロードされました。
werckerでも、このオリジナルのイメージを利用することで、もともと5分かかっていたタスクを4分ほど短縮することができました。

rspecの実行時間を短縮する

テストを並列実行するように設定を行いました。
parallel_tests
導入すると簡単に並列処理することができます。

行った作業は、bundle exec rspecを実行していたコマンドをbundle exec rake parallel:specに変更するだけです。
CPUの数を自動的に判定し、スペックをそれぞれに割り振ってくれます。

これだけで実行時間が10分から5分に減りました。

2つをあわせて、合計9分の短縮が行えました。
およそ半分です。

ハマったこと

オリジナルのイメージを使いはじめて、一部の環境にデプロイする際に失敗するケースがみられるようになりました。
capコマンドを実行している際にsshのコネクションが切れてしまって、次の処理が行われないことが原因でした。

オリジナルのDockerイメージに下記の設定を追加し、問題なくデプロイできるようになりました。

/etc/ssh/ssh_config

ServerAliveInterval 15

まとめ

werckerのビルド時間を短縮するために行った対策をざっと書いてみました。
結果、ビルドにかかる時間は半分になり、ビルド待ちの渋滞は少なくなったのですが、やはりピークの時間帯になると渋滞してしまいます。
今後は、Jenkinsを用いたCIになる予定なので、2つしか実行できないという制限がなくなると思われます。
Dockerhubを使えたり、なかなかいい勉強になったと思いました。