昨日のエントリーの続きです。
Gradle万能派の僕には、納得がいかなかったので、最後までやってみることにしました。
切り捨てたこと
まず、分散テストは何が目的なのか考えると、テスト結果をマージすることが目的なので、以下のことは切り捨てました。
- dockerの外でコンパイルしたクラスファイルの共有(昨日のドハマリその2により、共有してもコンパイルしてしまうので諦めた)
src
ディレクトリーの共有(Javaファイルを生成するタスクがある場合はsrc
ディレクトリーの共有をすると、各コンテナがJavaファイル生成を行ってしまうので、諦めた)
【2015/10/20 12:19追記】 つまり、コンパイル結果を共有しても再コンパイルされるので、build
ディレクトリーの共有は諦めました
この結果、妥協するのは次の点です。
共有するファイル
以上から、共有するファイルは以下に絞りました。
caches/modules-2/files-2.1
- dependencyファイルを共有して、無駄にjarのダウンロードを避けるためcaches/modules-2/metadata-2.15
- 上記と同じbuild/test-result
ディレクトリー - 分散してテスト実行した結果を書き込むため
さらに、諦めたこと
昨日はdocker-compose
からdockerコンテナを起動していましたが、docker-compose
から起動すると、何故かbuild/dependency-cache
ディレクトリーの生成に失敗してビルドが成功できないという事象がありました。
- なお、
docker run
からコンテナを起動した場合は、上記のディレクトリー生成に失敗することはありません docker run
からコンテナを複数起動した場合も同様に、上記のディレクトリー生成に失敗することはありませんdocker-compose
からコンテナを一つ起動した場合でも、上記のディレクトリー生成に失敗する
これらの現象を加味した結果、docker-compose
でのコンテナ起動は諦めて、docker run
によって複数スレッドで並行してコンテナを起動する方法を採択しました。
成果
以上をまとめて、複数のdockerコンテナでテストを並列実行するようなサンプルプロジェクトが完成しました。
このプロジェクトのdistTest
を実行すると、dockerコンテナが複数起動してテスト環境を隔離したままテストを並列実行できます。
ログはこんな感じ
$ gradle distTest Picked up _JAVA_OPTIONS: -Dfile.encoding=UTF-8 :buildSrc:compileJava UP-TO-DATE :buildSrc:compileGroovy UP-TO-DATE :buildSrc:processResources UP-TO-DATE :buildSrc:classes UP-TO-DATE :buildSrc:jar UP-TO-DATE :buildSrc:assemble UP-TO-DATE :buildSrc:compileTestJava UP-TO-DATE :buildSrc:compileTestGroovy UP-TO-DATE :buildSrc:processTestResources UP-TO-DATE :buildSrc:testClasses UP-TO-DATE :buildSrc:test UP-TO-DATE :buildSrc:check UP-TO-DATE :buildSrc:build UP-TO-DATE :copyProjectFiles :createTestResultsDir UP-TO-DATE :writeDockerfile UP-TO-DATE :dockerBuild Sending build context to Docker daemon 77.82 kB Step 0 : FROM mikeneck/gradle ---> 1720aa922a94 Step 1 : USER root ---> Using cache ---> 01a3316dc9d8 Step 2 : RUN mkdir -p /home/gradle/.gradle/caches/modules-2/files-2.1 && mkdir -p /home/gradle/.gradle/caches/modules-2/metadata-2.15 && mkdir -p /home/gradle/project/build/dist-test ---> Using cache ---> 1b8cee94ad1e Step 3 : VOLUME /home/gradle/.gradle/caches/modules-2/files-2.1 ---> Using cache ---> 736cda47bacb Step 4 : VOLUME /home/gradle/.gradle/caches/modules-2/metadata-2.15 ---> Using cache ---> 533e5c464749 Step 5 : VOLUME /home/gradle/project/build/dist-test ---> Using cache ---> f7befe5611a8 Step 6 : WORKDIR /home/gradle/project ---> Using cache ---> b20935239c3b Step 7 : ADD src/ /home/gradle/project/src ---> Using cache ---> 1d936eab6fdc Step 8 : ADD buildSrc/ /home/gradle/project/buildSrc ---> dc816d72e386 Removing intermediate container 5c19b832caa7 Step 9 : ADD build.gradle /home/gradle/project/build.gradle ---> 3498c2975adc Removing intermediate container cc9eca27ba49 Step 10 : ADD settings.gradle /home/gradle/project/settings.gradle ---> 4cd61cc8b129 Removing intermediate container 4351a94629ec Step 11 : ADD gradle.properties /home/gradle/project/gradle.properties ---> 5b752a803e30 Removing intermediate container 81cfa4d1944e Step 12 : RUN mkdir -p /home/gradle/project/buildSrc/.gradle && chown -R gradle -R /home/gradle/.gradle && chown -R gradle /home/gradle/project && chown -R gradle /home/gradle/project/build && chown -R gradle /home/gradle/project/build/dist-test ---> Running in 1f6fd2e5a6ad ---> bb126c3e38b8 Removing intermediate container 1f6fd2e5a6ad Step 13 : USER gradle ---> Running in d5f708078091 ---> 83a26282ebe7 Removing intermediate container d5f708078091 Successfully built 83a26282ebe7 :prepareDocker :runTestOnDocker :removeContainer :reportDistributedTest :distTest BUILD SUCCESSFUL Total time: 3 mins 35.146 secs
なお、このテストはjavajo-gradleでくっそ遅いテストとしてテスト並列実行の題材にしたもので、maxParallelForks
を4に設定すると35秒くらいでおわるものです。したがって、上のような妥協した部分がもろに影響して、ビルドが遅くなっているという印象は否めません。
元ネタのツイートから考慮する限り、速度より環境の隔離に重点が置かれているようなので、まあ、ビルドが遅いのは諦めてください。
@johtani 複数台だと嬉しいけど単一マシンでもok。外部依存があるからdockerで隔離しないと並列実行ができないのです。
— たむたむ (@tamtam180) 2015, 10月 16
あと、このプロジェクトはbuildSrc
によってカスタムプラグインを作成しないと、dockerで分散テスト実行できないので、プロジェクトの作りにどうしても依存してしまいます。したがって、汎用的に分散実行するような方法はないと思われます。
また、Gradle plugin portalで調べましたが、docker関連のプラグインはdockerコンテナのマネージ/イメージのDocker Hubへのプッシュなどのものしかないので、やはり分散テスト実行するためには、プロジェクトべったりにプラグイン(buildSrc
プロジェクト)を作りこむ必要があるでしょう。
もし、Gradleに関して、何かご相談があれば、伺いますので、気軽にご相談ください(もち、有償)。
以上