ご無沙汰気味です。ひさびさのブログ更新。そして今回は真面目なお仕事の話題。
今行っている現場にはCI環境が無かったので、Jenkins使って自分で作ることにしました。
自分でイチからJenkins構築するのは初めてだったのですが、意外となんとかなるもんです。ググれば大抵のことはなんとかなる。
色々苦労しながらJenkins環境を作ったのですが、動いてるマシンの環境に依存しまくり。
ローカルで動かしているので、私が普段使っている開発環境をそのまま使っている状態になっていました。
これはよくない。マシンの環境に依存せずにビルドできるようにしたい。
というわけで、前々から気になっていたDockerを使ってJenkins 環境を作り直すことにしました。
ついでに、AndroidのビルドもDocker上でするようにします。
Dockerでビルドする用のシェルスクリプトはプロジェクトの中に含めるけど、DockerでのビルドはJenkins専用になってしまわないように、プロジェクト側はJenkinsを意識しないように気をつける。
ホストマシンはMac。DockerでJenkins用コンテナを立ち上げて、そこから更にDockerでAndroidのビルド用コンテナを起動してビルドする。
DockerからDockerを起動する手法はdood(Docker outside of Docker)というホストマシンのDockerを共用する手法を使う。詳しく知りたい方はGoogle先生に聞いてみてください。
参考までに、Jenkins用コンテナの起動コマンド。
CURRENT_DIR=pwd
docker run \
-u root \
-p 8080:8080 \
-p 50000:50000 \
-v "${CURRENT_DIR}/jenkins_home:/var/jenkins_home" \
-v /var/run/docker.sock:/var/run/docker.sock \
-e "HOST_JENKINS_HOME=${CURRENT_DIR}/jenkins_home" \
-e JAVA_OPTS='-Xms512m -Xmx1024m' \
jenkinsci/blueocean
Androidのビルド用コンテナは起動されたらマウントされたディレクトリ直下にあるbuild.shを叩いてビルドする。
JenkinsはJobが実行されると、Gitからソースコードをcloneしてきて、直下にあるdocker-build.shを叩いてAndroidのビルド用コンテナを起動する。
docker-build.shにはソースコードをマウントしてAndroidのビルド用コンテナを起動するスクリプトを書いている。
ここでハマったのがマウントの仕方。DockerはホストマシンのDockerを使っているから、ホストマシン目線でPathをフルパスで指定する必要があった。
Jenkinsが動いているコンテナからは/var/jenkins_home/だけど、ホストマシンからすると/Users/ユーザ名/jenkins/jenkins_home/だったりするから、上手くマウンド出来ていなかった。
このことに気づかず、めちゃくちゃ苦労した。Docker初心者にdoodは荷が重すぎた。
これを解決するために、ホストマシンからJenkinsのコンテナを起動する時、環境変数にJENKINS_HOMEのパスを設定するようにした。Jenkins用コンテナの起動コマンドにあるHOST_JENKINS_HOMEがソレ。
Jenkins用のコンテナではカレントディレクトリのパスのjenkins_homeまでの部分を、環境変数に設定されているパスに置換してマウントするようにして対応。なんかスマートじゃない気がするけど、とりあえず動いてる。
もうひとつ困ったのが、Jenkinsのジョブ名に半角スペースが入りがちなので、そこの考慮に苦労した。半角スペース禁止の運用にしようかと何度思ったことか……。
そして最後に悩むことになったのがメモリ問題。
はじめ、メモリ不足でビルドがエラーになってたので、Jenkinsコンテナのrunに-Xmx2048mを指定してJavaのヒープを増やしたらコンテナ自体が落ちるようになった。
何の情報も無く、突然落ちやがるから原因が特定できずに苦労した。
結局、コンテナのメモリ容量が2GBで、そこにJavaのヒープメモリ最大値を2GB設定していたのでメモリ不足で落ちてたみたい。メモリ容量は-Xmx1024mにすることにした。
そしてビルドエラーになっていた原因はJenkinsコンテナではなく、Androidのビルド用コンテナの方だった……。そりゃそうですよね。ビルドしてるのそっちだもん。
Kotlinのビルドするのにメモリ2GBじゃ足りないみたいなので、これはもうコンテナ自体のメモリ容量を増やすしかない。
MacにインストールしたDocker Desktopの設定からメモリ容量を8GBに増やして解決。ホストマシンのメモリは32GBあるから無敵。
これにより、Jenkinsコンテナもメモリ容量8GBになったけど、-Xmx1024mで別に問題なさそうなので、これはそのままにした。
Jenkinsでやっていることを箇条書きにするとこんな感じ。
・Gitからプロジェクトをcloneしてくる
・JENKINS_HOMEに保持しているkeystoreファイルをプロジェクトの中にコピーする
・app/build.gradleを編集してkeystoreファイルのパスを指定する
・プロジェクト直下のdocker-build.shを叩く、その時にホストマシン目線の作業ディレクトリのパスを引数で渡す
・ビルド結果の成果物を圧縮する
これにて一件落着。大変だった……。大変だったけど、経験値がモリモリ増えた気がする!
今回はDocker Composeを使わずに環境を作ったけど、ググって色々調べているとDocker Composeを使った方がDockerの設定はキレイに書けそう。
今後、仕事でもDocker使う場面は出てくるだろうから、今のうちに慣れておきたいなー。