A containerd registry mirror doesn’t actually make your image pulls faster on its own; it makes them more reliable and available when the primary registry is slow or down.
Let’s see it in action. Imagine you’re running a Kubernetes cluster and need to pull an image from docker.io. Without a mirror, containerd directly contacts docker.io for every image layer. If docker.io is experiencing high latency or a transient outage, your pods won’t start.
Now, let’s configure a mirror. We’ll edit the containerd configuration file, typically located at /etc/containerd/config.toml.
# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri"]
...
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://registry-1.docker.io", "https://mirror.gcr.io"] # Example mirrors
...
In this snippet, we’ve added a mirrors section for docker.io. When containerd needs to pull an image from docker.io, it will now try https://registry-1.docker.io first (which is the default, but good to be explicit), and if that fails or is too slow, it will fall back to https://mirror.gcr.io.
The magic isn’t in speed, but in redundancy. If docker.io is having issues, containerd can seamlessly pull from mirror.gcr.io. This significantly reduces the chance of your deployments being blocked by external registry unavailability.
Here’s the mental model:
-
The Problem: External container registries (like Docker Hub, Quay.io, etc.) are shared resources. Their performance and availability can fluctuate. If your cluster relies solely on them, any hiccup on their end can halt your application deployments and updates. This is especially problematic for critical systems or in regions with poor network connectivity to the primary registry.
-
The Solution (Mirrors): A registry mirror is essentially a local or geographically closer copy of a remote registry. When you configure a mirror for a specific registry, containerd will attempt to fetch image layers from the mirror before or in parallel with the primary registry. If the mirror is reachable and has the layers, containerd uses those. If not, it proceeds to the next mirror or the original registry.
-
How it Works Internally: When containerd receives a request to pull an image (e.g.,
docker.io/library/nginx:latest), it consults its configuration. If a mirror is defined fordocker.io, it constructs a list of potential endpoints. It then tries to contact these endpoints in the order they are listed, or in parallel depending on its internal fetching strategy. For each image layer (identified by its digest), it will first query the mirror endpoints. If a mirror successfully serves the layer, containerd uses it and marks the primary registry’s attempt as unnecessary for that layer. If a mirror fails or times out, containerd moves to the next mirror in the list or eventually tries the original registry. -
Configuration Levers:
- Registry Hostname: The key in the
mirrorsmap ("docker.io"in our example) must precisely match the hostname used in your image references. If you pullregistry.example.com/myimage:tag, you need a mirror configured forregistry.example.com. - Endpoint List: The
endpointvalue is a list of URLs for your mirror registries. containerd will try these in order. You can list multiple mirrors for a single upstream registry. - Protocol: Mirrors should typically use
https. - Authentication: If your mirror requires authentication, this is configured separately via
config.tomlunder[plugins."io.containerd.grpc.v1.cri".registry.auth]or through Kubernetes secrets for image pull secrets. The mirror configuration itself doesn’t handle authentication. - Local Caching: While mirrors provide redundancy, they don’t inherently cache images like a local proxy would. containerd itself caches pulled images on the host, but a mirror is an external source it prefers to pull from. For true local caching and proxying, you’d look into solutions like Harbor or Sonatype Nexus.
- Registry Hostname: The key in the
The common misconception is that a mirror is a cache. It’s not. A mirror is an alternative source. If containerd pulls an image layer from registry-1.docker.io, that layer is then cached by containerd itself on the node. Subsequent pulls of that exact same layer will be served from containerd’s local cache, which is fast. The mirror only comes into play if the primary registry is unavailable or slow during the initial pull.
Once you have mirrors configured and your images are pulling successfully, the next challenge is ensuring your nodes have enough disk space for all the images they’re pulling and caching.