多平台镜像

方式一:通过清单文件构建多平台镜像

不同平台镜像通过在 tag 标签带上一个后缀标识这个平台,将多个平台的镜像推送到镜像仓库,然后通过 docker 的清单列表功能将多个 tag 合并为一个,然后推送这个清单文件到镜像仓库

# 在 arm64 的机器上构建 arm64 的镜像
docker build -t xxx:1.0.0-arm64 .
docker push xxx:xxx-arm64
 
# 在 amd64 的机器上构建 amd64 的镜像
docker build -t xxx:xxx-amd64 .
docker push xxx:1.0.0-amd64
 
# 在任意机器上,创建清单列表将两个平台的镜像放到一个 tag 下
docker manifest create xxx:1.0.0 \
  -a xxx:1.0.0-arm64 \
  -a xxx:1.0.0-amd64
 
# 推送清单列表到镜像仓库
docker manifest push xxx:1.0.0

之后可以通过 docker pull xxx:1.0.0 的方式拉取镜像,镜像仓库会自动区分平台

manifest 功能需要镜像仓库开启 https,docker 为镜像配置的 http 不会生效。

方式二:通过 docker buildx 交叉编译得到多平台镜像

github buildx | buildx 安装使用 buildkitd.toml.md | buildx 配置文件 buildx 需要 linux 内核支持:内核 >= 4.8 (uname -a 查看内核版本) 和 binfmt-support >= 2.1.7

安装 tonistiigi/binfmt

docker run --privileged --rm tonistiigi/binfmt --install all
 
# 查看本机支持的编译平台:
# cat /proc/sys/fs/binfmt_misc/qemu-*

为 buildx 创建一个新的编译器实例(默认实例不支持指定多个编译平台)

docker buildx create --use --name mybuilder
 
# 创建自定义编译器时指定 buildit 配置文件
# docker buildx create --use --name mybuilder --config xxx.toml

如果要通过 http 或者自签证书的 https 从镜像仓库拉取/推送镜像,需要在创建 编译器实例时通过 --config 指定 buildkit 配置文件:详情查看:buildkitd.toml.md

启动构建器

docker buildx inspect mybuilder --bootstrap
 
# 查看构建器支持的平台
# docker buildx ls

通过 --platform 参数指定要构建哪些平台的镜像

docker buildx build --load --platform linux/amd64,linux/arm64 -t xxx:1.0.0 .

可通过 docker pull xxx:1.0.0 --platform linux/arm64 拉取不同平台的镜像 配置了 buildx 后可直接跨平台运行支持的镜像 使用 --provenance=false 参数,不然生成的平台镜像会多一个 unknown/unknown,见:https://github.com/docker/buildx/issues/1964#issuecomment-1644634461

默认情况下构建出来的镜像只保存在缓存中,本地 docker images 命令查看不到。可以通过增加如下选项:

  • --load:加载到本地的 Docker 镜像列表中(仅支持指定一个平台架构)
  • --output:保存为本地文件(仅支持指定一个平台架构)
  • --push:在构建完成后自动将清单文件推送到镜像仓库

--output保存到本地文件示范:

docker buildx build --platform linux/arm64 --output type=docker,dest=xxx_1.0.0_arm64.tar -t xxx:1.0.0 .

type 选项

type 定义了输出的类型,可以是以下几种之一:

  1. type=docker:

    • 将镜像导出为可以通过 docker load 加载的 Docker 镜像文件(*.tar)。
    • 相关的配置:
      • dest:指定文件保存的路径(例如 output.tar)。

    示例:

docker buildx build --output type=docker,dest=output_image.tar -t your_image_name:tag .
  1. type=oci:

    • 将镜像导出为 OCI 格式的镜像文件,符合 OCI(Open Container Initiative)标准。
    • 相关的配置:
      • dest:指定文件保存的路径。

    示例:

docker buildx build --output type=oci,dest=output_image.tar -t your_image_name:tag .
  1. type=local:

    • 将镜像文件系统导出到本地文件系统目录中,而不是一个单一的镜像文件。适用于将构建结果导出为一个普通的文件结构。
    • 相关的配置:
      • dest:指定输出目录的路径。

    示例:

docker buildx build --output type=local,dest=./output_directory -t your_image_name:tag .
  1. type=tar:

    • 将镜像导出为 tar 文件,但与 type=docker 不同的是,type=tar 导出的是镜像文件系统,而不是完整的 Docker 镜像。
    • 相关的配置:
      • dest:指定保存 tar 文件的路径。

    示例:

docker buildx build --output type=tar,dest=output_filesystem.tar -t your_image_name:tag .
  1. type=registry:

    • 将镜像推送到指定的容器镜像仓库(如 Docker Hub、私有仓库)。
    • 无需指定 dest 参数,因为输出目标是远程仓库。
    • 你可以指定仓库和标签名称。

    示例:

docker buildx build --output type=registry -t your_registry/your_image_name:tag .
  1. type=image (需要 Docker 20.10.7+):

    • 用于将镜像直接保存到本地的 Docker 实例中,类似于 --load 的效果,但提供了更多选项。
    • 相关的配置:
      • name:指定镜像名称。
      • push:是否将镜像推送到远程仓库。

    示例:

docker buildx build --output type=image,name=your_image_name:tag,push=false -t your_image_name:tag .

如果执行过程中报错: libc-bin segfaults ( script subprocess returned error exit status 139 ) ( qemu: uncaught target signal 11 (Segmentation fault) - core dumped ) 见:https://github.com/docker/buildx/issues/314 讨论

执行如下操作可修复:

docker run --rm --privileged multiarch/qemu-user-static --reset -p yes -c yes