谁能简单地解释一下
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes -c yes
在执行docker build
之前,调用Dockerfile中的容器时做什么?
我的概念是允许将来自其他体系结构的容器使用到X86体系结构中,但我不太明白我在某些站点中找到的解释。
上述指令(docker run
)的存在是否意味着构建阶段的Dockerfile用于另一个体系结构?
发布于 2022-07-06 21:48:45
我最近也有这个问题,我没有一个完整的答案,但我知道,或者至少我相信:
设置和测试
每次重新启动系统都需要设置一次,其神奇之处就是:
# 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
请注意,该测试示例假设您运行的是您自己的“无根”docker
,因此它是以您自己的身份运行,而不是以root
(或通过sudo
)的身份运行,而且它的工作原理非常好。
血淋淋的细节
..。如果您想要了解,了解是如何/为什么工作的,那么哪些内容很重要。
这些信息的主要来源:
buildx
建立多/交叉拱图像)qemu-user-static
的替代品)完成这项工作的根本诀窍是将新的“魔术”字符串安装到内核进程空间中,以便当(ARM)可执行文件在坞映像中运行时,它会识别bin-fmt并使用QEMU解释器(来自multiarch/*
坞映像)来执行它。在设置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
启动(根的) 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
现在我们可以运行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
由于主机CPU是AMD,所以需要发出警告,并且可以通过将平台指定为docker来消除:
root@odysseus # docker run --rm --platform linux/arm64 -t arm64v8/ubuntu uname -m
aarch64
这到底是怎么回事?
在此基础上,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
嗯--这很有趣,特别是因为在主机系统上没有 /usr/bin/qemu-aarch64-static
,而且它也不在目标图像中,那么这个东西住在哪里呢?它在qemu-user-static
映像本身中,带有适当的表单标记:<HOST-ARCH>-<GUEST-ARCH>
,就像在multiarch/qemu-user-static:x86_64-aarch64
中一样。
# Not on the local system
odysseus % ls /usr/bin/qemu*
ls: cannot access '/usr/bin/qemu*': No such file or directory
# Not in the target image
odysseus % docker run --rm --platform linux/arm64 -t arm64v8/ubuntu bash -c 'ls /usr/bin/qemu*'
/usr/bin/ls: cannot access '/usr/bin/qemu*': No such file or directory
# where is it?
odysseus % docker run --rm multiarch/qemu-user-static:x86_64-aarch64 sh -c 'ls /usr/bin/qemu*'
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "sh": executable file not found in $PATH: unknown.
# Hmm, no `sh` in that image - let's try directly...
odysseus % docker run --rm multiarch/qemu-user-static:x86_64-aarch64 /usr/bin/qemu-aarch64-static --version
qemu-aarch64 version 7.0.0 (Debian 1:7.0+dfsg-7)
Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers
# AHA - there it is.
这才是真正的魔法,我还不太明白。在某种程度上,我认为docker
正在使用该映像来旋转QEMU解释器,然后从您想要运行的实际映像/容器中将代码提供给它,正如前面的uname
示例所示。一些网络搜索让我无法满足于这个魔法是如何实现的,但我猜想,如果我继续跟踪链接从这里,我可能会找到真正的来源,轻微的手。
发布于 2022-10-13 07:29:51
为了补充@crimson的回答:fix-binary
标志在binfmt_misc
中被用来使静态编译的qemu模拟器在不同的名称空间/色度/容器中工作。
在文档 for binfmt_misc
中,您可以找到fix-binary
标志的解释:
F- fix二进制 binfmt_misc的通常行为是在调用misc格式文件时懒洋洋地生成二进制文件。但是,面对挂载名称空间和变更,这并不能很好地工作,因此F模式在模拟安装后立即打开二进制文件,并使用打开的映像生成仿真器,这意味着无论环境如何更改,一旦安装,它总是可用的。
这个错误报告还解释了:
..。binfmt的fix-二进制标志是专门用来处理这个问题的。解释器文件(例如qemu静态)是在安装binfmt规则时加载的,而不是在遇到需要它的文件时加载的。当内核遇到一个需要解释器的文件时,它只是执行已经打开的文件描述符,而不是打开一个新的文件描述符(IOW:内核已经打开了正确的文件描述符,因此可能不同的根在查找解释器时不再发挥作用,从而允许像本机那样运行外部架构的名称空间/容器/色度)。
如果使用不带-p yes
选项的qemu -user静态映像,将不会添加fix-binary
标志,运行arm64容器将无法工作,因为现在内核实际上将尝试在容器的根文件系统中打开qemu模拟器:
$ docker run --rm --privileged multiarch/qemu-user-static --reset
[...]
$ cat /proc/sys/fs/binfmt_misc/qemu-aarch64
enabled
interpreter /usr/bin/qemu-aarch64-static
flags:
offset 0
magic 7f454c460201010000000000000000000200b700
mask ffffffffffffff00fffffffffffffffffeffffff
$ 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
exec /usr/bin/uname: no such file or directory
failed to resize tty, using default size
https://stackoverflow.com/questions/72444103
复制相似问题