一次多架构镜像构建实战:Docker Buildx + Harbor 踩坑记录
一、背景需求
宿主机架构:x86_64
目标平台:x86_64 + ARM64
镜像构建方式:通过 Jenkins 拉起容器 agent,在其中构建镜像,并推送至 Harbor
构建工具链:
docker buildx
+ buildkit
二、环境准备
启用binfmt_misc
//宿主机上执行 #docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d //验证 #ls /proc/sys/fs/binfmt_misc/ python3.10 qemu-aarch64 qemu-arm qemu-ppc64le qemu-s390x register status
创建并使用多平台构建器
//创建 #docker buildx create --use --name crossbuilder//启动 docker buildx inspect crossbuilder --bootstrap
查看当前使用的构建器及构建器支持的 CPU 架构
#docker buildx ls NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS crossbuilder * docker-containercrossbuilder0 unix:///var/run/docker.sock running linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6 default dockerdefault default running linux/amd64, linux/386
三、构建命令
最终可用的构建命令如下:
#docker buildx build --no-cache --pull -t $tag --platform=linux/arm64,linux/amd64 --push .
说明:
--push
:直接推送至远端仓库(如 Harbor),否则buildx
不会保留镜像(尤其是 manifest list 类型)--platform
:指定多平台架构--load
:不要使用,它只支持单一平台(默认本地加载),不支持 manifest list(多架构)
四、遇到的坑与解决方式
1. error: docker exporter does not currently support exporting manifest lists
问题:你使用了 --load
参数来导入多架构镜像到本地。
解决:manifest list 镜像无法 --load
,改为直接 --push
:
docker buildx build --platform=linux/amd64,linux/arm64 -t xxx --push .
2. error: failed to solve: granting entitlement network.host is not allowed by build daemon configuration
问题:你指定了 --network=host
,但宿主机 Docker Daemon 未开放该权限。
解决:修改 /etc/docker/daemon.json
,添加:
{"features": { "buildkit": true },"experimental": true,"builder": {"gc": {"enabled": true}},"entitlements": ["network.host"]
}
重启 Docker 后重试。
3. Harbor UI 中看不到两个架构
问题:Harbor UI 未展示 manifest list 的子镜像(可能和版本有关系),容易误以为只 push 了一个架构。
验证方法:
#docker buildx imagetools inspect harbor.yourdomain.com/daily/app:multi-platform
Name: harbor.yourdomain.com/daily/app:multi-platform
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest: sha256:9e12dfcf7a008c723372e94a3113d06ffe8e58df5d41c897b22ae152c592eba0Manifests:Name: harbor.yourdomain.com/daily/app:multi-platform@sha256:dfd72556bb959c67ff6a27fe4082a590cc7d81373708691a505672ce564b84efMediaType: application/vnd.docker.distribution.manifest.v2+jsonPlatform: linux/arm64Name: harbor.yourdomain.com/daily/app:multi-platform@sha256:89d7f63a7bde2a17988455be05c5d126ac32de380224452945fa124a19df517fMediaType: application/vnd.docker.distribution.manifest.v2+jsonPlatform: linux/amd64
确认 manifest list 已生成,说明构建成功。
4. --push
之后本地没有镜像
问题:这是 buildx
的设计,--push
会将构建产物直接上传 registry,不保留在本地(manifest list 类型本地也不能直接运行)。
解决:确认推送成功后,通过拉取测试:
docker pull --platform=linux/arm64 harbor.yourdomain.com/project/image:tag
或用 buildx imagetools inspect
验证。
五、Jenkins + Kubernetes Agent 中如何共享宿主机的 binfmt 能力
在 PodSpec 中挂载宿主机的 docker和buildx,示例如下
volumeMounts:- mountPath: "/usr/lib64/libltdl.so.7"name: "volume-3"readOnly: false- mountPath: "/usr/libexec/docker/cli-plugins/docker-buildx"name: "volume-5"readOnly: false- mountPath: "/var/run/docker.sock"name: "volume-2"readOnly: false- mountPath: "/usr/bin/docker"name: "volume-4"readOnly: falsevolumes:- hostPath:path: "/var/run/docker.sock"name: "volume-2"- hostPath:path: "/usr/bin/docker"name: "volume-4"- hostPath:path: "/usr/lib64/libltdl.so.7"name: "volume-3"- hostPath:path: "/usr/libexec/docker/cli-plugins/docker-buildx"name: "volume-5"
六、结语
docker buildx
是构建多平台镜像的现代化利器,但其行为与传统 docker build
不同,踩坑点较多,关于 --load
、--push
和 Harbor UI 展示方面容易让人困惑。