How to set up a simple registry mirror in Kubernetes
Table of Contents
For the longest time I held off on setting up a container registry mirror because I assumed I would have to set up a potentially maintenance heavy solution like Harbor, Zot or Quay, that also have way more features than I actually need in this specific use case.
If all you need is a mirror however, it is actually really simple to set up a bare minimum low-maintenance registry for this purpose in Kubernetes.
There are a few reasons why having a mirror is a good idea:
- Avoid rate limiting from upstream registries
- Ensure you have access to vital images behind company firewall if anything should happen to the upstream
- Faster pull speeds
In this guide we will be using the mirror functionality of the official registry image.
Deploying the registry to Kubernetes #
Let’s set up our registry step by step.
Deployment #
First of all we need a Deployment, here is a basic example to get started:
| |
- Ideally use a digest to refer to a specific image here. For example, if you wanted to use registry:2.8.3
you could refer to it like this in the deployment:
1docker.io/registry@sha256:319881be2ee9e345d5837d15842a04268de6a139e23be42654fc7664fc6eaf52 - It is good hygiene to always use sane securityContext settings.
- A persistent volume to store registry data in.
- ConfigMap containing the registry configuration.
Also, in a production environment you would probably want to configure this with a proper HA setup
with multiple replicas, probes, anti-affinity and a pod disruption budget.
I have written a blog post on how to do this here
Service #
Nothing fancy, just a standard Service to expose our registry on the cluster network.
If your mirror is purely used inside the same cluster you could use the service hostname to access it
(in this case registry-mirror.<namespace>.svc.cluster.local),
but if not you will need an ingress of some sort to expose it (more on this later).
| |
ConfigMap #
To feed the registry with the configuration to make it a mirror, we use a ConfigMap:
| |
If you want to tweak this (for example if you want to store data in an s3 bucket or set up authentication) you can find the full documentation with all configuration options here.
PersistentVolumeClaim #
If you want to persist the cache that is gradually built up by the registry,
you can use a volume and mount it to /var/lib/registry:
| |
If you are using more than one replica you will need to use ReadWriteMany (RWX) as the access mode.
As mentioned briefly above it is also possible to store this data in an s3 bucket or similar.
Ingress / Route #
How you handle ingress traffic in your cluster depends a lot on your environment,
but here is a basic example on how to use an Ingress:
| |
Wrapping up #
That is all it takes to set up a simple registry mirror that requires minimum effort to maintain,
There are some other cool registry mirroring solutions out there like spegel, but it unfortunately currently only supports containerd as the container runtime and does not work with OpenShift/cri-o which is what I usually work with.
In the next part we will be looking at how to configure nodes in a cluster to use a mirror when pulling images.