多平台图像

Docker 镜像可以支持多个平台,这意味着单个镜像可能包含针对不同架构的变体,有时还包含针对不同操作系统(例如 Windows)的变体。

当您运行支持多平台的镜像时,Docker 会自动选择与您的操作系统和架构相匹配的镜像。

Docker Hub 上的大多数 Docker 官方镜像都提供了 多种架构。例如,busybox图像支持amd64arm32v5arm32v6arm32v7arm64v8i386ppc64le、 和s390x。当在x86_64/机器上运行此映像时amd64,该amd64变体将被拉出并运行。

构建多平台图像

当您调用构建时,您可以设置标志--platform来指定构建输出的目标平台。例如,linux/amd64linux/arm64、 或 darwin/amd64

默认情况下,您一次只能针对一个平台进行构建。如果您想同时针对多个平台进行构建,您可以:

策略

您可以根据您的用例使用三种不同的策略构建多平台映像:

  1. 使用 内核中的QEMU 模拟支持
  2. 构建在由不同架构的多个节点支持的单个构建器上 。
  3. 使用 Dockerfile 中的阶段 交叉编译到不同的架构

QEMU

如果您的构建器已经支持,那么使用 QEMU 模拟构建多平台映像是最简单的入门方法。 Docker Desktop 开箱即用地支持它。它不需要更改 Dockerfile,并且 BuildKit 会自动检测可用的辅助架构。当 BuildKit 需要运行不同架构的二进制文件时,它会通过binfmt_misc处理程序中注册的二进制文件自动加载它。

笔记

使用 QEMU 进行仿真可能比本机构建慢得多,特别是对于编译、压缩或解压缩等计算量大的任务。

如果可能,请 改用多个本机节点交叉编译。

Docker 桌面支持

Docker Desktop提供binfmt_misc 多架构支持,这意味着您可以运行适用于不同 Linux 架构的容器,例如armmipsppc64le、 甚至s390x

这不需要在容器本身中进行任何特殊配置,因为它使用 Docker Desktop VM 中的qemu-static 。因此,您可以运行 ARM 容器,例如busybox 映像的arm32v7或变体。ppc64le

没有 Docker 桌面的 QEMU

binfmt_misc为了使在主机操作系统上注册的 QEMU 二进制文件能够在容器内透明地工作,它们必须使用该fix_binary标志进行静态编译和注册。这需要内核版本 4.8 或更高版本以及binfmt-support版本 2.1.7 或更高版本。

F您可以通过检查中的标志 是否包含来验证您的注册/proc/sys/fs/binfmt_misc/qemu-*。虽然 Docker Desktop 预先配置了binfmt_misc对其他平台的支持,但对于其他安装,它可能需要使用 tonistiigi/binfmt映像进行安装:

$ docker run --privileged --rm tonistiigi/binfmt --install all

多个本机节点

使用多个本机节点可以为 QEMU 无法处理的更复杂的情况提供更好的支持,并且还提供更好的性能。

您可以使用该标志将其他节点添加到构建器--append

以下命令从名为 node-amd64和 的Docker 上下文创建一个多节点构建器node-arm64。此示例假设您已经添加了这些上下文。

$ docker buildx create --use --name mybuild node-amd64
mybuild
$ docker buildx create --append --name mybuild node-arm64
$ docker buildx build --platform linux/amd64,linux/arm64 .

虽然这种方法比模拟具有优势,但管理多节点构建器会带来一些设置和管理构建器集群的开销。或者,您可以使用 Docker Build Cloud,这是一项在 Docker 基础设施上提供托管多节点构建器的服务。借助 Docker Build Cloud,您可以获得本机多平台 Arm 和 X86-64 构建器,而无需维护它们。使用云构建器还可以提供额外的好处,例如共享构建缓存。

注册 Docker Build Cloud 后,将构建器添加到本地环境并开始构建。

$ docker buildx create --driver cloud <ORG>/<BUILDER_NAME>
cloud-<ORG>-<BUILDER_NAME>
$ docker buildx build --builder cloud-<ORG>-<BUILDER_NAME> \
  --platform linux/amd64,linux/arm64,linux/arm/v7 \
  --tag <IMAGE_NAME> \
  --push .

交叉编译

根据您的项目,如果您使用的编程语言对交叉编译具有良好的支持,则可以有效地使用 Dockerfile 中的多阶段构建,使用构建节点的本机架构为目标平台构建二进制文件。诸如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 buildx ls命令 以列出现有的构建器:

$ docker buildx ls
NAME/NODE  DRIVER/ENDPOINT  STATUS   BUILDKIT PLATFORMS
default *  docker
  default  default          running  v0.11.6  linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6

这将显示默认的内置驱动程序,该驱动程序使用直接内置于 docker 引擎中的 BuildKit 服务器组件,也称为 dockerdriver

使用 docker-container驱动程序创建一个新的构建器 ,它使您可以访问更复杂的功能,例如多平台构建和更高级的缓存导出器,这些功能目前在默认docker驱动程序中不受支持:

