1つのJenkinsの環境で複数のプロジェクトのテストが実行されることは、ままあると思う。Jenkins上で動作するすべてのプロジェクトが同時に動作するようにJenkins環境を整えるのは難しいことがある。あるプロジェクトのためにライブラリのバージョンを更新したことで、別のプロジェクトのテストが落ちるとか。
Ruby なら Bundler やrbenvを使って環境を切り替えるとだいたい解決するけど、libhogeみたいな共有ライブラリやBundlerやrbenv自体の更新とか、どうしても共有される部分はあって、だいたい普段は問題はないが、まれに困ると言う感じだと思う。
そこで、テストごとにDockerのコンテナを立ち上げてその中でテストを実行するようにすれば、環境を独立させることができるので、環境をこわさないように丁寧に設定するみたいなことに気を使わなくてよくなるので便利。
miyagawaさんのdocker-plenv-vanillaを使うとplenv環境がととのったDokcer imageを作ったりできる。こういう感じでgoが動くDocker imageを作ってgoのテストを動かしてみたので、ご紹介します。
Dockerfile になんか以下のように書く
FROM ubuntu RUN apt-get -y update RUN apt-get -y install curl sudo git build-essential RUN mkdir -p /opt/local RUN curl https://go.googlecode.com/files/go1.2.linux-amd64.tar.gz -o /tmp/go.tar.gz RUN tar -C /opt/local -xzf /tmp/go.tar.gz RUN mkdir -p /gobuild/src RUN mkdir -p /gobuild/go/src/example.com/hakobe RUN ln -sf /gobuild/src /gobuild/go/src/example.com/hakobe/goproject RUN echo 'export GOPATH="/gobuild/go"' >> /gobuild/env RUN echo 'export GOROOT="/opt/local/go"' >> /gobuild/env RUN echo 'export PATH="/opt/local/go/bin:$PATH"' >> /gobuild/env
以下のようにしてimageを作る。
$ docker build -t gobuild .
テストは以下の様なスクリプトを用意しておいて実行する
docker run \ -name gotest \ -v "/path/to/goproject:/gobuild/src" \ gobuild \ sh -c 'cd /gobuild; . /gobuild/env; go test -v ./...' result="$?" docker rm gotest exit $result
ポイントは以下の様な感じです。
- /path/to/goprojectにあるソースコードはdocker run するときに /gobuild/src にmountされる
- goがパッケージ名を解決できるように、/gobuild/srcから /gobuild/go/src/example.com/hakobe/goproject にシンボリックリンクを張っておく
- パッケージ名が go get できる感じになっている場合は、こんなことする必要ないと思う
- 直接 $GOPATH/src以下にmountしてもいいかもしれない
- goの実行環境はバイナリのtarball持ってきて展開すれば作れる
- 実行用の環境変数は /gobuild/env にとっておいて、テスト実行時に source する
- /etc/bashrc? とかで勝手に読み込まれるようにしといても良いかもしれない
- 最後にdocker rm しないとテストを実行するたびにコンテナがmountされたままになる
- コンテナのmountはカーネルプロセスがやっていて、メモリを消費するので、ほうっておくとDockerのホストが爆発する
- Jenkins上でdocker buildしているような体だけど、実際はdocker repositoryとかを活用したら良いと思う