How To Setup A Private Docker Registry On K3s
It is not always appropriate to push ones own container images to a public registry. This post shows a quick way to create a private image registry inside a K3s Kubernetes cluster.
Please note, that with the following manifest, when the registry resources are being removed from the cluster, all images will be removed as well. There is a TODO in the very last line that addresses this.
Also important to note: The registry is unsecured. Further steps have to be taken to secure it with methods like username/password or certificates which is not scope of this tutorial.
Kubernetes Resources #
Before this manifest gets applied, the domain name under spec:rules:host
needs to be changed accordingly.
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: docker-registry-ingress
annotations:
kubernetes.io/ingress.class: "traefik"
spec:
rules:
- host: registry.domain.de
http:
paths:
- path: /
backend:
serviceName: docker-registry-service
servicePort: 5000
---
apiVersion: v1
kind: Service
metadata:
name: docker-registry-service
labels:
run: docker-registry
spec:
selector:
app: docker-registry
ports:
- protocol: TCP
port: 5000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: docker-registry
labels:
app: docker-registry
spec:
replicas: 1
selector:
matchLabels:
app: docker-registry
template:
metadata:
labels:
app: docker-registry
spec:
containers:
- name: docker-registry
image: registry
ports:
- containerPort: 5000
protocol: TCP
volumeMounts:
- name: storage
mountPath: /var/lib/registry
env:
- name: REGISTRY_HTTP_ADDR
value: :5000
- name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY
value: /var/lib/registry
volumes:
- name: storage
emptyDir: {} # TODO -make this more permanent later
The manifest gets applied with:
kubectl apply -f registry.yaml
Settings #
On the K3s nodes, the file /etc/rancher/k3s/registries.yaml
needs to be created with the following content. The domain name needs to match the one from above manifest.
mirrors:
"registry.domain.de":
endpoint:
- "http://registry.domain.de"
I did this on server and agent nodes. I am not sure if it really has to be done on the agents, I just did.
After that, server and agents need to be restarted.
On the server execute:
systemctl restart k3s
And on the agent node:
systemctl restart k3s-agent
If the changes applied can be checked with:
crictl info
There is a section called registry
that should list the newly created private registry.
The local workstation also needs to know about the new registry. I am working on macOS with Docker Desktop. Under “Preferences -> Docker Engine”, the settings had to be extended with the following entry:
{
...
"insecure-registries": [
"registry.domain.de"
]
}
Test the Registry #
In order to test if an image can be pushed to the new registry, I have built a small image just containing Nginx with a custom HTML-file:
<html>
<head><title>Hello World!</title>
<style>
html {
font-size: 500.0%;
}
div {
text-align: center;
}
</style>
</head>
<body>
<div>Hello World!</div>
</body>
</html>
The Dockerfile for the new image:
FROM nginx:alpine
COPY index.html /usr/share/nginx/html
Build and tag the new image according to your registry domain:
docker build -t registry.domain.de/hello:latest .
Finally the image can be pushed.
docker push registry.domain.de/hello:latest
Hopefully that worked without any issues.
For an additional test, the image can also be removed from the local workstation and then be pulled again from the private registry.
docker rmi registry.domain.de/hello:latest
docker pull registry.domain.de/hello:latest