組込みLinuxを使っていると、ライブラリなどをソースコードからビルドしたいことが度々あるのですが、通常はクロスコンパイルをするか、ターゲットマシンにDebianなどのOSをインストールしてビルドするといった方法を取ります。
しかし、クロスコンパイルする時には大抵クロスコンパイル用のオプションで嵌りますし、ターゲットマシンでビルドするにも遅すぎで、いつも困っていました。
そんな折、QEMUのユーザーモードエミュレーションとbinfmtを使うと、x86マシンの上でarmバイナリを動かすことができることを知りました。
KMC Staff Blog:QEMUのもうひとつの使い方: ユーザーモードエミュレーションとbinfmtとchrootの組み合わせ
このテクニックを使うと、chrootした後の環境で動くプログラムは、あたかもARMマシン上で動いているように錯覚します。*1そのため、x86マシンの強力なCPUパワーを使い、arm用のバイナリをビルドすることができるようになります。
しばらくはこの環境のお世話になっていたのですが、自分一人だけならまだしも、他の人に同じ環境を作らせようとすると、手順を教えるのがなかなか大変なです。
Web業界では、アプリケーションを実行するサーバーの環境を同一に保ち、保守をしやすくするために、仮想化やコンテナと呼ばれる技術を使うようです。これを使えばarm用のバイナリをビルドする環境を簡単に構築できるんじゃないか?と思い、試してみました。
Docker
コンテナとは、ホストOS上に*2名前空間を分離した環境を構築する技術です。Linuxのコンテナとしてはlxcなどもありますが、今回はDocker Hubを使って作成したイメージの配布が容易にできるDockerを使ってみます。
Dockerのインストール
Debian では、jessieやsidにはDocker 1.0のパッケージが追加されていますが、wheezyにはまだ入っていないようです。そのため、get.docker.io からパッケージを取得してインストールします。
$ wget https://get.docker.io/ -O - | sh
$ sudo gpasswd -a user docker
Docker imageの作成
Dockerでは、Docker imageと呼ばれるもので環境を管理します。DebianやUbuntu, Redhat, CentOSなど、大抵のOS用のイメージは最初から用意されているので、通常はそのイメージを使い、自分用の環境を構築します。しかし、さすがにarmhfバイナリを動かすような環境はないでしょうから*3、イメージを自前で作成します。
Docker imageの作成方法は、公式ドキュメントのCreating a Base Imageで解説されています。これを見ると、debootstrapを使ってルートファイルシステムを作り、それをDocker imageに変換するようです。
Docker imageを作成するスクリプトは、dockerの公式リポジトリのcontribディレクトリに含まれています。これを利用して、QEMUのユーザーモードエミュレーションとbinfmtを使ってdebootstrapでルートファイルシステムを作り、Docker imageを作成できるようにしてみました。*4
KoyoTakenoshita/docker at debootstrap-emul · GitHub
下記の手順で、Debian wheezy armhfなDocker imageを作成できます。
$ sudo apt-get install qemu-user-static
$ git clone https://github.com/KoyoTakenoshita/docker.git -b debootstrap-emul
$ cd docker/contib
$ sudo ./mkimage.sh -t USER/REPOSITORY debootstrap-emul --arch=armhf --interpreter-path=/usr/bin/qemu-arm-static wheezy
作成したDocker imageは、Docker Hubに上げてあります。
kytknst/debian-wheezy-armhf Repository | Docker Hub Registry - Repositories of Docker Images
動かしてみる
実際に作成したDocker imageを動かしてみると、下記のようになり、armアーキテクチャと錯覚していることが分かります。
$ docker pull kytknst/debian-wheezy-armhf
$ docker run -i -t kytknst/debian-wheezy-armhf uname -a
Linux ed64794e1dba 3.2.0-4-amd64 #1 SMP Debian 3.2.57-3+deb7u2 armv7l GNU/Linux