I'm a writing a docker registry API wrapper to pull images from one private registry and push them to another.
Based on the documentation first I need to pull the manifest and the layers for an image:tag
. Following Puling An Image I've successfully downloaded all the layers for a particular image:tag
and the manifest.
Following Pushing An Image I've followed the steps:
POST /v2/<name>/blobs/uploads/
(to get the UUID i.e.Location
header)HEAD /v2/<name>/blobs/<digest>
(check to see if it already exists in the registry)PUT /v2/<name>/blobs/uploads/<uuid>?digest=<digest>
(Monolithic Upload
)
What's not clear to me are the following:
- Is the
UUID
unique to each individual layer I push or is that reused for all layers (e.g. Do I need to run a new POST for each layer an get a newUUID
before I attempt to upload it?). - The Completed Upload section indicates
For an upload to be considered complete, the client must submit a PUT request on the upload endpoint with a digest parameter
However, as mentioned I'm using the Monolithic Upload which uses a PUT
and would be the same request as what shows in the Completed Upload section. So by doing a monolithic upload am I also completing the upload at the same time?
Problem
When I go through all the steps above I receive the
BLOB_UNKNOWN
error when uploading a digest, e.g.{ "errors:" [{ "code": "BLOB_UNKNOWN", "message": "blob unknown to registry", "detail": { "digest": } }, ... ] }
According to the docs this error is produced when pushing a manifest and one of the layers in the manifest are unknown:
If one or more layers are unknown to the registry, BLOB_UNKNOWN errors are returned. The detail field of the error response will have a digest field identifying the missing blob. An error is returned for each unknown blob. The response format is as follows:
What confuses me about this is
- I'm pushing a digest (aka a layer) not the manifest so why is this error returning?
- I would expect the blob to be unknown because I'm pushing a new image into the registry
For now I'm going to use the docker client, but I haven't found any wrapper examples on-line to see how this is pulled off. Presumably I'm missing some logic or misunderstanding the docs, but I'm not sure where I'm going wrong?