Work with registry behavior
Two recurring registry tasks: fronting an upstream whose content digests are not sha256, and cleaning up a blob upload
that stalled. This guide covers both, the digest to pin by when the upstream uses sha512, and the two moves that reclaim
or resume a half-done push. The examples assume peryx at http://127.0.0.1:4433.
Front a registry that uses non-sha256 digests
Most registries content-address with sha256, but the OCI spec allows sha512 and other registered algorithms, and some
registries advertise their Docker-Content-Digest in one of them. peryx proxies such an upstream with no special
configuration; the two things to get right are which digest to pin by and where the support stops.
Point a cached index at it
Nothing about the digest algorithm is configurable, so a cached index is the usual one:
# peryx.toml
[[index]]
name = "reg"
route = "reg"
ecosystem = "oci"
cached = "https://registry.example.com"
Pull as normal. peryx fetches the manifest, hashes the exact bytes under its own sha256, and serves them:
crane manifest --insecure 127.0.0.1:4433/reg/team/app:1.0Pin by the digest peryx reports, not the upstream's
peryx addresses every manifest it stores by sha256, so the digest it hands your clients for a tag pull is a sha256:
value, even when the upstream advertised sha512. Read it from the response header:
curl -sI http://127.0.0.1:4433/v2/reg/team/app/manifests/1.0 | grep -i docker-content-digest
Pin deployments to that sha256. It is the digest peryx serves the image under and the one a client verifies the bytes against. If you carry an upstream sha512 digest from elsewhere, a pull by it still works, and peryx serves the bytes under the digest you request and echoes it back:
crane manifest --insecure 127.0.0.1:4433/reg/team/app@sha512:<hex>What still requires sha256
The relaxation is scoped to reading a manifest through a proxy. Three things stay sha256 only:
- Blobs. A blob pull, mount, or upload commit must use
sha256:; any other algorithm answers400 DIGEST_INVALIDwithonly sha256 blob digests are supported. A client that pushes a blob under a non-sha256 digest is rejected. - A wrong sha256 advertisement. If the upstream advertises a
sha256:digest that does not hash the bytes it sent, that is a corrupting hop, and peryx returns502and caches nothing, unchanged. - Offline mirror pins. A mirror entry pinned by digest must be
sha256:.repo@sha512:…fails the mirror's own sha256 comparison; mirror by tag instead, which stores under the canonical sha256.
Verify the proxy
Confirm a tag pull succeeds and reports a sha256 digest:
curl -si http://127.0.0.1:4433/v2/reg/team/app/manifests/1.0 | head -3
A 200 with a docker-content-digest: sha256:… line is the proxy working. A 502 means the upstream advertised a
sha256: digest that did not match its bytes, a corrupting proxy between you and the upstream rather than an algorithm
peryx declined. The exact rules are in
content digest algorithms, and the
reasoning in why peryx accepts a non-sha256 content digest.
Cancel an in-progress upload
A container push is a series of blob uploads, and an upload can be left half-done: a client crashes mid-layer, or a
chunk arrives out of order and peryx answers 416. Both cleanups act on an
upload session, so both need the hosted index's
upload_token as the Basic-auth password (-u _:<token>).
An open session holds a staged temp file on the server. If you abandon the push, that file sits until the session's
one-hour idle timeout reaps it. To release it now, DELETE the session URL, the Location peryx returned when the
session opened:
curl -sS -i -u _:<token> -X DELETE \
http://127.0.0.1:4433/v2/images/<repo>/blobs/uploads/<session>
# 204 No Content
204 means the session and its staged bytes are gone. A session id peryx does not know, including one you already
finished or cancelled, answers 404 BLOB_UPLOAD_UNKNOWN:
curl -sS -i -u _:<token> -X DELETE \
http://127.0.0.1:4433/v2/images/<repo>/blobs/uploads/<already-gone>
# 404 Not Found
Because sessions live in the peryx process, a restart drops every open one, so a DELETE after a restart also answers
404. Reach for cancel in a CI job that aborts a build, or a script that opens a session it then decides not to use, so
the server is not left holding bytes no one will finish.
Resume a push that got a 416
peryx answers a PATCH whose Content-Range does not begin where the last chunk ended with
416 Range Not Satisfiable, and keeps the bytes it already has. The 416 reports the session coordinates you need to
continue:
416 Range Not Satisfiable
Location: /v2/images/<repo>/blobs/uploads/<session>
Docker-Upload-UUID: <session>
Range: 0-<end>
Read Range: 0-<end>: it is the byte span peryx holds, so the next chunk must start at byte <end> + 1. Re-send the
chunk from there against the Location URL:
curl -sS -i -u _:<token> -X PATCH \
-H 'Content-Type: application/octet-stream' \
-H 'Content-Range: <end+1>-<new-end>' \
--data-binary @chunk \
http://127.0.0.1:4433/v2/images/<repo>/blobs/uploads/<session>
# 202 Accepted, Range: 0-<new-end>
If you have lost track of how much landed, ask the session directly. GET on the session URL reports progress as
Range: 0-<end> without changing anything, so you can read the offset before you resume:
curl -sS -i -u _:<token> \
http://127.0.0.1:4433/v2/images/<repo>/blobs/uploads/<session>
# 204 No Content, Range: 0-<end>
Then finish the push with PUT …?digest=sha256:<hex> once the last chunk is in. docker, podman, and crane run
this recovery for you; you only drive it by hand when you are scripting an upload or debugging one that stalls, as in
push a blob chunk by chunk.
Related
- The statuses, headers, and digest rules these commands rely on: registry behavior
- Why peryx serves the registry this way: why peryx serves the registry the way it does
- Every
/v2/upload verb and its success code: HTTP endpoints