Debian armhfなDocker imageを作ってみた

組込み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と呼ばれるもので環境を管理します。DebianUbuntu, 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

 

 

*1:例えば、uname -m に対しては "armv7l" が返ってきます。

*2:仮想化とは異なるものなので、"ホストOSの中に"と書いた方が直観的かも?

*3:Docker Hubを探したらあるかもしれませんが。。

*4:ルートファイルシステムを作るスクリプトKranz Kornerさんのブログ記事を参考にしました。