CircleCIを導入してみて思ったこと
今メインで関わっているプロジェクトでは半年ほどTravisCIを使っていたけど、 TravisCIはそれなりにお金がかかるということで、 CircleCIを検討してくれないかとの依頼を受けました。
それほど時間をかけずに移行もできてよかったので、今思っていることをまとめてみます。
1. Pricing
TravisCIはOpen Sourceの場合は無料。StartUpが2並列で$129ドル。SmallBussinessが5並列で$249。
CircleCIはSoloが1コンテナで$19, StartUpが2コンテナで$69。1コンテナごとに$50ドルずつ増える。
追記: 2014年末、$19の値下げがあった。1コンテナなら$0、1コンテナごとに$50
OpenSourceで使うならTravisCIでよいけど、プライベートなリポジトリを使う場合はCircleCIは50ドルくらい安い。
2. 性能
速度的にはどちらも問題ない感じ。CircleCIのほうが気持ち早いような気がするけどほぼ誤差の範囲と思います。
TravisCIで12分程度かかっていたテストがCircleCIで11分半くらい。
3. 設定ファイル
TravisCIは.travis.yml、CircleCIはcircle.yml。両方ともおくと挙動が怪しくなるので、切り替えのタイミングではどちらか一方のみにしたほうがよい。
CircleCIは設定ファイルを配置しなくても基本的なテスト項目ならよろしく実行してくれる。
Rubyのプロジェクトの場合、DBを初期化してrspecをまわすくらいなら特に細かい設定は必要ないです。
設定ファイルに互換性はないので、細かなテスト項目や初期化処理が必要な場合はcircle.ymlをしっかり作る必要がある。
これはコストではあるけど、一度作ってしまえばしばらく使い続けるので、十分リターンには見合う感はある。
キャッシュ等の設定もしっかりしておけば全体的なリターンはかなり大きくなる。
Travisでもキャッシュの設定ができるので、gemファイルやテストに使うデータベースなどはキャッシュしておくと高速になる。これについては後述。
4. 並列処理
TravisCIのテスト並列化は、Rubyの場合test-parallelを使うみたい。
CircleCIは複数のインスタンスでテストを実行することでテストを並列化し、高速に実行することができる。
インスタンスを複数たてて実行するため、コンテナの数が確保できるならより高速にテストを実行できる。
ただし、並列テストを行うには自前でバランシングする必要があるので少々手間があるかも。
5. SSH
CircleCIはテストインスタンスにSSHで入れる機能があって、ボタンひとつでgithubに登録してある公開鍵でSSHできる。自前でデータベースなどを準備する場合にこの機能は結構便利で、失敗するテストセットアップを細かく調べることができる。
こんな感じで移行にはあまり困りませんでした。というわけで個人的にはCircleCI最高な感じなのですが、キャッシュと並列処理についてもうちょっとまとめます。
キャッシュ設定
Rubyのgemはbundlerで管理することが多いのですが、gemは遅いので毎回実行するのではなく、キャッシュすることで テスト全体の速度を大きくあげることができる。 それ以外にも、CircleCIでデフォルトでインストールされているデータベースサーバなどとは別のバージョンを使うために、 事前にインストールする設定をcircle.ymlに書いている場合は、毎回ダウンロード・インストールせず、 キャッシュから配置することで速度を上げられる。 この機能はTravisCIにもあるので、.travis.ymlの設定を持ってくるとだいたいうまくいきます。
CircleCIのドキュメントに、Redisをインストールする場合のキャッシュ設定やElasticsearchのキャッシュ設定が 載っているので、この辺りを参考に。
- https://circleci.com/docs/installing-custom-software
- https://circleci.com/docs/installing-elasticsearch
並列処理
並列処理は便利だけど、細かな設定を自前でやらないのがちょっと面倒。 一応ドキュメントはあって、大雑把なrspecの設定が載っていたりはする。
https://circleci.com/docs/parallel-manual-setup
sawanobolyさんのqiita記事とかsakatamさんのgistが参考になって、こんな感じのrspecを実行するスクリプトを用意して circle.yml側にはrspecの代わりにこれを叩くような設定を書いておく。
rubocop
rspecだけでなく、rubocopも並列処理したいって需要はあると思う。 (例のプロジェクトだと1コンテナでの実行は30秒以上かかるけど、2コンテナでやると15秒くらいになる)
rubocopのいい感じのスクリプトは見つけられなかったので、結局いい感じのスクリプトを書くことにしました。 で、PullRequest投げたら横の席の方がいい感じに書き直してくれました。Ruby力不足の厳しさ。
rubocopのYAMLを読むようになっていて、include/excludeをいい感じに処理します。
で、circle.yml、rubocopの代わりにbin/rubocop_parallel
を実行するようにします。
こんな感じでカスタマイズをするのは少し手間ですが、面白な機能がついているのがよいですね。 CircleCIを使う際にはぜひ参考にしてみてください!