多平台构建
多平台版本是指将
多种不同的操作系统或 CPU 架构组合。什么时候
构建镜像,这允许您创建可在多个上运行的单个镜像
平台,例如 、 和 。linux/amd64
linux/arm64
windows/amd64
为什么选择多平台构建?
Docker 通过打包应用程序解决了“它可以在我的机器上运行”的问题 及其依赖项添加到容器中。这使得运行相同的操作变得容易 应用程序,例如开发、测试和 生产。
但容器化本身只能解决部分问题。器皿
共享主机内核,这意味着在
容器必须与主机的架构兼容。这就是您
无法在 arm64 主机上运行容器(不使用仿真),
或 Linux 主机上的 Windows 容器。linux/amd64
多平台 build 通过打包 相同的应用程序合并到单个镜像中。这使您能够在 不同类型的硬件,例如运行 x86-64 或 云中基于 ARM 的 Amazon EC2 实例,无需仿真。
单平台镜像和多平台镜像的区别
多平台镜像的结构与单平台镜像不同。 单平台镜像包含一个指向单个 配置和一组层。多平台镜像包含一个 manifest 列表,指向多个清单,每个清单都指向一个 不同的配置和层集。
当您将多平台镜像推送到 registry 时,registry 会将
manifest list 和所有单独的清单。当您拉取镜像时,
registry 返回清单列表,Docker 会自动选择
根据主机的架构进行正确的变体。例如,如果您运行
multi platform 镜像,Docker 选择变体。如果您在 x86-64 笔记本电脑上运行相同的镜像,则 Docker
选择变体(如果您使用的是 Linux 容器)。linux/arm64
linux/amd64
先决条件
要构建多平台镜像,您首先需要确保您的 Docker 环境设置为支持它。有两种方法可以做到这一点:
- 您可以从 “classic” 镜像存储切换到 containerd 镜像存储。
- 您可以创建和使用自定义生成器。
Docker Engine 的 “classic” 镜像存储不支持多平台 镜像。切换到 containerd 镜像存储可确保您的 Docker 引擎 可以推送、拉取和构建多平台镜像。
创建使用具有多平台支持的驱动程序的自定义构建器,
比如 driver,会让你构建多平台镜像
而无需切换到其他镜像存储。但是,您仍然无法
将您构建的多平台镜像加载到 Docker Engine 镜像中
商店。但是,您可以使用 .docker-container
docker build --push
启用 containerd 镜像存储的步骤取决于您是否 使用 Docker Desktop 或 Docker Engine 独立版:
如果您使用的是 Docker Desktop,请在 Docker Desktop 设置中启用 containerd 镜像存储。
如果您使用的是 Docker Engine 独立版,请启用 containerd 镜像存储 使用 daemon 配置文件。
要创建自定义构建器,请使用命令创建一个
builder 的 Builder。docker buildx create
docker-container
$ docker buildx create \
--name container-builder \
--driver docker-container \
--bootstrap --use
注意
使用驱动程序的构建不会自动加载到您的 Docker Engine 镜像存储。有关更多信息,请参阅构建 驱动程序。
docker-container
如果您使用的是 Docker Engine 独立版,并且需要构建多平台 镜像,还需要安装 QEMU,详见安装 QEMU 手动。
构建多平台镜像
触发构建时,使用标志定义目标
构建输出的平台,例如 和 :--platform
linux/amd64
linux/arm64
$ docker buildx build --platform linux/amd64,linux/arm64 .
策略
您可以使用三种不同的策略构建多平台镜像: 根据您的使用案例:
QEMU
使用 QEMU 在仿真下构建多平台镜像是最简单的方法 如果您的生成器已经支持它,请开始使用。使用仿真不需要 更改,并且 BuildKit 会自动检测 可用于仿真的架构。
注意
使用 QEMU 进行仿真可能比原生构建慢得多,尤其是对于 计算密集型任务,如编译和压缩或解压缩。
Docker Desktop 支持在 emulation 的 intent 值。无需配置,因为构建器使用 捆绑在 Docker Desktop VM 中的 QEMU。
手动安装 QEMU
如果您在 Docker Desktop 之外使用构建器,例如您正在使用 Linux 上的 Docker Engine,或者自定义远程构建器,您需要安装 QEMU 并在主机操作系统上注册可执行类型。先决条件 安装 QEMU 的有:
- Linux 内核版本 4.8 或更高版本
binfmt-support
版本 2.1.7 或更高版本- QEMU 二进制文件必须静态编译并使用标志注册
fix_binary
使用 tonistiigi/binfmt
镜像
安装 QEMU 并使用单个
命令:
$ docker run --privileged --rm tonistiigi/binfmt --install all
这将安装 QEMU 二进制文件并将其注册到 binfmt_misc
,使 QEMU 能够
执行非本机文件格式以进行仿真。
安装 QEMU 并在主机操作系统上注册可执行类型后,
它们在容器内透明地工作。您可以通过以下方式验证您的注册
检查 是否在 中的标志中。F
/proc/sys/fs/binfmt_misc/qemu-*
多个原生节点
使用多个原生节点可以更好地支持更复杂的情况 QEMU 无法处理,并且还提供了更好的性能。
您可以使用该标志向生成器添加其他节点。--append
以下命令从名为 和 的 Docker 上下文创建一个多节点构建器。此示例假定您已经添加了
那些背景。node-amd64
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 构建器,而无需承担 维护它们。使用 Cloud Builder 还可以提供额外的好处,例如 作为共享构建缓存。
注册 Docker Build Cloud 后,将构建器添加到本地 环境并开始构建。
$ docker buildx create --driver cloud <ORG>/<BUILDER_NAME>
cloud-<ORG>-<BUILDER_NAME>
$ docker build \
--builder cloud-<ORG>-<BUILDER_NAME> \
--platform linux/amd64,linux/arm64,linux/arm/v7 \
--tag <IMAGE_NAME> \
--push .
有关更多信息,请参阅 Docker Build Cloud。
交叉编译
根据您的项目,如果您使用的编程语言具有良好的支持
对于交叉编译,您可以利用多阶段构建来构建二进制文件
对于构建器本机架构中的目标平台。特殊构建
参数(如 和 )会自动
可在 Dockerfile 中使用。BUILDPLATFORM
TARGETPLATFORM
在以下示例中,该指令固定到本机
platform (使用选项)
防止仿真启动。然后,预定义参数和 build 参数在指令中插入。在
在这种情况下,值只是使用 StdOut 打印到 stdout,但是这个
说明了如何将它们传递给编译器进行交叉编译。FROM
--platform=$BUILDPLATFORM
$BUILDPLATFORM
$TARGETPLATFORM
RUN
echo
# 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
例子
以下是多平台构建的一些示例:
使用仿真进行简单的多平台构建
此示例演示如何使用 与 QEMU 进行仿真。该镜像包含一个文件,该文件将 容器的架构。
先决条件:
- Docker Desktop 或安装了 QEMU 的 Docker Engine
- 已启用 containerd 镜像存储
步骤:
创建一个空目录并导航到它:
$ mkdir multi-platform $ cd multi-platform
创建一个简单的 Dockerfile,用于打印容器的架构:
# syntax=docker/dockerfile:1 FROM alpine RUN uname -m > /arch
为 和 构建镜像:
linux/amd64
linux/arm64
$ docker build --platform linux/amd64,linux/arm64 -t multi-platform .
运行镜像并打印体系结构:
$ docker run --rm multi-platform cat /arch
- 如果您在 x86-64 计算机上运行,您应该会看到 .
x86_64
- 如果您在 ARM 计算机上运行,则应看到 .
aarch64
- 如果您在 x86-64 计算机上运行,您应该会看到 .
使用 Docker Build Cloud 进行多平台 Neovim 构建
此示例演示如何使用 Docker Build 运行多平台构建
用于编译和导出 Neovim 二进制文件的云
为和平台。linux/amd64
linux/arm64
Docker Build Cloud 提供支持原生 多平台构建,无需仿真,使其更快 执行 CPU 密集型任务,例如编译。
先决条件:
步骤:
创建一个空目录并导航到它:
$ mkdir docker-build-neovim $ cd docker-build-neovim
创建一个构建 Neovim 的 Dockerfile。
# syntax=docker/dockerfile:1 FROM debian:bookworm AS build WORKDIR /work RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ apt-get update && apt-get install -y \ build-essential \ cmake \ curl \ gettext \ ninja-build \ unzip ADD https://github.com/neovim/neovim.git#stable . RUN make CMAKE_BUILD_TYPE=RelWithDebInfo FROM scratch COPY --from=build /work/build/bin/nvim /
为 Docker Build Cloud 构建镜像并使用 Docker Build Cloud:
linux/amd64
linux/arm64
$ docker build \ --builder <cloud-builder> \ --platform linux/amd64,linux/arm64 \ --output ./bin .
此命令使用 Cloud Builder 构建镜像,并将 二进制文件添加到目录中。
bin
验证二进制文件是否为这两个平台构建。您应该会看到 和 的二进制文件。
nvim
linux/amd64
linux/arm64
$ tree ./bin ./bin ├── linux_amd64 │ └── nvim └── linux_arm64 └── nvim 3 directories, 2 files
交叉编译 Go 应用程序
此示例演示了如何为多个 平台。该应用程序是一个简单的 HTTP 服务器 侦听端口 8080 并返回容器的架构。 此示例使用 Go,但相同的原则也适用于其他编程 支持交叉编译的语言。
使用 Docker 构建的交叉编译通过利用一系列 预定义的(在 BuildKit 中)构建参数,为您提供有关 builder 和 build 目标的平台。您可以使用这些预定义的 arguments 将平台信息传递给编译器。
在 Go 中,你可以使用 和 环境变量来指定
目标平台。GOOS
GOARCH
先决条件:
- Docker Desktop 或 Docker Engine
步骤:
创建一个空目录并导航到它:
$ mkdir go-server $ cd go-server
创建一个构建 Go 应用程序的基本 Dockerfile:
# syntax=docker/dockerfile:1 FROM golang:alpine AS build WORKDIR /app ADD https://github.com/dvdksn/buildme.git#eb6279e0ad8a10003718656c6867539bd9426ad8 . RUN go build -o server . FROM alpine COPY --from=build /app/server /server ENTRYPOINT ["/server"]
此 Dockerfile 还不能构建具有交叉编译的多平台。如果 您将尝试使用 、构建器 将尝试使用仿真为指定的 平台。
docker build
要添加交叉编译支持,请更新 Dockerfile 以使用 pre-defined 和 build 参数。这些 当您将标志与 .
BUILDPLATFORM
TARGETPLATFORM
--platform
docker build
- 使用选项将镜像固定到构建器的平台。
golang
--platform=$BUILDPLATFORM
- 为 Go 编译阶段添加说明,以使 和 build 参数可用于
这个阶段。
ARG
TARGETOS
TARGETARCH
- 将 和 环境变量设置为 和 的值。Go 编译器使用这些变量来执行
交叉编译。
GOOS
GOARCH
TARGETOS
TARGETARCH
# syntax=docker/dockerfile:1 FROM --platform=$BUILDPLATFORM golang:alpine AS build ARG TARGETOS ARG TARGETARCH WORKDIR /app ADD https://github.com/dvdksn/buildme.git#eb6279e0ad8a10003718656c6867539bd9426ad8 . RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o server . FROM alpine COPY --from=build /app/server /server ENTRYPOINT ["/server"]
# syntax=docker/dockerfile:1 FROM golang:alpine AS build WORKDIR /app ADD https://github.com/dvdksn/buildme.git#eb6279e0ad8a10003718656c6867539bd9426ad8 . RUN go build -o server . FROM alpine COPY --from=build /app/server /server ENTRYPOINT ["/server"]
# syntax=docker/dockerfile:1 -FROM golang:alpine AS build +FROM --platform=$BUILDPLATFORM golang:alpine AS build +ARG TARGETOS +ARG TARGETARCH WORKDIR /app ADD https://github.com/dvdksn/buildme.git#eb6279e0ad8a10003718656c6867539bd9426ad8 . -RUN go build -o server . RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o server . FROM alpine COPY --from=build /app/server /server ENTRYPOINT ["/server"]
- 使用选项将镜像固定到构建器的平台。
为 和 构建镜像:
linux/amd64
linux/arm64
$ docker build --platform linux/amd64,linux/arm64 -t go-server .
此示例展示了如何为多个 平台。如何进行交叉编译的具体步骤 可能会因您使用的编程语言而异。查阅 编程语言的文档,了解有关交叉编译的更多信息 适用于不同的平台。
提示
您可能还需要考虑查看 xx - Dockerfile 交叉编译帮助程序。 是一个 Docker 镜像,其中包含实用程序脚本,可以更轻松地与 Docker 构建进行交叉编译。
xx