15

我正在编写一个 docker 注册表 API 包装器来从一个私有注册表中提取图像并将它们推送到另一个。

首先,根据文档,我需要为image:tag. 在 Puling An Image之后,我已经成功下载了特定image:tag和清单的所有层。

推送图像之后,我遵循了以下步骤:

  1. POST /v2/<name>/blobs/uploads/(获取 UUID 即Location标头)
  2. HEAD /v2/<name>/blobs/<digest>(检查它是否已经存在于注册表中)
  3. PUT /v2/<name>/blobs/uploads/<uuid>?digest=<digest>( Monolithic Upload)

我不清楚的是以下几点:

  1. 我推送的每个单独层是UUID唯一的还是所有层都重复使用(例如,我是否需要为每个层运行一个新的 POST 并UUID在尝试上传之前获取一个新的?)。
  2. Completed Upload部分表示

为了使上传被认为是完整的,客户端必须在上传端点上提交一个带有摘要参数的 PUT 请求

但是,如前所述,我正在使用Monolithic Upload,它使用 aPUT并且与 Completed Upload 部分中显示的请求相同。那么通过整体上传,我是否也同时完成了上传?

问题

  1. 当我完成上述所有步骤时,我BLOB_UNKNOWN 在上传摘要时收到错误消息,例如

    { "errors:" [{ "code": "BLOB_UNKNOWN", "message": "blob unknown to registry", "detail": { "digest": } }, ... ] }

根据文档,推送清单时会产生此错误,并且清单中的其中一个层是未知的:

如果注册表未知一个或多个层,则返回 BLOB_UNKNOWN 错误。错误响应的详细信息字段将包含一个摘要字段,用于标识丢失的 blob。每个未知 blob 都会返回一个错误。响应格式如下:

让我感到困惑的是

  1. 我推送的是摘要(又名层)而不是清单,那么为什么会返回此错误?
  2. 我希望 blob 是未知的,因为我正在将新图像推送到注册表中

现在我将使用 docker 客户端,但我还没有在网上找到任何包装器示例来了解它是如何实现的。大概我错过了一些逻辑或误解了文档,但我不确定我哪里出错了?

4

1 回答 1

4

哇,很高兴知道我不是唯一一个迷失在 V2 API 中的人......

我正在实现一个类似的库并遇到了同样的问题。根据我对文档的理解,有两个Monolithic上传:单个交换POST变体(在文档底部提到)和两个交换POST+PUT变体(在文档顶部提到)。

我无法让 POST-only 方法正常工作。就我而言,我使用它在图层 blob 之后和注册表清单之前上传图像清单。虽然 POST 显示成功并返回 202,但注册表上的调试日志显示它从未从暂存位置复制到数据存储中(就像在分块上传之后发生的那样)。随后上传清单的尝试失败并显示 400,并调试日志记录“注册表未知的 blob”。

但是,我能够通过使用 POST+PUT 方法解决此问题。

对我来说,文档中的关键部分是:

尽管指定了 Location 标头的 URI 格式 (/v2//blobs/uploads/),但客户端应将其视为不透明的 url,并且永远不应尝试组装它。

单片上传只是带有单个块的分块上传......

按照这两个说明,我使用 POST 创建了一个新的 Location 标头(和 UUID),附加了摘要值,并通过将 blob 放到修改后的位置来完成上传。

旁注:查看注册表调试日志,docker CLI在开始新上传之前检查 blob 的存在(以及在完成上传之后——假设对状态代码进行双重检查)。

更新:发现自己又在做这个了,我想我会告诉你我发现了什么......

注册中心只支持在PATCHPUT操作期间处理响应体;不会为POSTcopyFullPayload调用帮助程序。此外,所有上传似乎都被视为整体上传(从某种意义上说,它们从单个请求正文流式传输 blob),因为似乎没有实现对标头的处理。Content-Range

旁注:我在大修期间在增加V2 API的测试覆盖率的范围内进行了这个分析;是 POST+PUT 方法的一个工作示例。一般来说,我发现官方文档在标题和状态代码方面与当前的实现不同步。我已经针对本地 V2 注册表和 DockerHub 对此进行了测试,但没有针对其他注册表(例如 DTR、quay 或 MCR)进行测试。

于 2019-07-17T03:53:57.637 回答