在构建容器之前运行 multiarch/qemu-user-static 会做什么?

Kan*_*bot 9 qemu docker

有人可以用简单的术语解释一下什么是

docker run --rm --privileged multiarch/qemu-user-static --reset -p yes -c yes
Run Code Online (Sandbox Code Playgroud)

docker build在从 Dockerfile执行容器之前调用时执行什么操作?

我的想法是允许将其他架构的容器使用到 X86 架构中,但我不确定我是否完全理解我在某些网站上找到的解释。

上述指令( )的存在是否docker run意味着构建阶段的Dockerfile是针对另一种架构的?

cri*_*ret 16

我最近也有这个问题,我没有完整的答案,但这是我所知道的,或者至少相信:

设置和测试

设置的魔力 - 每次重新启动系统都需要一次,就是这样:

# start root's docker (not via any `-rootless` scripts, obviously)
sudo systemctl start docker
# setup QEMU static executables formats
sudo docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# test
docker run --rm -t arm64v8/ubuntu uname -m
# shoudl expect:
# >> aarch64
# optional: shutdown root's docker
sudo systemctl stop docker
Run Code Online (Sandbox Code Playgroud)

请注意,测试示例假设您正在运行您自己的个人“rootless-” docker,因此作为您自己,而不是作为root(也不是via sudo),并且它工作得很好。

血淋淋的细节

...如果您想了解其工作方式/原因,这很重要。

此信息的主要来源:

实现这项工作的基本技巧是将新的“神奇”字符串安装到内核进程空间中,以便当(ARM)可执行文件在 docker 映像内运行时,它可以识别 bin-fmt 并使用 QEMU 解释器(来自multiarch/*docker image) 来执行它。在我们设置 bin 格式之前,内容如下所示:

root@odysseus # mount | grep binfmt_misc
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=35,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=45170)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,relatime)
root@odysseus # ls /proc/sys/fs/binfmt_misc/
jar  llvm-6.0-runtime.binfmt  python2.7  python3.6  python3.7  python3.8  register  sbcl  status
Run Code Online (Sandbox Code Playgroud)

在我们启动(root)dockerd并设置格式后:

root@odysseus # systemctl start docker
root@odysseus # docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
Setting /usr/bin/qemu-alpha-static as binfmt interpreter for alpha
Setting /usr/bin/qemu-arm-static as binfmt interpreter for arm
[...]
root@odysseus # ls /proc/sys/fs/binfmt_misc/
jar                      python3.8        qemu-armeb       qemu-microblazeel  qemu-mipsn32    qemu-ppc64le  qemu-sh4eb        qemu-xtensaeb
llvm-6.0-runtime.binfmt  qemu-aarch64     qemu-hexagon     qemu-mips          qemu-mipsn32el  qemu-riscv32  qemu-sparc        register
python2.7                qemu-aarch64_be  qemu-hppa        qemu-mips64        qemu-or1k       qemu-riscv64  qemu-sparc32plus  sbcl
python3.6                qemu-alpha       qemu-m68k        qemu-mips64el      qemu-ppc        qemu-s390x    qemu-sparc64      status
python3.7                qemu-arm         qemu-microblaze  qemu-mipsel        qemu-ppc64      qemu-sh4      qemu-xtensa
Run Code Online (Sandbox Code Playgroud)

现在我们可以运行 ARM 版本的 ubuntu:

root@odysseus # docker run --rm -t arm64v8/ubuntu uname -m
WARNING: The requested image's platform (linux/arm64/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested
aarch64
Run Code Online (Sandbox Code Playgroud)

该警告是预料之中的,因为主机 CPU 是 AMD,并且可以通过为 docker 指定平台来消除该警告:

root@odysseus # docker run --rm --platform linux/arm64 -t arm64v8/ubuntu uname -m
aarch64
Run Code Online (Sandbox Code Playgroud)

这到底是如何运作的?

其基础是 QEMU 能够插入 DBM(动态二进制修改)解释器,将一个系统的指令集转换为底层平台的指令集。

我们要做的唯一技巧是告诉底层系统在哪里可以找到这些解释器。这就是qemu-user-static图像在注册二进制格式魔术字符串/解释器时所做的事情。那么,那些里面有什么binfmt

root@odysseus # cat /proc/sys/fs/binfmt_misc/qemu-aarch64
enabled
interpreter /usr/bin/qemu-aarch64-static
flags: F
offset 0
magic 7f454c460201010000000000000000000200b700
mask ffffffffffffff00fffffffffffffffffeffffff
Run Code Online (Sandbox Code Playgroud)

嗯 - 这很有趣,特别是因为在主机系统上没有 /usr/bin/qemu-aarch64-static而且它也不在目标映像中,那么这个东西位于哪里?它位于qemu-user-static图像本身中,具有以下形式的适当标记:<HOST-ARCH>-<GUEST-ARCH>,如 中所示multiarch/qemu-user-static:x86_64-aarch64

root@odysseus # mount | grep binfmt_misc
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=35,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=45170)
binfmt_misc on /proc/sys/fs/binfmt_misc type binfmt_misc (rw,relatime)
root@odysseus # ls /proc/sys/fs/binfmt_misc/
jar  llvm-6.0-runtime.binfmt  python2.7  python3.6  python3.7  python3.8  register  sbcl  status
Run Code Online (Sandbox Code Playgroud)

这就是我还不太明白的真正魔法。我相信,不知何故docker,使用该映像来启动 QEMU 解释器,然后从您想要运行的实际映像/容器中向其提供代码,如uname前面的示例所示。一些网络搜索让我对如何实现这种魔法感到不满意,但我猜如果我继续关注这里的链接,我可能会找到这种小手的真正来源。