Why Use a Registry Mirror?
As of April 1, 2025, Docker has implemented new pull rate limits for Docker Hub. These changes may significantly impact Kubernetes Clusters.
Here’s a quick overview of the updated limits:
User Type | Pull Rate Limit (per 6 hours) | Public Repositories | Private Repositories |
---|---|---|---|
Business (authenticated) | Unlimited | Unlimited | Unlimited |
Team (authenticated) | Unlimited | Unlimited | Unlimited |
Pro (authenticated) | Unlimited | Unlimited | Unlimited |
Personal (authenticated) | 200 | Unlimited | Up to 1 |
Unauthenticated users | 100 per IP | N/A | N/A |
When unauthenticated, Docker Hub will limit you to 100 pulls every 6 hours per IPv4 address or IPv6 /64 subnet.
For more details, check the official Docker Hub pull usage and limits documentation.
To avoid these limitations and make your Kubernetes clusters more resilient and performant, setting up a local registry mirror is highly recommended.
One great option: the k3s embedded registry mirror.
Setting Up the k3s Embedded Registry Mirror
As of December 2024, the embedded registry mirror in k3s is GA (Generally Available) in the following versions:
- v1.29.12+k3s1
- v1.30.8+k3s1
- v1.31.4+k3s1
Earlier versions from January 2024 had it available as an experimental feature.
The embedded mirror is powered by Spegel, a stateless distributed OCI registry mirror that allows peer-to-peer sharing of container images across your k3s cluster.
1. Enable the Distributed OCI Registry Mirror
You must start the server nodes with the embedded registry enabled. Add the following to your k3s config file or CLI options:
# /etc/rancher/k3s/config.yaml
embedded-registry: true
Alternatively, using the CLI:
k3s server --embedded-registry
Once enabled:
- Every node hosts a local OCI registry on port
6443
. - Nodes advertise available images over a peer-to-peer network on port
5001
.
You can change the peer-to-peer port by setting the K3S_P2P_PORT
environment variable, but this is not recommended.
Important: All nodes must be able to reach each other over their internal IPs on TCP ports 5001 and 6443.
2. Enable Registry Mirroring
To mirror images from Docker Hub (docker.io
) or Kubernetes Registry (registry.k8s.io
), edit or create the registries.yaml
file on all nodes:
# /etc/rancher/k3s/registries.yaml
mirrors:
docker.io:
registry.k8s.io:
If you prefer to mirror all registries automatically, wildcard support is available:
mirrors:
"*":
Note: You must quote the
*
wildcard!
3. Special Handling for latest
Tag
Images pulled with the latest
tag are not distributed between nodes by default.
To mirror images tagged as latest
, set this environment variable:
K3S_P2P_ENABLE_LATEST=true
Warning: Enabling this is unsupported and not recommended because
latest
tags can frequently change.
4. Security Considerations
- Access to the embedded registry requires a client certificate signed by the cluster’s CA.
- The peer-to-peer network uses a pre-shared key and mutual certificate authentication.
- Be aware: All nodes can share images, even if some images were originally private.
- To avoid potential tampering, always reference images by digest, not by mutable tags.
5. Sharing Air-gap or Manually Loaded Images
You can manually load images into the embedded registry using ctr
:
ctr -n k8s.io image import /path/to/image.tar
or pull directly:
ctr -n k8s.io image pull docker.io/library/nginx:latest
Tip: Always use the
k8s.io
namespace when managing images withctr
so they are visible to Kubernetes.
6. Monitoring Spegel Metrics
Spegel, the engine behind the embedded registry mirror, exposes Prometheus-compatible metrics. These help you monitor the health and performance of your image distribution.
Here are the key metrics you should care about:
Metric | Type | Why It Matters |
---|---|---|
spegel_advertised_images |
Gauge | Shows how many images your node is sharing with others. A sudden drop might indicate problems with local images or networking. |
spegel_mirror_requests_total |
Counter | Counts image pull requests handled by Spegel, with labels like cache=hit or miss andsource=internal external . Use it to measure how effective the mirror is. High miss counts may suggest missing images. |
spegel_resolve_duration_seconds |
Histogram | Tracks how long it takes to resolve image requests. Spikes here might indicate network issues or slow storage. |
http_request_duration_seconds |
Histogram | Measures how long HTTP requests to the embedded registry take. Useful for spotting performance bottlenecks. |
http_requests_inflight |
Gauge | Shows how many requests are currently being processed. High values could hint at overloaded nodes. |
Example Usage
- Detect issues early: If
spegel_advertised_images
suddenly drops to zero, the node might have lost its local images or network connectivity. - Tune performance: Monitor
spegel_resolve_duration_seconds
andhttp_request_duration_seconds
to ensure fast image pulls. - Validate caching efficiency: Look at the
cache=hit
vscache=miss
labels inspegel_mirror_requests_total
. A high hit ratio means your cluster is serving images efficiently.
You can scrape these metrics directly by pointing Prometheus to the k3s embedded registry metrics endpoint (usually exposed on the node’s IP and registry port).
Tip: Consider setting alerts on low
cache=hit
rates or highresolve_duration_seconds
to catch issues automatically.
Conclusion
Setting up the k3s embedded registry mirror is an excellent way to:
- Avoid Docker Hub pull rate limits
- Speed up container pulls inside the cluster
- Make your clusters more resilient in case of external outages
With just a few configuration changes, you can fully leverage the power of peer-to-peer image distribution in k3s.
Happy clustering! 🚀