如何从 Docker 容器内检测 QEMU 模拟?

Rah*_*ibo 7 arm qemu docker debian-buster apple-m1

从 docker 容器(在我的例子中运行基于 Debian Busty 的映像)中,如何检测它是否在 QEMU 模拟下运行(如在 ARM Mac 上运行 AMD64 映像)?

从非 docker 的角度来看,我看到了cpuinfo可能会出现这种情况的建议,但当从容器内部运行时,它不会产生任何与 QEMU 直接相关的内容:

$ docker run -it --entrypoint /bin/bash debian-buster-based-amd64-image

WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested

root@c93f6a8ec754:/app# cat /proc/cpuinfo
processor   : 0
BogoMIPS    : 48.00
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm ssbs sb paca pacg dcpodp flagm2 frint
CPU implementer : 0x00
CPU architecture: 8
CPU variant : 0x0
CPU part    : 0x000
CPU revision    : 0

processor   : 1
BogoMIPS    : 48.00
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm ssbs sb paca pacg dcpodp flagm2 frint
CPU implementer : 0x00
CPU architecture: 8
CPU variant : 0x0
CPU part    : 0x000
CPU revision    : 0

# ...etc
Run Code Online (Sandbox Code Playgroud)

带有 QEMU 的 Docker 不支持容器内某些功能所依赖的功能(inotify 文件系统事件) - 我希望切换容器内的行为以避免库尝试使用它时发生崩溃。

jor*_*ski 7

有很多方法可以检测容器是否在模拟下运行,但是最可靠的方法是使用识别入口点是否被模拟。

当容器被创建时,入口点将成为PID 1。Docker用于qemu模拟的机制将检测到入口点是针对不同的架构,并且将涉及模拟器来模拟该架构。您可以阅读有关本文中使用的机制的更多信息。

由于将模拟入口点,因此进程名称将替换为qemu-xxxxxxxx要模拟的架构。如果我们像下面的例子那样qemu调用,我们可以确定我们的入口品脱过程是否被替换:ps -uax

docker run -it --entrypoint /bin/bash amd64/ubuntu                                                                                                                                  
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
root@043bd4f57ca8:/# ps -uax
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.7  0.1 149280 13804 pts/0    Ssl  07:08   0:00 /usr/bin/qemu-x86_64 /bin/bash /bin/bash
root        22  0.0  0.1 150404  9564 ?        Rl+  07:04   0:00 ps -uax
Run Code Online (Sandbox Code Playgroud)

利用这种知识来检测我们是否被模拟的一种简单方法是获取pmapPID 1检查响应中是否存在qemu( 的计数qemu大于 0)

root@043bd4f57ca8:/# pmap 1 | grep qemu | wc -l
5
Run Code Online (Sandbox Code Playgroud)

pmap报告进程的内存映射以及从哪个二进制/库创建内存段,本例中的结果如下所示:

root@043bd4f57ca8:/# pmap 1
1:   /usr/bin/qemu-x86_64 /bin/bash /bin/bash
0000000000200000    724K r---- qemu-x86_64
00000000002c4000   1652K r-x-- qemu-x86_64
0000000000470000    236K rw--- qemu-x86_64
00000000004ba000     84K rw--- qemu-x86_64
00000000004cf000    128K rw---   [ anon ]
0000000017053000      4K -----   [ anon ]
0000000017054000     16K rw---   [ anon ]
0000004000000000    180K r---- bash
000000400002d000    708K r---- bash
00000040000de000    220K r---- bash
0000004000115000     16K r---- bash
0000004000119000     36K rw--- bash
0000004000122000    460K rw---   [ anon ]
000000400112c000      4K -----   [ anon ]
000000400112d000   8192K rw---   [ anon ]
000000400192d000      4K r---- ld-2.31.so
000000400192e000    140K r---- ld-2.31.so
0000004001951000     32K r---- ld-2.31.so
0000004001959000      4K -----   [ anon ]
000000400195a000      4K r---- ld-2.31.so
000000400195b000      4K rw--- ld-2.31.so
000000400195c000     12K rw---   [ anon ]
0000004001961000     56K r---- libtinfo.so.6.2
000000400196f000     60K r---- libtinfo.so.6.2
000000400197e000     56K r---- libtinfo.so.6.2
000000400198c000     16K r---- libtinfo.so.6.2
0000004001990000      4K rw--- libtinfo.so.6.2
0000004001991000      8K rw---   [ anon ]
0000004001993000      4K r---- libdl-2.31.so
0000004001994000      8K r---- libdl-2.31.so
0000004001996000      4K r---- libdl-2.31.so
0000004001997000      4K r---- libdl-2.31.so
0000004001998000      4K rw--- libdl-2.31.so
0000004001999000    136K r---- libc-2.31.so
00000040019bb000   1504K r---- libc-2.31.so
0000004001b33000    312K r---- libc-2.31.so
0000004001b81000     16K r---- libc-2.31.so
0000004001b85000      8K rw--- libc-2.31.so
0000004001b87000     28K rw---   [ anon ]
0000004001b90000     12K r---- libnss_files-2.31.so
0000004001b93000     28K r---- libnss_files-2.31.so
0000004001b9a000      8K r---- libnss_files-2.31.so
0000004001b9c000      4K r---- libnss_files-2.31.so
0000004001b9d000      4K rw--- libnss_files-2.31.so
0000004001b9e000     24K rw---   [ anon ]
0000ffff78916000   1808K rw---   [ anon ]
0000ffff78ada000 131068K rwx--   [ anon ]
0000ffff80ad9000      4K -----   [ anon ]
0000ffff80ada000   1196K rw---   [ anon ]
0000ffff80c05000      8K -----   [ anon ]
0000ffff80c07000    140K rw---   [ anon ]
0000ffff80c2a000      8K r----   [ anon ]
0000ffff80c2c000      4K r-x--   [ anon ]
0000ffffd61bc000    132K rw---   [ stack ]
 total           149536K
Run Code Online (Sandbox Code Playgroud)

需要注意的是,当我们想要在 Intel 下模拟 ARM 时,这同样有效,如下例所示:

root@9bd90133ebee:/# ps -uax
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.6  0.1 151208 13560 pts/0    Ssl  06:57   0:00 /usr/bin/qemu-aarch64 /usr/bin/bash

root@9bd90133ebee:/# pmap 1
1:   /usr/bin/qemu-aarch64 /usr/bin/bash
0000000000200000   1408K r---- qemu-aarch64
0000000000360000   3304K r-x-- qemu-aarch64
000000000069a000    408K rw--- qemu-aarch64
0000000000700000     48K rw--- qemu-aarch64
000000000070c000    136K rw---   [ anon ]
0000000001d5a000      4K -----   [ anon ]
0000000001d5b000     12K rw---   [ anon ]
0000005500000000   1132K r---- bash
....
Run Code Online (Sandbox Code Playgroud)