LoginSignup
21
22

More than 5 years have passed since last update.

Dockerを使った並列テスト

Last updated at Posted at 2013-10-14

みなさん、Dockerを知っていますか?DockerはLinuxコンテナの使用を劇的に簡単にしてくれるツールです。最近、じわじわと人気が出てきてて、QiitaでもいくつかDockerについて記事を書いている人もいます。

DockerはコンテナベースのVM(のようなもの)を提供してくれます。VMが手軽に欲しいならVagrant使えば?とか考えると思いますが、コンテナはVMよりも軽量という利点があります。

軽量の利点は主にふたつあります。

瞬間起動: マシンの起動/停止がめちゃくちゃ早いです。VMなら停止した状態からアプリケーションを実行するまでOSをブートする時間がかかりますが、Linuxコンテナはそんなの全然ありません。マシンを起動した瞬間にアプリケーションを走らせることができます。

複数同時起動: 一度に沢山のインスタンスを起動することができます。VMであれば、いくら動かすアプリケーションを限定してもOSはロードされなければいけないので、それなりにメモリを食います。だから、ひとつのホストで沢山VMを同時に走らせることはできません。Linuxコンテナならできます。もちろん、ホストマシンの性能にもよりますが、VMよりは遥かに沢山です。

Dockerの使いどころ

これらの利点を何に活かすことができるかな??と考えた時、テストの実行環境に使うことを真っ先に思いつきました。テストはできるだけ独立した環境で実行されるのが望ましいので、VMを生成 -> テスト実行 -> 削除 という方法をしている人もいると思いますが、欠点はVMの生成/削除は重いので時間がかかってしまいます。なので、並列でやりたくなりますが前述したようにリソースを食うので沢山のマシンが必要になってしまいます。Dockerなら二つの問題を一気に解決してくれます。

CucumberテストをDockerで並列実行してみよう

Dockerのインストールやイメージの作成は他の人も書いているので省略します。ここでは、イメージからコンテナを起動して、各コンテナにひとつのcucumber featureを実行させるというのをシェルスクリプトをつかってやる方法を紹介します。

前提

  • kimh/ruby-baseというイメージが存在する
  • kimh/ruby-baseにはテストと実行環境が整っている。(つまり、ログインしてbundle exec cucumberとやればテストを実行できる)
  • ローカルマシンの ./features ディレクトリと同じ内容のファイルが kimh/ruby-baseの/git/your_app/features ディレクトリ配下にある
  • 1コンテナ / 1feature で実行する

以下のような簡単なシェルスクリプトで実現できます。

DID=""
container="kimh/ruby-base"
dir="/git/your_repo"

for feature in `find  ./features/`
do
  DID=$DID" "`docker run -d $container /bin/bash -c "
  source /etc/profile
  cd $dir
  export LC_CTYPE="ja_JP.UTF-8"
  export RAILS_ENV=test
  bundle exec cucumber $feature -r features/
  "`
done
docker wait $DID

やっていることをまとめると

1. ./featutes以下にあるファイルを各featureファイルに分割して、feature変数に入れてイテレートする

for feature in `find  ./features/`

2. コンテナを起動して、feature変数のcucumber featureを実行するコマンドを実行して、コンテナIDを変数に格納します。

DID=$DID" "`docker run -d $container /bin/bash -c "
  source /etc/profile
  cd $dir
  export LC_CTYPE="ja_JP.UTF-8"
  export RAILS_ENV=test
  bundle exec cucumber $feature -r features/
  "`

-d はバックグランドでコンテナを起動します。docker runの戻り値はコンテナのIDです。後から状態を確認するのに必要になります。イテレートが終わった時点でDID変数はスペースで区切られたコンテナIDを複数もっています。こんな感じ e106b9fea6c8 20a5059fea048 llff6orfea0dkd

3. すべてのコンテナが終了するまでブロックします

docker wait $DID

docker waitコマンドは与えられたコンテナIDが停止するまで処理をブロックします。全部停止すると各コンテナの最終ステータスコードを表示します。こんな感じ。

$ docker wait e106b9fea6c8 20a5059fea048 llff6orfea0dkd
0
1
0

cucumberはテスト結果をステータスコードで返すので、これだけでどのコンテナのテストが成功/失敗したのかがわかりますね。

詳細を見る

しかし、ステータスコードだけじゃ何が失敗したのかわかりません。
詳細を見るのはdocker logs コンテナIDです。
コンテナの出力を全部見れるので、cucumberの実行ログを見ることができます。今回の例にはないですが、ステータスコードが0でなければ、そのコンテナのログを見るような処理を書けば、何が失敗したのかすぐわかるので便利だと思います。

まとめ

プリミティブな例でしたが、Dockerを使った並列テスト実行のイメージは掴んでもらえたでしょうか?
今回はシェルスクリプトを使ったので沢山のことはできませんが、DockerはRemote APIがあるのでこれを使えばもっと高度なこともできるます。

というわけでbaleenというruby gemを作ってみました。今のバージョンではcucumberのテストを並列実行するだけですが、将来的には他の種類のテストも実行することができる、並列テスト実行ツールを目指して開発しています。

次の記事ではbaleenについて書きたいと思います。

Enjoy Docker!!

21
22
0

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
21
22