背景
Dockerで、armhfなクロス環境のコンテナができると、Raspberry piでのアプリケーション開発が捗ります。
クロスコンパイラで可能ですが、apt-get等でライブラリ等をインストールするとなると、尚更敷居が高く感じます(といいますか、やり方知らないだけです…)。また、x86で作成して、Raspbianでリビルドしても、ディストリビューションの違いから、リビルドエラーや実行時エラーがでて、その手間も馬鹿にできません。
クロス環境のコンテナを動かすには、binfmtが必要となりますが、CentOS等、提供されていないディストリビューションもあります。このような背景を受けて、他ディストリビューションでもクロス環境ができないか試行錯誤してみました。
種明かし
最初に種明かしをしておきます。binfmtの環境をホストに作るのではなく、コンテナ上で動かしてchrootします。その際のポイントとして、
- binfmt_miscをコンテナ実行時にマウントする
- /proc/sys/fs/binfmt_misc/registerにarmefなELFを書き込む
- コンテナ実行時はSYS_ADMIN,SYS_CHROOTを--cap-add で追加する
で実行できます。
Dockerfile
FROM ubuntu
RUN apt-get update && apt-get -y upgrade \
&& apt-get install -y \
qemu-user-static \
binfmt-support \
vim
RUN mkdir /raspi-root \
&& mkdir /app
ADD root.tar.gz /raspi-root
ADD start.sh /
RUN chmod +x start.sh
WORKDIR /raspi-root
CMD ["/start.sh"]
qemu-user-staticとbinfmt-supportがあれば十分です。rootイメージについては、"Raspbianをdebootstrapから作る"を参考にしてください。
start.sh
cd /raspi-root
mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:' > /proc/sys/fs/binfmt_misc/register
mount -t sysfs sysfs sys/ && \
mount -t proc proc proc/ && \
mount -o bind /dev dev/ && \
mount -o bind /dev/pts dev/pts
exec chroot . 動かしたいもの
実行時は、chrootの一般的なmountとbinfmt_miscのmount及びELFイメージの書き込みだけです。
(※sysfs,proc,devのmountは無くても問題ないかと思います。必要に応じてでいいかと…)
コンテナ実行
docker run -it --rm \
--name コンテナ名 \
--cap-add SYS_ADMIN --cap-add SYS_CHROOT \
イメージ名
です。
その他
上記の内容でDocker for Windows(Hyper-V版)で問題なく動いてます。多分、CentOS,CoreOS等でも実行できると思います。
コンパイル速度はクロスコンパイルに比べると、かなり遅くイライラします。が、あれこれ環境を作るよりも簡単ですし、本番環境も全く同じ環境でリビルドできたりするので、トータル的には良しとしています。