需求
为了降低服务器运行成本,之后可能会将服务器从 x86 架构迁移到 arm 架构,而这也就意味着之前打包的一些 docker 镜像需要重新构建 arm 版本的镜像。在迁移过程中,需要一个镜像同时支持 x86 和 arm 两个架构,这样在迁移的时候就不需要手动指定镜像的 tag。
基本操作
podman 打包跨架构镜像的命令和 docker 基本上是一样的。
对于docker来说,只需要输入:
docker buildx build --platform linux/amd64,linux/arm64 -t image:tag .
而对于 podman 来说,需要稍微修改一下命令:
podman build --platform linux/amd64,linux/arm64 --manifest image:tag .
相比于 docker 的命令,有两个不同:
1. 直接使用了 build, 不需要 buildx build。docker 的 buildx 是为了调用 buildkit,而 podman 不需要。不过,podman 保留了 buildx 的兼容性。你也可以继续使用 podman buildx build。
2. 对于多架构镜像,需要是应用 –manifest 而不是 –tag
在构建完毕后,跟普通镜像一样直接使用 docker push 命令就可以将这个镜像推送到仓库中了。
跨架构运行命令
如果你的 Containerfile 比较简单,不涉及到运行命令的话,你到这里应该就可以结束了。然而大部分镜像都不是这样的,他们可能需要运行一些安装工具的命令,甚至需要直接编译对应架构的二进制。
而由于容器是非常轻量的运行环境隔离技术,其二进制本质上是直接运行于宿主机的 CPU 上的。这也就意味着如果你尝试在 x86 的 CPU 上运行 arm 架构镜像中的二进制,你的 CPU 就会不认识对应的指令,直接给你一个报错。
为了解决在 X86 CPU 上运行 arm 指令集的问题,我们需要引入 QEMU 模拟器翻译架构指令。而为了让镜像中的命令无感地在 QEMU 中运行,我们还需要引入 binfmt_misc 技术,在内核中注册对应的二进制格式的解析器,令内核在调用对应二进制之前运行 QEMU。
Stackoverflow 上的”运行 multiarch/qemu-user-static 镜像到底干了什么” 问答给出了详细的技术细节,简要来说就是:
1. multiarch/qemu-user-static 镜像打包了 qemu-user-static 的二进制;
2. 这个镜像启动时运行了 qemu-binfmt-conf.sh 脚本;
3. 这个脚本会尝试挂载 /proc/sys/fs/binfmt_misc 目录,并配置对应架构的 binfmt_misc;
4. 在配置 binfmt_misc 过程中,如果你指定了-p yes,则会使用 “F” 这个标志。这个标志令内核中驻留了对应的 QEMU 二进制文件。这样在容器镜像中就不会出现找不到配置的 QEMU 二进制的问题。
所以摆在面前的有两条路:
1. 在系统启动之后,运行一次 docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
2. 安装 qemu-user-static 软件包,这个软件包会自己注册 binfmt_misc
但是有个问题,我既不想用方案1,我的基础镜像是 alpine 又没有这个软件包不能使用方案2。这就只能通过上述流程自己配置了:
FROM alpine
RUN apk add --no-cache podman iptables qemu-aarch64
ADD https://raw.githubusercontent.com/qemu/qemu/e75941331e4cdc05878119e08635ace437aae721/scripts/qemu-binfmt-conf.sh /usr/local/bin/qemu-binfmt-conf.sh
RUN chmod +x /usr/local/bin/*
# 接着在 entrypoint 里面调用 qemu-binfmt.conf.sh
# qemu-binfmt-conf.sh --qemu-path /usr/bin -p yes
在跑完这些之后,你的镜像就应该能运行 arm64 架构的二进制了。你可以先找个二进制本机运行:
wget https://github.com/EXALAB/Busybox-static/blob/main/busybox_arm64
chmod +x busybox_arm64
./busybox_arm64
然后可以通过下面的命令来验证 podman 是否能够正确执行:
podman run --platform=linux/arm64 alpine uname -m
最后就可以使用下面的命令打包多架构镜像了:
podman buildx build --platform linux/amd64,linux/arm64 --manifest test .
常见问题
- exec container process
/bin/uname: Exec format error- 没有正常设置 binfmt_misc,指令格式认不到;
- exec container process (missing dynamic library?)
/bin/uname: No such file or directory- 没加
-p yes,导致找不到 qemu
- 没加
0 条评论