一次多架构镜像构建实战:Docker Buildx + Harbor 踩坑记录

发布于:2025-07-18 ⋅ 阅读:(13) ⋅ 点赞:(0)

一、背景需求

  • 宿主机架构:x86_64

  • 目标平台:x86_64 + ARM64

  • 镜像构建方式:通过 Jenkins 拉起容器 agent,在其中构建镜像,并推送至 Harbor

  • 构建工具链:docker buildx + buildkit


二、环境准备

  1. 启用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
  2. 创建并使用多平台构建器

    //创建
    #docker buildx create --use --name crossbuilder
     
    //启动
    docker buildx inspect crossbuilder --bootstrap
  3. 查看当前使用的构建器及构建器支持的 CPU 架构

    #docker buildx ls
    NAME/NODE       DRIVER/ENDPOINT             STATUS  PLATFORMS
    crossbuilder *  docker-container
      crossbuilder0 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         docker
      default       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:9e12dfcf7a008c723372e94a3113d06ffe8e58df5d41c897b22ae152c592eba0

Manifests:
  Name:      harbor.yourdomain.com/daily/app:multi-platform@sha256:dfd72556bb959c67ff6a27fe4082a590cc7d81373708691a505672ce564b84ef
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64

  Name:      harbor.yourdomain.com/daily/app:multi-platform@sha256:89d7f63a7bde2a17988455be05c5d126ac32de380224452945fa124a19df517f
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  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: false
  volumes:
  - 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 展示方面容易让人困惑。


网站公告

今日签到

点亮在社区的每一天
去签到