CircleCIで Androidアプリも楽ちんにビルドできるのはいいのだけど、調子に乗って Flavorを増やしていったりすると OOMで殺されがちです。ヒープとかを頑張ってチューンするのにつかれた自分は金にモノを言わせて 3つのコンテナを使って並列ビルドするようにしました。
CircleCIではコンテナごとに 4GiBつかえる!
つまりコンテナを増やして仕事を分割すれば OOMを気にすることなく高速にビルドができるのです。実際はすべてのコンテナでしなきゃいけない仕事があったりするので単純にスケールするものでもないのでしょうが、それでも自分の環境では十分効果が上がりました。
やったこと
仕事でやったことなので repositoryを公開はできませんが概略を書きます:
containerごとに buildを分割
testステージ用の buildスクリプトをつくり、そこで $CIRCLE_NODE_INDEX
にしたがって処理を振り分けるコードを書きました。以下の様な感じです:
case $CIRCLE_NODE_INDEX in
0)
TERM=dumb ./gradlew assembleFoo testFoo{Debug,Release}UnitTest -PdisablePreDex
find app/build/test-results/* -type f -name '*.xml' -exec cp {} $CIRCLE_TEST_REPORTS \;
;;
1)
TERM=dumb ./gradlew assembleBar testBar{Debug,Release}UnitTest -PdisablePreDex
find app/build/test-results/* -type f -name '*.xml' -exec cp {} $CIRCLE_TEST_REPORTS \;
;;
2)
# Instrumentation test
echo no | android create avd --name emu --target android-15 --abi armeabi-v7a
nohup bash -c "emulator @emu -no-window &"
nohup bash -c "adb logcat > app/build/outputs/logcat.txt &"
TERM=dumb ./gradlew connectedFooDebugAndroidTest -PdisablePreDex
find app/build/outputs/androidTest-results/connected -type f -name '*.xml' -exec cp {} $CIRCLE_TEST_REPORTS \;
;;
esac
コンテナ #0と #1は、それぞれの flavorの APKをつくり Unit testを通します。
コンテナ #2では、Foo flavorでだけで instrumentation testを走らせます。
もう一つコンテナを増やして Bar flavorでも instrumentation test走らせられますが、それはケチってます。
あ、あと上の buildでは wait_for_emulator
的な処理を gradleの中でやっています。並列ビルドにしたからといってその待ちが必要なくなるわけではないのでご注意を。
なぜか最新の data binding libraryが入ってなかったので取得
あと、なぜか並列ビルドすると data binding libraryが見つからず buildが failしました。CircleCIのサポートに聞いてみたのですが、まだちゃんと返事をもらってません。並列用だとイメージが違ったりするのでしょうか?
そこで dependenciesステージで強引にもってくる workaroundを入れました:
dependencies:
override:
- ./script/load-dependencies.sh
#!/bin/bash -e
echo install extra-android-m2repository
echo y | android update sdk --no-ui --all --filter 'extra-android-m2repository'
こんな感じで強引に持ってきてますが、1分ぐらい余計に時間がかかります。何もしなくてもいいようにしたいものです。
まとめ
以上のような変更でビルドを走らせることにより out of memoryを回避できています。おまけに、ビルド時間も短くなりました。22分ぐらいが 14分ぐらいに。1/3になってないのは、すべてのコンテナでやる仕事がばかにならないからですね。
しかし、data binding libraryが見つからないとか、Androidで並列ビルドしてる人が少ないせいで地雷を踏んでしまったのでしょうか。みなさんも試してみていっしょに地雷を踏んでもらうことを期待します。