在信创,ARM开始崛起的现在,Docker 也从一开始的只支持 x86_64 架构变为支持各种架构了,虽然 Docker 的目的是保证只要 Docker 安装好,在任意机器上运行都能达到一样的效果,但是这个的前提是Docker镜像的架构和当前服务器的架构一致,以前都是 x84_64架构自然可以,但现在也有别的架构,因此 一个镜像如果只有 x86_64 架构的版本,那么是无法在
Arm 架构的服务器上运行的。
和运行同理,打包也是如此,x86_64 的机器只能打包 x86_64 的镜像。
但是新版本的 docker (从 server 版本 大于 19.10 开始) 有了一个插件 buildx , 这个插件支持从一个平台构建多个平台的镜像。
下面是常见的几种方式
Docker Desktop
此软件是用于开发,测试使用的,很方便,因为新版本默认集成了 buildx ,也集成了多平台镜像模拟运行。、
我安装的版本
docker version
输出结果
Client:
Cloud integration: v1.0.35+desktop.13
Version: 26.1.1
API version: 1.45
Go version: go1.21.9
Git commit: 4cf5afa
Built: Tue Apr 3011:46:57 2024
OS/Arch: linux/amd64
Context: default
Server: Docker Desktop
Engine:
Version: 26.1.1
API version: 1.45(minimum version 1.24)
Go version: go1.21.9
Git commit: ac2de55
Built: Tue Apr 3011:48:28 2024
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.31
GitCommit: e377cd56a71523140ca6ae87e30244719194a521
runc:
Version: 1.1.12
GitCommit: v1.1.12-0-g51d5e94
docker-init:
Version: 0.19.0
GitCommit: de40ad0
buildx 情况
docker buildx ls
输出
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
default* docker
\_ default \_ default running v0.13.2 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/mips64le, linux/mips64, linux/loong64, linux/ppc64
可以看到,build 支持打包多个架构的镜像,如打包
linux/arm64
的,只需要如下执行即可
docker build -t test1 --platform linux/arm64 .
docker build --platform linux/amd64,linux/arm64 .
默认情况下,Docker Desktop 支持在仿真下运行和构建多平台镜像。无需配置,因为生成器使用捆绑在 Docker Desktop VM 中的 QEMU。
Docker Server
Docker Desktop 是用于 windows ,mac上开发使用的,实际使用肯定是在 linux 上的,此时装的都是 Docker Server 服务,如 docker-ce ,由于默认情况下是不支持多平台的,所以需要参考官方文档:
多平台 |Docker 文档 — Multi-platform | Docker Docs(https://docs.docker.com/build/building/multi-platform/)
文档中介绍了三种方式,分别是 QEMU 模拟仿真,使用具有多个原生节点的构建器, 将交叉编译与多阶段构建结合使用,下面别分介绍
QEMU
这个最简单,不过需要满足一些条件(不一定是所有条件都需要有效,但是开着准没错)
- 物理机环境变量 DOCKER_BUILDKIT=1,应该会有用
- 物理机环境变量 DOCKER_CLI_EXPERIMENTAL=enabled,应该会有用
- 物理机 Linux 内核版本 4.8 或更高版本,即
uname -r
的输出版本号大于4.8 ,否则会存在各种奇奇怪怪的错误。 binfmt-support
版本 2.1.7 或更高版本,Ubuntu 可以通过apt-cache policy binfmt-support
查看版本- QEMU 二进制文件必须静态编译并使用
fix_binary
标志进行注册
一般情况下,你只要内核版本满足,binfmt-support 啥的也能满足
QEMU 安装
官网推荐是通过镜像
tonistiigi/binfmt
来操作,常用操作命令如下:
# 查看支持的架构和模拟器列表
docker run --privileged --rm tonistiigi/binfmt:master
# 安装所有架构模拟器
docker run --privileged --rm tonistiigi/binfmt:master --install all
# 安装指定架构的
docker run --privileged --rm tonistiigi/binfmt:master --install arm64,riscv64,arm
# 删除所有架构
docker run --privileged --rm tonistiigi/binfmt --uninstall qemu-*
# 删除指定架构
docker run --privileged --rm tonistiigi/binfmt --uninstall qemu-aarch64
# 查看版本
docker run --privileged --rm tonistiigi/binfmt:master --version
# 查看帮助
docker run --privileged --rm tonistiigi/binfmt:master --help
验证命令
docker run --rm arm32v6/alpine:3.20.3 uname -a
docker run --rm arm32v7/alpine:3.20.3 uname -a
docker run --rm arm64v8/alpine:3.20.3 uname -a
docker run --rm s390x/alpine:3.20.3 uname -a
docker run --rm i386/alpine:3.20.3 uname -a
docker run --rm ppc64le/alpine:3.20.3 uname -a
docker run --rm riscv64/alpine:3.20.3 uname -a
docker run --rm amd64/alpine:3.20.3 uname -a
docker run --rm alpine:3.20.3 uname -a
查看安装好的注册节点
ls -alh /proc/sys/fs/binfmt_misc
输出:
drwxr-xr-x 2 root root 0 Sep 2413:46 .
dr-xr-xr-x 1 root root 0 Sep 2413:46 ..
-rw-r--r-- 1 root root 0 Sep 2413:46 WSLInterop
-rw-r--r-- 1 root root 0 Sep 2413:46 WSLInterop-late
-rw-r--r-- 1 root root 0 Sep 2413:46 aarch64
-rw-r--r-- 1 root root 0 Sep 2413:46 arm
-rw-r--r-- 1 root root 0 Sep 2413:46 mips64
-rw-r--r-- 1 root root 0 Sep 2413:46 mips64le
-rw-r--r-- 1 root root 0 Sep 2413:46 ppc64le
-rw-r--r-- 1 root root 0 Sep 2523:10 qemu-loongarch64
-rw-r--r-- 1 root root 0 Sep 2523:10 qemu-s390x
--w------- 1 root root 0 Sep 2523:07 register
-rw-r--r-- 1 root root 0 Sep 2413:46 riscv64
-rw-r--r-- 1 root root 0 Sep 2413:46 status
如果上面的都不行,那么可能就是存在一些特殊情况了,可以使用
tonistiigi/binfmt
类似的
multiarch/qemu-user-static
, 这个也很牛皮,可以在早期的docker 版本上实现跨平台打包镜像,如 docker 19.10 左右的版本,但是需要自己去深入研究一下。
使用命令如下:
$ uname -m
x86_64
$ docker run --rm -t arm64v8/ubuntu uname -m
standard_init_linux.go:211: exec user process caused "exec format error"
$ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
$ docker run --rm -t arm64v8/ubuntu uname -m
aarch64
# 查看帮助说明
docker run --rm --privileged multiarch/qemu-user-static:latest --help
# 安装除了当前处理器支持的架构之外的模拟器
docker run --rm --privileged multiarch/qemu-user-static:latest
# 删除现有的模拟器,安装除了当前处理器支持的架构之外的模拟器
docker run --rm --privileged multiarch/qemu-user-static:latest --reset
# 删除现有的模拟器,安装除了当前处理器支持的架构之外的模拟器,并且持久化
docker run --rm --privileged multiarch/qemu-user-static:latest --reset -p yes# 查看安装的模拟器列表ls -alh /proc/sys/fs/binfmt_misc
使用 QEMU 进行仿真可能比原生构建慢得多,尤其是对于编译和压缩或解压缩等计算密集型任务。
默认情况下,Docker Desktop 支持在仿真下运行和构建多平台镜像。无需配置,因为生成器使用捆绑在 Docker Desktop VM 中的 QEMU。
多个原生节点
需要额外的机器,即有对应的不同平台的机器集群打包,不考虑,我有额外的机器了,就不用纠结这个了
交叉编译
根据您的项目,如果您使用的编程语言对交叉编译有很好的支持,则可以利用多阶段构建从构建器的本机架构为目标平台构建二进制文件。特殊的构建参数(如
BUILDPLATFORM
和
TARGETPLATFORM
)会自动在 Dockerfile 中使用。
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM golang:alpine AS build
ARG TARGETPLATFORM
ARG BUILDPLATFORM
RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM" > /log
FROM alpine
COPY --from=build /log /log
Docker in Docker
很多情况都是因为docker所处的内核版本等等不足导致,那么就可以尝试使用 Docker in Docker ,套娃的方式打包。性能会低一点,至少可以打包,还没那么多问题
GitHub - crazy-max/docker-docker: Docker in Docker (DinD) image(https://github.com/crazy-max/docker-docker#about)
参考链接
- “sh: write error: Invalid argument” errors when register · Issue #38 · multiarch/qemu-user-static · GitHub(https://github.com/multiarch/qemu-user-static/issues/38)
- sh: write error: Invalid argument - Centos 7 · Issue #100 · multiarch/qemu-user-static · GitHub(https://github.com/multiarch/qemu-user-static/issues/100)
- failed to load LLB: runtime execution on platform linux/arm64 not supported · Issue #138 · docker/buildx · GitHub(https://github.com/docker/buildx/issues/138)
- buildx is not a docker command on linux/amd64 ? · Issue #132 · docker/buildx · GitHub(https://github.com/docker/buildx/issues/132#issuecomment-521759117)
- GitHub - crazy-max/docker-docker: Docker in Docker (DinD) image(https://github.com/crazy-max/docker-docker#about)
- sh: write error: Invalid argument - Centos 7 qemu报错解决方案 - 小小记录本 - 博客园(https://www.cnblogs.com/xiaojiluben/p/16745276.html)
- 多架构 Docker 镜像 ·Maartje Eyskens — Multiarch Docker Images · Maartje Eyskens(https://eyskens.me/multiarch-docker-images/)
版权归原作者 DHclly 所有, 如有侵权,请联系我们删除。