Mac M 芯片(ARM 架构)电脑上构建的 Docker 镜像,在 Linux (AMD64/Intel) 服务器上运行时可能会出现 exec format error 等错误。这是由于 CPU 架构不兼容导致的。本文介绍如何使用 docker buildx 来解决跨平台构建问题。

1. 什么是 Docker Buildx?

Docker Buildx 是一个 CLI 插件,扩展了 docker 命令,利用 Moby BuildKit 提供的功能,支持创建多个构建器实例,最重要的是支持同时针对多个节点(平台)进行构建

M1/M2 Mac 上默认的构建架构是 linux/arm64,而大部分服务器是 linux/amd64

2. 启用 Buildx

Docker 19.03+ 版本已包含 Buildx。如果未启用,可通过环境变量开启:

1
export DOCKER_CLI_EXPERIMENTAL=enabled

3. 创建构建器实例

默认的构建器可能不支持多平台构建,建议创建一个新的构建器。

1
2
3
4
5
# 创建名为 mybuilder 的构建器并切换使用
docker buildx create --use --name mybuilder

# 验证构建器状态
docker buildx ls

输出示例:

1
2
3
4
5
NAME/NODE    DRIVER/ENDPOINT             STATUS  PLATFORMS
mybuilder * docker-container
mybuilder0 unix:///var/run/docker.sock running linux/amd64, linux/386
default docker
default default running linux/amd64, linux/386

4. 编写 Dockerfile

Dockerfile 本身通常不需要修改,但可以利用 TARGETPLATFORM 等参数进行更高级的条件构建。

1
2
3
4
5
6
7
8
9
# 示例:打印构建平台信息
FROM --platform=$BUILDPLATFORM node: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
CMD ["cat", "/log"]

5. 构建多平台镜像

5.1 推送到远程仓库 (推荐)

Buildx 构建多平台镜像时,最佳实践是直接 push 到镜像仓库(如 Docker Hub),因为本地的 docker images 无法同时存储同一 Tag 的多种架构镜像。

1
2
# 同时也构建 arm 和 amd64 架构
docker buildx build -t yangpeng2468/test --platform=linux/arm,linux/arm64,linux/amd64 . --push

5.2 导出到本地 (单平台)

如果只需要打一个能在 Intel 服务器运行的包,可以指定单一平台并输出为 Docker 格式或 tar 包。

1
2
# 构建 linux/amd64 镜像并导出为 tar 文件
docker buildx build -t demo:0.1 --platform=linux/amd64 -o type=docker,dest=./demo.tar .

构建完成后,将 demo.tar 上传至目标 Linux 服务器,加载镜像:

1
docker load -i demo.tar

6. 清理缓存

如果构建占用过多空间,可以清理 Buildx 缓存:

1
docker buildx prune