Skip to content

多平台构建

原文:https://docs.docker.com/build/guide/multi-platform/

到目前为止,本指南中您已经构建了 Linux 二进制文件。本节将描述如何使用多平台构建通过仿真和跨平台编译来支持其他操作系统和架构。

使用仿真开始为多个平台构建是最简单的方法。通过仿真,您可以为多个架构构建应用程序,而无需对 Dockerfile 进行任何更改。您需要做的只是在构建命令中传递 --platform 标志,并指定您想要构建的操作系统和架构。

以下命令为 linux/arm/v7 平台构建服务器镜像:

console
docker build --target=server --platform=linux/arm/v7 .

您也可以使用仿真同时为多个平台产生输出。然而,Docker Engine 的默认镜像存储不支持构建和加载多平台镜像。您需要启用支持并发多平台构建的 containerd 镜像存储。

启用 containerd 镜像存储

在 Docker Desktop 中启用 containerd 镜像存储,请转到 设置 并在 常规 选项卡中选择 使用 containerd 拉取和存储镜像

请注意,更改镜像存储意味着您将暂时无法访问经典镜像存储中的镜像和容器。这些资源仍然存在,但要查看它们,您需要禁用 containerd 镜像存储。

使用仿真构建

要运行多平台构建,请调用 docker build 命令,并像之前一样传递相同的参数。只是这次,还要添加一个 --platform 标志,指定多个架构。

console
docker build \
    --target=binaries \
    --output=bin \
    --platform=linux/amd64,linux/arm64,linux/arm/v7 .

此命令使用仿真运行同一构建三次,每个平台一次。构建结果导出到 bin 目录。

text
bin
├── linux_amd64
│   ├── client
│   └── server
├── linux_arm64
│   ├── client
│   └── server
└── linux_arm_v7
    ├── client
    └── server

当您同时为多个平台构建时,BuildKit 会在仿真下为您指定的每个平台运行所有构建步骤。实际上,它将构建分成多个并发过程。

使用仿真的构建管道

然而,使用仿真运行多平台构建也有一些缺点:

  • 如果您尝试运行上面的命令,您可能已经注意到它完成需要很长时间。对于 CPU 密集型任务,仿真可能比本机执行慢得多。
  • 仿真只有在您使用的基础镜像支持架构时才有效。本指南中的示例使用的是 Alpine Linux 版本的 golang 镜像,这意味

着您只能以这种方式为有限的一组 CPU 架构构建 Linux 镜像,而不必更改基础镜像。

作为仿真的替代方案,下一步将探索跨平台编译。跨平台编译使多平台构建更快速和多样化。

使用跨平台编译构建

使用跨平台编译意味着利用编译器的能力为多个平台构建,无需仿真。

首先您需要做的是将构建器固定使用节点的本机架构作为构建平台。这是为了防止仿真。然后,从节点的本机架构开始,构建器将应用程序跨平台编译到其他目标平台。

平台构建参数

这种方法涉及使用一些预定义的构建参数,您可以在 Docker 构建中访问这些参数:BUILDPLATFORMTARGETPLATFORM(以及衍生参数,如 TARGETOS)。这些构建参数反映了您传递给 --platform 标志的值。

例如,如果您使用 --platform=linux/amd64 调用构建,则构建参数解析为:

  • TARGETPLATFORM=linux/amd64
  • TARGETOS=linux
  • TARGETARCH=amd64

当您向平台标志传递多个值时,使用预定义平台参数的构建阶段将自动为每个平台分叉。这与在仿真下运行的构建相反,在那里整个构建管道按平台运行。

使用跨平台编译的构建管道

更新 Dockerfile

要使用跨平台编译技术构建应用,请按以下方式更新 Dockerfile:

  • 在初始 base 阶段的 FROM 指令中添加 --platform=$BUILDPLATFORM,将 golang 镜像的平台固定为与主机机器的架构相匹配。
  • 为 Go 编译阶段添加 ARG 指令,使 TARGETOSTARGETARCH 构建参数可用于此阶段的命令。
  • GOOSGOARCH 环境变量设置为 TARGETOSTARGETARCH 的值。Go 编译器使用这些变量进行跨平台编译。
diff
  # syntax=docker/dockerfile:1
  ARG GO_VERSION=1.21
  ARG GOLANGCI_LINT_VERSION=v1.52
- FROM golang:${GO_VERSION}-alpine AS base
+ FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine AS base
  WORKDIR /src
  RUN --mount=type=cache,target=/go/pkg/mod \
      --mount=type=bind,source=go.mod,target=go.mod \
      --mount=type=bind,source=go.sum,target=go.sum \
      go mod download -x

  FROM base AS build-client
+ ARG TARGETOS
+ ARG TARGETARCH
  RUN --mount=type=cache,target=/go/pkg/mod \
      --mount=type=bind,target=. \
-     go build -o /bin/client ./cmd/client
+     GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /bin/client ./cmd/client

  FROM base AS build-server
+ ARG TARGETOS
+ ARG TARGETARCH
  RUN --mount=type=cache,target=/go/pkg/mod \
      --mount=type=bind,target=. \
-     go build -o /bin/server ./cmd/server
+     GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /bin/server ./cmd/server

  FROM scratch AS client
  COPY --from=build-client /bin/client /bin/
  ENTRYPOINT [ "/bin/client" ]

  FROM scratch AS server
  COPY --from=build-server /bin/server /bin/
  ENTRYPOINT [ "/bin/server" ]

  FROM scratch AS binaries
  COPY --from=build-client /bin/client /
  COPY --from=build-server /bin/server /

  FROM golangci/golangci-l

int:${GOLANGCI_LINT_VERSION} as lint
  WORKROOM /test
  RUN --mount=type=bind,target=. \
      golangci-lint run

现在,您需要做的只是运行实际的构建。要运行多平台构建,请设置 --platform 选项,并指定您想要构建的操作系统和架构的 CSV 字符串。以下命令演示了如何为 Mac (ARM64)、Windows 和 Linux 构建并导出二进制文件:

console
docker build \
  --target=binaries \
  --output=bin \
  --platform=darwin/arm64,windows/amd64,linux/amd64 .

构建完成后,您会在 bin 目录中找到所有选定平台的客户端和服务器二进制文件:

diff
bin
├── darwin_arm64
│   ├── client
│   └── server
├── linux_amd64
│   ├── client
│   └── server
└── windows_amd64
    ├── client
    └── server

总结

本节演示了如何使用仿真和跨平台编译开始多平台构建。

相关信息:

您可能还想了解一下 xx - Dockerfile 跨平台编译助手xx 是一个包含使 Docker 构建中的跨平台编译更简单的实用脚本的 Docker 镜像。

下一步

本节是“使用 Docker 构建”的最后一部分。以下页面包含一些下一步的指引。