我正在尝试使用 QEMU 构建一个便携式跨架构 Docker 容器。但是,根据主机系统和主机上安装的程序,容器的行为有所不同。
在 Windows 上运行容器,模拟工作正常。它在 Ubuntu 16.04 上也运行良好什么时候qemu-user-static 已安装。但如果不是,它将停止模拟。
只要在主机内核(对于 Linux 上的 Docker)或虚拟机内核(对于 Windows 上的 Docker)中启用了 binfmt 支持,并且容器文件系统中提供了必要的二进制文件,模拟就可以工作。
我的目标是使容器可移植且可运行,而无需将 qemu 注册为内核中的解释器,因为我们的客户禁止对主机操作系统本身或其内核进行任何修改。但目前,这是运行容器的结果:
$ sudo docker run -ti qemu:xenial_arm64
qemu-aarch64-static: /usr/bin/groups: cannot execute binary file: Exec format error
/usr/bin/lesspipe: line 28: /usr/bin/basename: cannot execute binary file: Exec format error
/usr/bin/lesspipe: line 282: /usr/bin/dirname: cannot execute binary file: Exec format error
/usr/bin/lesspipe: line 295: [: =: unary operator expected
qemu-aarch64-static: /usr/bin/dircolors: cannot execute binary file: Exec format error
root@41f2795e2569:/# uname -m
qemu-aarch64-static: /bin/uname: cannot execute binary file: Exec format error
但是,如果我安装 qemu-user-static (通过安装 qemu 也将在 binfmt_misc 中启用):
$ sudo apt-get -yqq install qemu-user-static
Selecting previously unselected package qemu-user-static.
(Reading database ... 245713 files and directories currently installed.)
Preparing to unpack .../qemu-user-static_1%3a2.5+dfsg-5ubuntu10.42_amd64.deb ...
Unpacking qemu-user-static (1:2.5+dfsg-5ubuntu10.42) ...
Processing triggers for man-db (2.7.5-1) ...
Setting up qemu-user-static (1:2.5+dfsg-5ubuntu10.42) ...
$ sudo docker run -ti qemu:xenial_arm64
root@7903b45a3c1e:/# uname -m
aarch64
我对此的解释是:
- qemu-aarch64-static 开始模拟 /bin/bash
- /bin/bash 使用 execve(..) 调用其他一些可执行文件
- Linux主机:
- 如果主机或容器启用了 binfmt_misc(在 Linux 上,主机和 Docker 来宾共享内核),则 qemu 将被动态分配为 arm64 可执行文件的解释器
- 否则,执行将失败并抛出“Exec format error”
- Windows 主机:
- 由于 Windows 和 Linux 具有不同的内核,因此无法通过将系统调用传递到主机内核来执行 Linux 客户机
- 因此,在 Windows 上,容器在具有单独内核的 VM 内运行;然后该内核与容器共享
- 如果带有 binfmt-support 的 qemu-user-static 一旦在任何容器中安装并启用,它仍然可以达到其目的,并动态地将 qemu 分配为另一个体系结构的可执行文件的解释器
在 Linux 和 Windows 上执行会产生相同的结果。
一个可能的修复方法是使用 --privileged 标志启动容器。然后我就可以挂载 binfmt_misc 并从而将 qemu-user-static 注册为容器内的解释器。但我们的客户禁止使用该标志。
我已经测试过所描述的方法这里以及 qemu-user 的 -0 标志。两者都不起作用。
Dockerfile:
FROM scratch
ADD xenial-arm64-rootfs /
ADD qemu-aarch64-static /usr/bin/qemu-aarch64-static
RUN chmod +x /usr/bin/qemu-aarch64-static
ENTRYPOINT ["/usr/bin/qemu-aarch64-static", "-0", "/usr/bin/qemu-aarch64-static"]
CMD ["/bin/bash"]
qemu-aarch64-static 取自 /usr/bin/qemu-aarch64-static (与 qemu-user-static 一起安装) xenial-arm64-rootfs 使用以下命令创建:
qemu-debootstrap --arch=arm64 --components=main,universe,multiverse,restricted --variant=buildd --foreign xenial xenial-arm64-rootfs http://ports.ubuntu.com/ubuntu-ports/
我该怎么做才能让仿真继续进行?