不需要安装QEMU,ARM版本的docker镜像可以在x86环境下启动

由于业务需求,需要在x86_64环境下使用Docker运行基于Yocto的ARM嵌入式Linux环境。参考将ARM环境的Raspbian镜像在x86上的Docker中运行的方法,我从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。

docker_version.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]

由于下载了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。

browser_access.png

我已经成功访问了,但是我仍然担心这个错误。错误的内容是说使用了qemu不支持的指令,所以也许将最新版本安装到/usr/bin中可以解决这个问题。因此,我准备从multiarch/qemu-user-static 下载最新版本(目前是4.0)的qemu-arm-static.tar.gz,并尝试在容器内进行安装。

由于未安装wget,因此首先需要安装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 在启动时抛出错误的问题,据说需要指定编译选项重新构建才能解决。

顺便提一下,在我们使用的基于Yocto的ARM嵌入式Linux环境中,如果将qemu-arm-static升级到4.0版本,这个问题就不再出现了。

无论如何,如果您要在最新的Docker for Mac版本下运行,那么您无需安装qemu-arm-static来在x86_64环境下启动和运行ARM版的docker镜像,因为该功能已经作为Docker for Mac的多种架构兼容的一部分内置进去了。

如果您希望将此映像部署到云端,为了不依赖于Docker引擎的版本,在容器内安装qemu-arm-static可能是一个不错的选择。

广告
将在 10 秒后关闭
bannerAds