是否可以在 linux 机器上将多 OS 映像从一个 docker 注册表复制到另一个注册表?

Is it possible to copy a multi-OS image from one docker registry to another on a linux machine?

我需要一种方法来将我的清单和所有相关的 blobs/etc 从私有注册表复制到 public 注册表,之前从未将图像推送到 public 注册表。

我正在通过 buildah 成功创建多架构清单。请注意,虽然图像是使用 buildah 构建的,但我对基于 docker 的方法在注册表之间复制最终结果感到满意。这是 buildah inspect 的输出:

{
    "schemaVersion": 2,
    "manifests": [
        {
            "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
            "digest": "sha256:e1c1de1b56adc07e5a97970b3340b1cf71c02796eb4e27c638634b6bcf0e510e",
            "size": 5590,
            "platform": {
                "architecture": "amd64",
                "os": "windows"
            }
        },
        {
            "mediaType": "application/vnd.oci.image.manifest.v1+json",
            "digest": "sha256:c4bf2b94bbedceab3888544f4b966e8c1435231daeff27546acaf3b817485226",
            "size": 511,
            "platform": {
                "architecture": "amd64",
                "os": "linux"
            }
        }
    ]
}

在现实中,会有更多的排列......但这个简单的清单证明了这个问题。

出于性能(和其他各种)原因,我的 CI 将此映像推送到本地注册表。测试完最终清单后,我想将其推送到具有相同标签的 public docker.io 注册表。

在我将 Windows 添加到组合中之前,我能够通过拉取每个图像、使用新注册表重新标记它并推送来完成此操作。像...

buildah manifest create docker.io/img/name:latest

# Retag & add windows...
buildah pull myreg/img/name:windows
buildah tag myreg/img/name:windows docker.io/img/name:windows
buildah push docker.io/img/name:windows
buildah manifest add docker.io/img/name:latest docker.io/img/name:windows

# ... other variants ...

不幸的是,这不适用于 Windows。当 Linux 机器尝试拉取 Windows 图像时,我收到以下错误:

Error committing the finished image: error adding layer with blob "sha256:0363fe57a309a0e39c3dd1bb7be80beed88dcef74b1773ee1a37f6caf81e0fe2": Error processing tar file(exit status 1): link /Files/Program Files/common files/Microsoft Shared/Ink/en-US/micaut.dll.mui /Files/Program Files (x86)/common files/Microsoft Shared/ink/en-US/micaut.dll.mui: no such file or directory

我是否需要使用 Windows 机器进行重新标记,图像从本地复制到 public 注册表?或者是否有一种简单的方法可以 copy/mirror 整个清单而不添加所有这些额外的 pull/tag/push 步骤?

对于注册表之间的复制,您可以点击注册表 API 而无需与 docker 引擎或任何其他容器交互 运行 时间。这些图像是 OCI 图像规范中描述的 json 清单和压缩的 tar blob,并且 API 对注册表中的图像的访问现在包含在 OCI 分发规范中。

其中最复杂的部分通常是处理可能因注册表服务器而异的身份验证,否则它可以相当容易地在 shell 脚本中使用各种 curl 和 jq 命令实现。我最终制作了自己的工具来处理这个确切的用例,可在 github.com/regclient/regclient 上获得。对于您的具体要求,您会 运行:

regctl image copy myreg/img/name:latest docker.io/img/name:latest

我认为实现这些功能的类似工具包括 RedHat 的 skopeo 和 Google 的 crane(他们的 go-containerregistry 项目的一部分)。