$ docker buildx create --name mybuilder --bootstrap --use

现在再次列出现有的构建器,我们可以看到我们的新构建器已注册:

$ docker buildx ls
NAME/NODE     DRIVER/ENDPOINT              STATUS   BUILDKIT PLATFORMS
mybuilder *   docker-container
  mybuilder0  unix:///var/run/docker.sock  running  v0.12.1  linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
default       docker
  default     default                      running  v0.13.1  linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v6

例子

测试工作流程以确保您可以构建、推送和运行多平台映像。创建一个简单的示例 Dockerfile,构建几个镜像变体,并将它们推送到 Docker Hub。

以下示例使用单个Dockerfile构建 Alpine 镜像,并为多个架构安装了 cURL:

# syntax=docker/dockerfile:1
FROM alpine:3.19
RUN apk add curl

使用 buildx 构建 Dockerfile,传递要构建的架构列表:

$ docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t <username>/<image>:latest --push .
...
#16 exporting to image
#16 exporting layers
#16 exporting layers 0.5s done
#16 exporting manifest sha256:71d7ecf3cd12d9a99e73ef448bf63ae12751fe3a436a007cb0969f0dc4184c8c 0.0s done
#16 exporting config sha256:a26f329a501da9e07dd9cffd9623e49229c3bb67939775f936a0eb3059a3d045 0.0s done
#16 exporting manifest sha256:5ba4ceea65579fdd1181dfa103cc437d8e19d87239683cf5040e633211387ccf 0.0s done
#16 exporting config sha256:9fcc6de03066ac1482b830d5dd7395da781bb69fe8f9873e7f9b456d29a9517c 0.0s done
#16 exporting manifest sha256:29666fb23261b1f77ca284b69f9212d69fe5b517392dbdd4870391b7defcc116 0.0s done
#16 exporting config sha256:92cbd688027227473d76e705c32f2abc18569c5cfabd00addd2071e91473b2e4 0.0s done
#16 exporting manifest list sha256:f3b552e65508d9203b46db507bb121f1b644e53a22f851185d8e53d873417c48 0.0s done
#16 ...

#17 [auth] <username>/<image>:pull,push token for registry-1.docker.io
#17 DONE 0.0s

#16 exporting to image
#16 pushing layers
#16 pushing layers 3.6s done
#16 pushing manifest for docker.io/<username>/<image>:latest@sha256:f3b552e65508d9203b46db507bb121f1b644e53a22f851185d8e53d873417c48
#16 pushing manifest for docker.io/<username>/<image>:latest@sha256:f3b552e65508d9203b46db507bb121f1b644e53a22f851185d8e53d873417c48 1.4s done
#16 DONE 5.6s

笔记

  • <username>必须是有效的 Docker ID 以及<image>Docker Hub 上的有效存储库。
  • --platform标志通知 buildx 为 AMD 64 位、Arm 64 位和 Armv7 架构创建 Linux 映像。
  • --push标志生成一个多架构清单并将所有映像推送到 Docker Hub。

docker buildx imagetools使用命令检查图像 :

$ docker buildx imagetools inspect <username>/<image>:latest
Name:      docker.io/<username>/<image>:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:f3b552e65508d9203b46db507bb121f1b644e53a22f851185d8e53d873417c48

Manifests:
  Name:      docker.io/<username>/<image>:latest@sha256:71d7ecf3cd12d9a99e73ef448bf63ae12751fe3a436a007cb0969f0dc4184c8c
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64

  Name:      docker.io/<username>/<image>:latest@sha256:5ba4ceea65579fdd1181dfa103cc437d8e19d87239683cf5040e633211387ccf
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64

  Name:      docker.io/<username>/<image>:latest@sha256:29666fb23261b1f77ca284b69f9212d69fe5b517392dbdd4870391b7defcc116
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm/v7

该镜像现已在 Docker Hub 上提供,标签为<username>/<image>:latest。您可以使用此映像在 Intel 笔记本电脑、Amazon EC2 Graviton 实例、Raspberry Pi 和其他架构上运行容器。 Docker 为当前架构提取正确的映像,因此 Raspberry PI 运行 32 位 Arm 版本,EC2 Graviton 实例运行 64 位 Arm。

摘要识别出完全合格的图像变体。您还可以在 Docker Desktop 上运行针对不同架构的映像。例如,当您在 macOS 上运行以下命令时:

$ docker run --rm docker.io/<username>/<image>:latest@sha256:2b77acdfea5dc5baa489ffab2a0b4a387666d1d526490e31845eb64e3e73ed20 uname -m
aarch64
$ docker run --rm docker.io/<username>/<image>:latest@sha256:723c22f366ae44e419d12706453a544ae92711ae52f510e226f6467d8228d191 uname -m
armv7l

在上面的示例中,即使在本机 macOS 或 Windows 开发人员计算机上运行命令,也会按预期uname -m返回aarch64和。armv7l