はじめに
僕が所属するプロジェクトでは、CIツールとしてwerckerを使ってます。
テストの実行からコードの反映までを、githubへのプッシュをトリガーにして行ってくれるのでとても便利だなーと思うのですが、少し時間がかかるようになってきました(だいたい50分くらい)
ビルド->デプロイ
という流れで処理が実行されます。
ビルドのパイプラインでは、基本的にテストコードの実行(bundle exec rspec)を行っていて、デプロイではcapコマンドを叩いてコードの反映を行っています。
今回着目したのはビルドのパイプラインです。
時間は50分のうちの20分を占めるのですが
- werckerでは同時に実行できるパイプラインが2つまでという制約
- ビルドはプルリクエスト状態のすべてのブランチで実行されること
から、ビルド待ちの渋滞ができてしまって、「デプロイしたいけどできないお・ω・」
という状態になってしまっていました。
実行待ちのビルドを停止していって、やっとデプロイしたいリボジトリのビルドが動き始めるという...
時間がかかる要因
ビルドという作業の内訳をもう少し細かく確認していくと
- werckerのboxのセットアップ
- bundle install
- 足りてないツールのインストール、バージョンのアップデート
- npm install
- gulpの実行でjsファイルをコンパイル
- rspecの実行
- 出力の保存
というタスクが実行されていました。
それぞれで使っている時間はマチマチだったのですが、毎回ボトルネックになっていたのが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を使えたり、なかなかいい勉強になったと思いました。