0x00 前言
缘起于使用 MBP M1 Arm64 构建的 docker 镜像推到 Amd64 架构的测试环境中可以正常运行,好奇 Docker 是怎么实现的。
0x01 docker multi-platform 原理
参考 Manuals / Docker Build / Building images / Multi-platform images,Docker 通过两个方面使 docker 镜像可以一次构建,多平台运行:
- 通过 buildx 可以一次构建多个平台的镜像,或者在 docker build 时通过
--platform
指定构建镜像的运行平台; - 通过 binfmt_misc 和 QEMU 模拟运行不同于当前平台的镜像;
运行环境需要满足以下条件:
- kernel >= 4.8
- binfmt-support >= 2.1.7
- docker engine >= 19.03
docker 镜像默认的运行平台需要通过以下命令查看:
docker image inspect --format='{{ .Architecture }}' <image_name>
0x02 docker build
构建不同平台的 docker 镜像方式可以分为两种:
- docker build 时通过
--platform
参数,或者设置DOCKER_DEFAULT_PLATFORM
变量的方式指定镜像的运行平台;docker build --platform linux/arm64/v8 --tag aggresss/benchmark_bc:arm64_v8 . docker build --platform linux/amd64 --tag aggresss/benchmark_bc:amd64 .
- 通过 buildx 插件构建镜像;
docker buildx create --use --name=mutil-platform-builder docker buildx build --push --platform linux/arm64,linux/amd64 --tag aggresss/benchmark_bc:v0.0.1 .
0x03 docker run
当 docker 镜像运行平台与指定的平台不一致时,通常会有类似下面的提示:
WARNING: The requested image’s platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
可见,跨平台虽然可以运行,但是性能肯定会受到影响,接下来通过一个实验验证下跨平台运行的性能损耗。
鉴于简洁性考虑,我们使用 bc 运算 arctan() 的方式求圆周率小数点后 5000 位的时间作为 benchmark 来粗略的估算一下非跨平台运行和跨平台运行的性能差别。
time echo "scale=5000; a(1)*4" | bc -l
Dockerfile
:
# A simple /bin/sh CPU benchmark using bc on alpine image
FROM alpine
RUN apk update && apk add bc
WORKDIR '/payload'
ADD benchmark_bc.sh .
CMD ["sh", "benchmark_bc.sh"]
benchmark_bc.sh
:
#!/bin/sh
time sh -c 'echo "scale=5000; a(1)*4" | bc -l'
测试环境:
uname -a
Darwin localhost 22.4.0 Darwin Kernel Version 22.4.0: Mon Mar 6 20:59:28 PST 2023; root:xnu-8796.101.5~3/RELEASE_ARM64_T6000 arm64
运行结果:
docker run -it --rm aggresss/benchmark_bc:arm64_v8
real 0m 16.10s
user 0m 15.86s
sys 0m 0.23s
docker run -it --rm aggresss/benchmark_bc:amd64
real 0m 58.72s
user 0m 57.68s
sys 0m 1.02s
可见,在当前的测试环境下,跨平台运行的效率大概只有非跨平台运行的 1/4 。