我面前有两台电脑,一台Linux/x86_64,一台MacOS/arm64(M2 Mac)。我想构建一个多平台 Docker 镜像。我想在一台计算机上为其自己的架构(例如 x86_64)启动构建过程,上传/推送构建的映像,然后可能将该映像拉到另一台计算机上,为该架构(arm64)构建,然后推送包含多个架构的合成图像。我正在解释 Docker 手册中的这一行:
当您运行支持多平台的镜像时,Docker 会自动选择与您的操作系统和架构相匹配的镜像。
意味着确实存在一个多平台图像实体,而不是通过清单松散链接的两个存储库中的两个图像。
我不想使用 QEMU 进行构建。我不想购买整个云构建器的东西。我想做的事情似乎很简单,但我似乎找不到any有关如何做到这一点的信息。所有信息都是关于在云中使用 QEMU 或本机构建器,以某种方式编排的。有没有办法遵循上面的简单方法?
意味着确实存在一个多平台图像实体,而不是通过清单松散链接的两个存储库中的两个图像。
这令人困惑或者可能不准确。注册表中的多平台镜像由清单列表或索引表示,它是一个包含清单列表的 json 结构(顾名思义)。这些清单均由摘要引用,并位于同一存储库中。最终结果如下:
您可以使用标准 docker 构建创建单个平台映像并将其推送到注册表。要构建多平台映像,对我来说最简单的选择是利用 buildkit 和 buildx,它在运行时默认利用 qemu:
docker buildx build --platform=linux/amd64,linux/arm64 -t $repo:$tag .
如果编译器通过 Dockerfile 中的一些其他选项支持它,您可以跳过 qemu 并利用交叉编译:
# syntax=docker/dockerfile:1
# --platform=$BUILDPLATFORM runs this step on the local architecture
FROM --platform=$BUILDPLATFORM ${base_image} as build
COPY . /src
WORKDIR /src
# builtin vars are exposed to the environment for the target to build
ARG TARGETOS
ARG TARGETARCH
# the make command would need to leverage the TARGETOS and TARGETARCH vars
RUN make app
# this step runs with the target architecture
FROM ${deploy_image} as release
# with only a copy step, and no run commands, there is no qemu involved
COPY --from=build /src/bin/app /usr/local/bin/app
第三个选项是单独构建每个映像,推送到注册表,然后创建引用这两个映像的清单列表。有一些工具可以做到这一点,但我不一定会将此称为简单的选择,因为很少有人这样做(您还要处理构建管道中的竞争条件)。
Docker 的内置工具是
docker manifest
,它具有创建和推送创建的清单的选项。它被标记为实验性的,因此取决于它可能意味着需要在未来的 docker 版本中修改脚本:
$ docker manifest --help
Usage: docker manifest COMMAND
The **docker manifest** command has subcommands for managing image manifests and
manifest lists. A manifest list allows you to use one name to refer to the same image
built for multiple architectures.
To see help for a subcommand, use:
docker manifest CMD --help
For full details on using docker manifest lists, see the registry v2 specification.
EXPERIMENTAL:
docker manifest is an experimental feature.
Experimental features provide early access to product functionality. These
features may change between releases without warning, or can be removed from a
future release. Learn more about experimental features in our documentation:
https://docs.docker.com/go/experimental/
Commands:
annotate Add additional information to a local image manifest
create Create a local manifest list for annotating and pushing to a registry
inspect Display an image manifest, or manifest list
push Push a manifest list to a repository
rm Delete one or more manifest lists from local storage
Run 'docker manifest COMMAND --help' for more information on a command.
由于这可以完全在注册表上完成,因此还有其他不需要了解 docker 的工具可用。我知道的其中两个是 Google 的 Crane 和我自己的 regctl:
$ crane index append --help
This sub-command pushes an index based on an (optional) base index, with appended manifests.
The platform for appended manifests is inferred from the config file or omitted if that is infeasible.
Usage:
crane index append [flags]
Examples:
# Append a windows hello-world image to ubuntu, push to example.com/hello-world:weird
crane index append ubuntu -m hello-world@sha256:87b9ca29151260634b95efb84d43b05335dc3ed36cc132e2b920dd1955342d20 -t example.com/hello-world:weird
# Create an index from scratch for etcd.
crane index append -m registry.k8s.io/etcd-amd64:3.4.9 -m registry.k8s.io/etcd-arm64:3.4.9 -t example.com/etcd
Flags:
--docker-empty-base If true, empty base index will have Docker media types instead of OCI
--flatten If true, appending an index will append each of its children rather than the index itself (default true)
-h, --help help for append
-m, --manifest strings References to manifests to append to the base index
-t, --tag string Tag to apply to resulting image
Global Flags:
--allow-nondistributable-artifacts Allow pushing non-distributable (foreign) layers
--insecure Allow image references to be fetched without TLS
--platform platform Specifies the platform in the form os/arch[/variant][:osversion] (e.g. linux/amd64). (default all)
-v, --verbose Enable debug logs
$ regctl index create --help
Create a manifest list or OCI Index.
Usage:
regctl index create <image_ref> [flags]
Aliases:
create, init, new
Flags:
--annotation stringArray Annotation to set on manifest
--artifact-type string Include an artifactType value
--by-digest Push manifest by digest instead of tag
--desc-annotation stringArray Annotation to add to descriptors of new entries
--desc-platform string Platform to set in descriptors of new entries
--digest stringArray Digest to include in new index
--digest-tags Include digest tags
--format string Format output with go template syntax
-h, --help help for create
-m, --media-type string Media-type for manifest list or OCI Index (default "application/vnd.oci.image.index.v1+json")
--platform stringArray Platforms to include from ref
--ref stringArray References to include in new index
--referrers Include referrers
--subject string Specify a subject tag or digest (this manifest must already exist in the repo)
例如使用
regctl
,看起来像:
$ regctl index create \
--ref registry.example.org/someimage:1.0-amd64 \
--ref registry.example.org/someimage:1.0-arm64 \
registry.example.org/someimage:1.0