Androidエンジニアは自分専用のDockerイメージを作るべきだと思った

初めてDockerイメージを作ったのでエントリに書いておきます。タイトルはすこし言い過ぎな感じはありますが、CIにDocker使っている人は自分でDockerイメージ作った方がいいよねって話です。

私とCI

CIという言葉もかなり広まり、会社で使うだけではなく個人の開発でもCIを導入している人は多いのではないでしょうか。私はVPN + JenkinsでCIを始めて、1年半前にWerckerに乗り換えました。Jenkinsにはとてつもない自由さやCIがコケた時に原因究明が楽な点がありますが、メンテナンスが大変でした。CIサービスはメンテナンスがあまり必要なくてとても気に入ってます。
Werckerのメリットについては他に書かれている方がたくさんいるので、適当にググって読んでみてください。

WerckerとDocker

私がWerckerに移行した当時はBoxと呼ばれる実行環境でビルドするようになっていましたが、少し前からDockerに差し替わりました。Dockerというキーワードは知っていたもののイメージを作ったことも使ったこともなかったので、適当にイメージを探して他の人のイメージを使わせてもらっていました。しばらくはそれで大丈夫だったのですが、最近この辺でストレスが溜まるようになってきました。

ストレスの原因

一番の理由はAndroidのbuild toolやサポートライブラリのアップデートについていくために実行環境のアップデートをしないといけないのですが、他人のイメージを使っているがために、なかなかアップデートすることができないところです。Dockerfileはオープンソースで公開されているんだからPR出せばいいじゃんという声も聞こえてきそうですが、PRを出したとしてもすぐにマージされるわけではないので、そこでストレスが溜まってしまいます。他の人のライブラリや環境を使うなら当然のリスクですが、プライベートで開発できる時間は限られています。こういった待ち時間があるとついついモチベーションが落ちがちなのでどうにかしたいです。

環境の変化

Android誕生してからもう少しで10年経とうとしていますが、その開発環境は決して枯れることはなく常に変化しています。今もJack and JillやOpen JDK移行などが迫ってきており、今後も開発環境の決定版といえるものはでてこないと思います。

使いたいパッケージの違い

また、人によって使いたいパッケージは異なります。私の場合、CIが終わった後にSlackで通知をしたく、そういったプラグインを使っているのですが、そのプラグインRubyで書かれているためRubyをインストールする必要があります。こういった要望はなかなかPRにすることはできません。

そして自分のDockerイメージを作った

というわけでこのストレスを解消すべく自分でAndroidアプリのビルドができるDockerイメージを作りました。

作ったイメージはdocker hubに公開したので、試してみたいという方はどうぞ

https://hub.docker.com/r/tomorrowkey/wercker-container-android/

DockerfileもGitHubに公開しました。

github.com

できるだけ最新のものにアップデートしていきますしそういったPRも大歓迎ですが、ベストエフォートなのであしからず。そこでストレスが溜まってきたら自分のイメージを作るいいタイミングだと思います。私のリポジトリをforkしてもいいですし、一から作るのもDockerを理解することができると思うのでおすすめです。

メモ

以下、イメージを作るにあたってどう解決したかメモを残しておきます。

OS

FROM ubuntu:14.04

ベースはAndroidのビルド環境によく使われるUbuntuにした。

Oracle Java8のインストール

# Java8 installation
RUN \
  apt-get install -y software-properties-common curl && \
  add-apt-repository -y ppa:webupd8team/java && \
  apt-get update -y && \
  echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selections && \
  apt-get install -y oracle-java8-installer

oracle-javaのインストールはapt-getに新しくリポジトリを追加することでできると知った。

How To Install Oracle Java 8 In Debian Via Repository [JDK8] ~ Web Upd8: Ubuntu / Linux blog

リポジトリ追加したらapt-get updateしてインストール可能なソフトウェアの更新が必要なところに注意

echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | debconf-set-selectionsと書かれているところは使用許諾の同意に必要。

Docker上でOracle Javaの実行はライセンス違反の可能性があるとの情報を得たのでOpen JDKを使うように修正しました。

Dockerコンテナ上でのJavaの実行はライセンス違反なのか?

RUN \
  apt-get install -y software-properties-common curl && \
  add-apt-repository -y ppa:openjdk-r/ppa && \
    apt-get update && \
    apt-get install -y openjdk-8-jdk

OpenJDK8もppaの追加が必要なので、add-apt-repositoryを使ってインストール。以前OpenJDKを使ったときにビルドできないなどの不具合があった気がしたが、いまのところ問題なさそうなのでしばらくこれでやってみようと思います。

Android SDKのインストール

# Android SDK Installation
ENV ANDROID_SDK_REVISION r24.4.1
RUN \
  cd /usr/local && \
  curl -L -O "https://dl.google.com/android/android-sdk_$ANDROID_SDK_REVISION-linux.tgz" && \
  tar -xf "android-sdk_$ANDROID_SDK_REVISION-linux.tgz" && \
  rm "/usr/local/android-sdk_$ANDROID_SDK_REVISION-linux.tgz"
RUN apt-get install -y lib32z1 lib32gcc1

Android SDKのインストールはアーカイブをダウンロードして、配置すればよいと思っていたが、aaptが使うパッケージが足りなかったみたいなので、追加でlib32z1lib32gcc1をインストールしている。実際にCIでビルドしようと思っていたアプリをビルドしてみたらaaptがエラーを吐いていたので何か足りないんだなと分かった。あとは適当に調べてパッケージをインストールした。

androidコマンドがなくなる

RUN echo y | android update sdk --no-ui --force --all --filter "tools"
RUN echo y | android update sdk --no-ui --force --all --filter "platform-tools"

toolsとplatform-toolsを同時にインストールしようとしたが、そしたらandroidコマンドがなくなるという不具合に出会った。別にインストールすると問題なかった。

Rubyのインストール

# Ruby installation
RUN add-apt-repository -y ppa:brightbox/ruby-ng && apt-get update && apt-get install ruby

ビルド終わった後にSlackで通知するようにしているのだが、そのプラグインRubyが必要なのでインストールしている。 当初はrbenvを使ってRubyをインストールするように実装してみたが、rbenvはexport環境変数を設定しようとする。Dockerではビルド中にexportしても無視されてしまうので、素直にrbenvを使うことができない。ではDockerで環境変数を設定するにはどうするかというとENVを使わなければならない。どうにかスクリプトに書き込むことでrbenvを使うことができるようになったが、CI上ではパスが通らなくて調査困難で諦めた。

Rubyのインストールも新しくリポジトリを追加しないといけなかったので、追加してる。

Ruby packages for Ubuntu - Brightbox Cloud

apt-add-repository vs add-apt-repository

リポジトリの追加するコマンドはapt-add-repositoryadd-apt-repositoryがあるみたいで、どう違うか調べた。どちらも一緒らしいので、add-apt-repositoryを使うように揃えた。

Dockerコマンドとか

docker-machineの起動

docker-machine start default

Dockerfileのビルド

docker build .

イメージの列挙

docker images -a

イメージの起動

docker run -it <IMAGE_ID>

コンテナの列挙

docker ps -a

コンテナの停止

docker rm <CONTAINER_ID>

全コンテナの停止

docker ps -aq | xargs docker rm

ネットワークが繋がらなくなる

ルノアールにてdocker buildしようとしたらネットワークが不通になることに少しだけハマった。詳しくはよくわからないが、接続するネットワークが変わったことが原因っぽい。docker-machine restartで再起動すると治った。