registrymirror

package
v0.2.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package registrymirror routes container image pulls through a pull-through registry cache on the LAN.

Why

ephemerd nodes re-pull the same base image constantly. A production linux-amd64 node measured 294 GB inbound over 4.1 days across ~330 jobs — roughly 890 MB per job — and the single biggest contributor was one 1.1 GB CI image pulled 163 times in seven days, because dind pulls into a per-job containerd namespace and the per-repo cache was not retaining content. Layers that a LAN cache would serve at wire speed were crossing the WAN dozens of times a day per node. Pointing every pull at a pull-through cache makes the first pull the only WAN pull, and takes the node out of Docker Hub's anonymous rate limit besides.

How

containerd's docker resolver picks a registry endpoint through a docker.RegistryHosts function: given the host part of a reference ("docker.io"), it returns an ordered list of endpoints to try. The resolver walks that list and moves to the next entry whenever one fails to answer, 404s, or returns any 4xx/5xx. So "mirror first, origin second" is expressed directly as a two-element host list, and fail-open falls out of the resolver's own retry loop — no health checking, no circuit breaker, no state.

The mirror entry is advertised with pull+resolve capabilities only. Pushes never touch it: a pull-through cache is not somewhere to publish, and the push path (pkg/dind/registry.go) is deliberately left on the origin registry.

No-mirror path

Every entry point is nil-safe and returns no options when no mirror is configured, so an unconfigured node builds exactly the same pull call it built before this package existed.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func RegistryHostFromRef

func RegistryHostFromRef(ref string) string

RegistryHostFromRef peels the registry hostname off an image reference, applying Docker's rule that a first segment without a dot, colon, or the literal name "localhost" is not a host at all but the start of a Docker Hub repository path.

It exists here so the mirror lookup agrees with the host containerd's own reference parser will hand to RegistryHosts.

Types

type Creds

type Creds func(host string) (string, string, error)

Creds supplies a username/secret pair for a registry host. It matches the shape docker.WithAuthCreds wants. A nil Creds means anonymous.

type Mirror

type Mirror struct {
	// contains filtered or unexported fields
}

Mirror is a resolved, immutable mirror policy shared by every pull path. A nil *Mirror means "no mirror configured" and every method on it is a no-op, so callers never need a branch.

func New

New builds a Mirror from configuration. It returns nil when mirroring is disabled or nothing is mapped — the caller keeps the nil and every method stays a no-op.

cfg must have passed config validation; malformed endpoints are dropped here with a warning rather than failing, because by this point the daemon is already running and degrading to origin pulls beats refusing to start.

func (*Mirror) Enabled

func (m *Mirror) Enabled() bool

Enabled reports whether this Mirror routes anything. Nil-safe.

func (*Mirror) Endpoint

func (m *Mirror) Endpoint(registry string) (*url.URL, bool)

Endpoint returns the mirror base URL serving an upstream registry host, and whether one is configured. The argument is normalized, so both "docker.io" and "index.docker.io" find a docker.io mapping. Nil-safe.

func (*Mirror) LogPull

func (m *Mirror) LogPull(ref string)

LogPull emits one line per pull naming the endpoint actually tried first, so an operator can confirm from the daemon log that traffic is going to the cache. No-op when no mirror covers the reference.

func (*Mirror) PullOpts

func (m *Mirror) PullOpts(creds Creds) []client.RemoteOpt

PullOpts returns the containerd RemoteOpts that route a pull through the mirror, authenticating with creds where credentials are needed.

It returns nil — meaning "add nothing to the pull" — when no mirror is configured AND no credentials were supplied. That is the important property for the no-mirror path: an unconfigured node's client.Pull call is byte-identical to what it was before this package existed, right down to containerd constructing its own default resolver internally.

Pass nil creds for an anonymous pull.

func (*Mirror) RegistryHosts

func (m *Mirror) RegistryHosts(creds Creds) docker.RegistryHosts

RegistryHosts returns the docker.RegistryHosts function containerd's resolver consults for each reference. For a mirrored registry the list is [mirror, origin] (or [mirror] with fallback disabled); for every other registry it is exactly the containerd default, so a node with a docker.io mirror still reaches ghcr.io the ordinary way.

Nil-safe: a nil Mirror yields the containerd default for every host, which is what makes this usable as the single code path for "pull with credentials, no mirror" too.

func (*Mirror) Resolver

func (m *Mirror) Resolver(creds Creds) remotes.Resolver

Resolver builds a containerd resolver honoring this mirror. Exported for the pull paths that need the resolver itself rather than a RemoteOpt, and for tests.

func (*Mirror) String

func (m *Mirror) String() string

String renders the policy for diagnostics.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL