Support the containerd ns query parameter for multi-registry mirroring
The container handler currently routes /v2/ requests by path only: unprefixed names go to the default registry (upstream.oci_default), and named upstreams require the reserved upstream/{name}/ path prefix. containerd's hosts.toml mirror mechanism instead appends ?ns=<registry-host> to every request (see containerd hosts.md), which the handler ignores today. Multi-registry mirroring therefore needs one hosts.toml per registry with override_path = true pointing at the matching prefix; wildcard setups (certs.d/_default, k3s mirrors: "*") cannot work at all, because the mirror never learns which registry a request is for.
Add ns support so a single host entry can mirror every configured registry.
Requirements
- Treat
ns as a closed-world lookup key, never a dial target: resolve Docker Hub aliases (docker.io, index.docker.io, registry-1.docker.io) and the host of the configured oci_default to the default route, and hosts derived from the existing upstream.oci URLs to their named upstream. No new config keys. Host matching is case-insensitive and normalizes scheme-default ports.
- Unknown
ns returns an OCI-error 404 (NAME_UNKNOWN) so containerd falls back to its next host / server entry; requests without ns behave exactly as today.
- When
ns is present, the path is the verbatim upstream repository; reject the reserved upstream/ prefix on that route so ns-routed requests cannot mint cache keys belonging to the prefix route.
- Strip
ns before forwarding the tags-list query upstream (it currently leaks verbatim).
- Cache identities are reused so an image pulled via ns, via
upstream/{name}/, or unprefixed shares cache entries; manifest keys already include the resolved registry URL.
- Auth needs no changes: configured credentials and Bearer-challenge tokens are keyed on the resolved upstream URL.
Implementation notes
- Build the ns host index after
NewContainerHandlerWithRegistry overrides the default registry URL, otherwise a custom oci_default host would 404.
- Duplicate hosts across
upstream.oci entries (or colliding with the default route) get a startup warning and a deterministic winner rather than a validation error.
- Blob digest verification on ingest is tracked separately but recommended as a preparatory change, since shared cache identities make unverified ingest a cross-route concern.
Tests
- containerd-style pulls for
docker.io (client-normalized library/ names) and a named registry.
ns=<custom-default-host> with an overridden oci_default.
- Unknown ns → 404 with no upstream contact.
- Cache sharing across the three routes (default,
upstream/{name}/, ns).
upstream/-prefix rejection under ns.
- No
ns leakage to upstreams.
- README and
docs/configuration.md instructions with a _default hosts.toml example.
Support the containerd
nsquery parameter for multi-registry mirroringThe container handler currently routes
/v2/requests by path only: unprefixed names go to the default registry (upstream.oci_default), and named upstreams require the reservedupstream/{name}/path prefix. containerd'shosts.tomlmirror mechanism instead appends?ns=<registry-host>to every request (see containerd hosts.md), which the handler ignores today. Multi-registry mirroring therefore needs onehosts.tomlper registry withoverride_path = truepointing at the matching prefix; wildcard setups (certs.d/_default, k3smirrors: "*") cannot work at all, because the mirror never learns which registry a request is for.Add
nssupport so a single host entry can mirror every configured registry.Requirements
nsas a closed-world lookup key, never a dial target: resolve Docker Hub aliases (docker.io,index.docker.io,registry-1.docker.io) and the host of the configuredoci_defaultto the default route, and hosts derived from the existingupstream.ociURLs to their named upstream. No new config keys. Host matching is case-insensitive and normalizes scheme-default ports.nsreturns an OCI-error 404 (NAME_UNKNOWN) so containerd falls back to its next host /serverentry; requests withoutnsbehave exactly as today.nsis present, the path is the verbatim upstream repository; reject the reservedupstream/prefix on that route so ns-routed requests cannot mint cache keys belonging to the prefix route.nsbefore forwarding the tags-list query upstream (it currently leaks verbatim).upstream/{name}/, or unprefixed shares cache entries; manifest keys already include the resolved registry URL.Implementation notes
NewContainerHandlerWithRegistryoverrides the default registry URL, otherwise a customoci_defaulthost would 404.upstream.ocientries (or colliding with the default route) get a startup warning and a deterministic winner rather than a validation error.Tests
docker.io(client-normalizedlibrary/names) and a named registry.ns=<custom-default-host>with an overriddenoci_default.upstream/{name}/, ns).upstream/-prefix rejection under ns.nsleakage to upstreams.docs/configuration.mdinstructions with a_defaulthosts.toml example.