werckerでDockerfileのテストをする


株式会社リクルートテクノロジーズ Advent Calendar 2014の11日目の記事です。

werckerはDocker Boxのサポートをしています
今つくっているソフトウェアはDockerコンテナとして動作させているため、Dockerfileのテストを行うためにweckerのbox内部でdockerコマンドを実行しています。

はじめはDockerfile内でテストコマンドを実行していたのですが、開発中に気軽にコンテナをビルドしようとするとテストに時間がかかって煩わしくなりました。
最終的に「werckerでdocker build後にdocker runでテスト実行する」という方針にしてみたところ、まあまあいい感じに運用できています。

Dockerfile内でテスト実行する

Dockerfileというものを知ったときには、「この中でテストも全部してしまえば、CI環境でいろいろやらなくてもDockerfile単体で完結する!」と思いつき、実際にDockerfileの中でテストを走らせていたりもしました。

# Dockerコンテナ内部で使う自作gemのインストール
ADD builder /tmp/builder
WORKDIR /tmp/builder
RUN /opt/ruby-2.1.2/bin/bundle install --path=vendor/bundle
# テスト実行
RUN /opt/ruby-2.1.2/bin/bundle exec rake spec
RUN /usr/local/bin/gem build builder.gemspec
RUN /usr/local/bin/gem install builder-0.0.1.gem

しかし、実際にDockerfileを作ってみると、必要なライブラリやソフトウェアをインストールするだけでそれなりに時間がかかります。ここにテストの実行時間も加わると、やる気を削がれます。

また、開発中にDockerfileでADDしているモジュールを修正して試しに動かしてみようとすると、毎回ビルドとテストが走って待ちの時間が入るのでリズムを崩されてしまいます。

werckerでdocker build後にdocker runでテスト実行する

そこでDockerfileからテスト実行コマンドを取り除き、wercker.ymlを以下のように書き換えてみました。

wercker.yml
box: wercker-labs/docker
build:
  steps:
    - script:
        name: docker build
        code: docker build -t pool ./docker/pool
    - script:
        name: run system test
        # 実際には他にオプションを与えているのですが、見やすくするため省略します
        code: |
            sudo docker run -workdir="/tmp/builder" pool  /opt/ruby-2.1.2/bin/bundle exec rspec --tag system_test

1度ビルドしたイメージでコンテナを起動させ、--workdirオプションでテスト対象ディレクトリに移動、コマンドにテスト実行コマンドを指定することでテスト実行しています。
werckerでビルドされたイメージは次のscriptコマンド実行時も保持されているため、

  1. docker build -t <イメージ名>でテスト対象イメージを作成
  2. イメージ作成後にdocker run <イメージ名> <テスト実行コマンド>でテスト

とすることによって、手元でコンテナを立ち上げる分には長時間かかるテストを実行せずにすみます。
werckerはブランチをプッシュすると自動でビルドを実行してくれて、Pull Requestにも実行結果が表示されるため、レビュー時には結合テストも通っているかが確認できます。

(落ちてます。。)

結合テスト環境としてのDockerコンテナについて

werckerに限らず、ビルドパイプライン中で「docker build後にdocker runでテスト実行する」というやり方は結合テストを実行する場合に便利ではないかと思います。
テストを実行する際には、実行環境の状態が等しいというのが理想ですが、毎回AWSのインスタンス+プロビジョニングツールなどの組み合わせでまっさらな環境を用意しているとテスト実行に時間がかかってしまいます。

しかし、テスト実行環境をDockerイメージとしてビルドした後にrunコマンドでテスト実行コマンドを与えてあげれば、毎回同じ状態の環境に対して異なるテストを実行してあげることができます。

結合テストの自動テストをやる際には、このやり方を試してみたいなと思っています。