Skip to content
Open
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,62 @@ Or pull images directly:
docker pull localhost:8080/library/nginx:latest
```

#### containerd (Kubernetes, k3s, nerdctl)

containerd mirrors send the original registry host in an `ns` query
parameter, so one mirror entry can serve Docker Hub and the registries
configured in `upstream.oci` whose URL has no path. Point containerd's CRI
plugin at a hosts directory in `/etc/containerd/config.toml` and restart
containerd. For containerd 2.x:

```toml
version = 3

[plugins."io.containerd.cri.v1.images".registry]
config_path = "/etc/containerd/certs.d"
```

For containerd 1.x:

```toml
version = 2

[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
```

Then create `/etc/containerd/certs.d/_default/hosts.toml`:

```toml
[host."http://proxy.example.com:8080"]
capabilities = ["pull", "resolve"]
```

To check that CRI picked up the directory, confirm the setting containerd
runs with and pull through CRI (on k3s use `k3s crictl`):

```bash
containerd config dump | grep config_path
crictl pull docker.io/library/nginx:latest
```

The proxy logs a `container manifest request` line for the pull and, when
`access_log.path` is set, an access-log entry. `ctr images pull --hosts-dir`
is no substitute for this check: it reads the directory itself and succeeds
even while CRI still has no `config_path`.

`docker.io` and the host of `upstream.oci_default` use the default registry;
the host of each `upstream.oci` URL uses that named registry. Pulls for any
other registry get `404 NAME_UNKNOWN`, and containerd falls back to the
registry itself; only an image path that itself starts with `upstream/{name}/`
always selects that upstream. Existing per-registry `hosts.toml` files that point at
`/v2/upstream/{name}` with `override_path = true` keep working, also when
that upstream is a mirror of the registry the nodes pull from. See [docs/configuration.md](docs/configuration.md) for how
hosts are matched and which entry wins when two share a host. k3s generates
the hosts directory itself from `/etc/rancher/k3s/registries.yaml`; `mirrors:
{"*": {endpoint: ["http://proxy.example.com:8080"]}}` produces the same
`_default` entry.

### Helm

Configure each HTTP chart repository with a name, then add the matching proxy
Expand Down
24 changes: 24 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,30 @@ mise section in the README for the client-side `url_replacements`.
while `upstream.oci` selects named registries through the `upstream/{name}/`
repository prefix. For example, `oci://proxy.example.com/upstream/ghcr/owner/chart`
uses the `ghcr` registry with `owner/chart` as its repository.

containerd mirror requests carry the original registry host in an `ns` query
parameter (see the containerd section in the README). The proxy only looks the
host up and never connects to it: `docker.io`, `index.docker.io`,
`registry-1.docker.io` and the host of `upstream.oci_default` select the default
registry, and the host of each `upstream.oci` URL selects that named registry.
Hosts are compared case-insensitively. The scheme's default port (443 for
`https`, 80 for `http`) may be spelled out or left out in the image reference;
any other port must match exactly, so `https://registry.example:80` and
`https://registry.example` are two different registries. An
unknown host returns `404 NAME_UNKNOWN`, so containerd falls back to its next
host. Registry URLs with a path (for example an Artifactory repository path)
are not reachable through `ns`, only through `upstream/{name}/`. When two
entries share a host, the proxy logs a warning at startup; the default registry
wins, otherwise the alphabetically first name. Pulls through `ns`,
`upstream/{name}/` and unprefixed requests share the same cache entries.
Requests that combine the `upstream/{name}/` prefix with `ns`, as per-registry
containerd mirrors with `override_path = true` send them, are routed by the
prefix. They are refused only when `ns` names a host that belongs to another
configured route. Docker Hub (`docker.io` and its aliases) is always accepted
there, because Docker Hub repository names have two path components and can
never start with `upstream/`, so a Docker Hub mirror behind any prefix stays
reachable. A host the proxy does not know is accepted as well, for example
`ghcr.io` when the upstream is a mirror of it.
When the proxy uses plain HTTP (for example `localhost:8080`), pass
`--plain-http` to Helm OCI commands.

Expand Down
Loading
Loading