QEMUをインストールしなくてもARM版のdockerイメージはx86環境下で起動できる


業務の都合で、YoctoベースのARM組込Linux環境をx86_64環境下のDockerで動かす必要があり、[ARM環境のRaspbianイメージをx86上のDockerで動かす](https://qiita.com/hishi/items/61652e2d9755e17630de)を参考にSDカードイメージからdockerイメージを作成しました。その時、手順を間違えて、うっかり`qemu-arm-static`を`/usr/bin`にコピーしてない状態でコンテナを起動してしまったのですが、普通に起動してしまい`qemu-arm-static`をインストールしてしていないことに丸一日気がつきませんでした。

一体どういうことなのか？

気になるので、ARM版nginxの公式dockerイメージをダウンロードしてコンテナを起動し検証してみます。`arm32v7/nginx:latest`だと、apt-getもpsもインストールされていないので色々困りますから`arm32v7/nginx:1.15.12-perl`のイメージを起動します。

```
$ docker run -it -p8080:80 arm32v7/nginx:1.15.12-perl /bin/bash
# ps -ef
bash: ps: command not found
```

psがないなんて軽量化しすぎな気もしますが…　仕方ないのでインストールします。

```
# apt-get update
Get:1 http://security-cdn.debian.org/debian-security stretch/updates InRelease [94.3 kB]
Ign:2 http://cdn-fastly.deb.debian.org/debian stretch InRelease          
Get:3 http://cdn-fastly.deb.debian.org/debian stretch-updates InRelease [91.0 kB]
Get:4 http://cdn-fastly.deb.debian.org/debian stretch Release [118 kB]
Get:5 http://cdn-fastly.deb.debian.org/debian stretch Release.gpg [2434 B]
Get:6 http://security-cdn.debian.org/debian-security stretch/updates/main armhf Packages [477 kB]
Get:7 http://cdn-fastly.deb.debian.org/debian stretch-updates/main armhf Packages [31.5 kB]
Get:8 http://cdn-fastly.deb.debian.org/debian stretch/main armhf Packages [6912 kB]
Fetched 7726 kB in 13s (576 kB/s)                  
Reading package lists... Done
# apt-get install procps
# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 12:23 pts/0    00:00:00 /usr/bin/qemu-arm /bin/bash
root        20     1  0 May16 ?        00:00:00 /bin/ps -ef
```

参照した記事によると、`qemu-arm-static`をコンテナの`/usr/bin`にコピーしないと起動しないそうです。しかし、自分の環境では起動しますし`/bin/bash`は`/usr/bin/qemu-arm`を経由していることになっています。

解せぬ…　（ローゼマイン風味）

ちなみに、自分の環境はmacOS Mojave 10.14.4に以下のDocker for Macをインストールしています。

<img width="585" alt="docker_version.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245269/c6d35cfa-d373-e381-5454-10a935cc9edf.png">

本当に`qemu-arm-static`はインストールされていないのでしょうか？カーネル情報とともに確認してみます。

```
# uname -r 
4.9.125-linuxkit
# find / -name qemu-arm-static
#
```

カーネルはlinuxKitが使われているのでこれだけではARMかどうかは分かりません。しかし、少なくともコンテナ内に`qemu-arm-static`が存在していないことだけは確実です。そこで、先ほどの`apt-get update`で表示されたパッケージのダウンロード元が`armhf`になっているか確認します。

```
Get:8 http://cdn-fastly.deb.debian.org/debian stretch/main armhf Packages [6912 kB]
```

`armhf`がありました。ARM向けのパッケージをダウンロードしていることから、ARM環境が動作していると考えて間違い無いようです。では、nginxを起動してブラウザからアクセスしてみます。

```
# /etc/init.d/nginx start
qemu: Unsupported syscall: 243
2019/05/18 08:43:07 [emerg] 372#372: io_setup() failed (38: Function not implemented)
```

おぅふ…😱

nginxプロセスが起動しているか確認します。

```
# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 00:42 pts/0    00:00:00 /usr/bin/qemu-arm /bin/bash
root       667     1  0 00:54 ?        00:00:00 /usr/bin/qemu-arm /usr/sbin/nginx
nginx      669   667  0 00:54 ?        00:00:00 /usr/bin/qemu-arm /usr/sbin/nginx
root       671     1  0 00:41 ?        00:00:00 /bin/ps -ef
```

とりあえず起動はしているようですので、ブラウザから`localhost:8080`にアクセスしてみます。

<img width="689" alt="browser_access.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245269/3092d747-03af-ffae-8989-a6b973daabaa.png">

ちゃんとアクセスできましたが、エラーが気になります。エラー内容はqemuがサポートしていない命令が使われたということなので、ひょっとすると最新版を`/usr/bin`にインストールすると改善したりするかもしれません。ということで、 [multiarch/qemu-user-static](https://github.com/multiarch/qemu-user-static/releases/download/v4.0.0/qemu-arm-static.tar.gz) から最新版（本日時点では4.0）の`qemu-arm-static.tar.gz`をダウロードしてコンテナ内にインストールしてみます。

`wget`もインストールされていないので、まずはそこから…

```
$ apt-get install wget
$ cd /usr/bin
$ wget https://github.com/multiarch/qemu-user-static/releases/download/v4.0.0/qemu-arm-static.tar.gz
$ tar zxf qemu-arm-static.tar.gz
```

nginxを再起動してみます。

```
$ /etc/init.d/nginx restart
[....] Restarting nginx: nginxqemu: Unsupported syscall: 243
2019/05/18 08:17:58 [emerg] 176#176: io_setup() failed (38: Function not implemented)
```

ダメか…

こちらの [yumでインストールしたnginxが起動時にエラーを吐くの巻](https://blog.trippyboy.com/2013/nginx/nginx-yumでインストールしたnginxが起動時にエラーを吐く/2/) によると、コンパイルオプションを指定してビルドし直さないと治らないようです。

ちなみに、業務で使用しているYoctoベースのARM組込Linux環境では、`qemu-arm-static`を4.0にアップグレードすると発生しなくなりました。

いずれにせよ、最新のDocker for Macの下で動かすのであれば、ARM版のdockerイメージをx86_64環境下で起動し動かすために`qemu-arm-static`をインストールする必要はなく、Docker for Macそのものにマルチアーキテクチャー対応の一部としてその機能は組み込まれているようです。

ただ、このイメージをクラウド上に展開しようとするならば、dockerエンジンのバージョンに依存しなくて済むよう、`qemu-arm-static`をコンテナ内にインストールしておいたほうが無難なように思います。