Es ist nicht immer angebracht, eigene Container-Images in eine öffentliche Registry zu pushen. Dieser Beitrag zeigt einen schnellen Weg, eine private Image-Registry innerhalb eines K3s Kubernetes-Clusters zu erstellen.

Bitte beachte, dass mit dem folgenden Manifest, wenn die Registry-Ressourcen aus dem Cluster entfernt werden, alle Images ebenfalls entfernt werden. Es gibt ein TODO in der allerletzten Zeile, das dies adressiert.

Auch wichtig: Die Registry ist ungesichert. Weitere Schritte (zum Beispiel Benutzername/Passwort oder Zertifikate) sind erforderlich, um sie zu sichern; das liegt außerhalb des Umfangs dieses Tutorials.

Kubernetes-Ressourcen

Bevor dieses Manifest angewendet wird, muss der Domainname unter spec:rules:host entsprechend geändert werden.

---
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

Wende das Manifest an mit:

kubectl apply -f registry.yaml

Einstellungen

Auf den K3s-Nodes erstelle die Datei /etc/rancher/k3s/registries.yaml mit folgendem Inhalt. Der Domainname muss mit dem im Manifest oben übereinstimmen.

mirrors:
 "registry.domain.de":
 endpoint:
  - "http://registry.domain.de"

Ich habe das sowohl auf den Server- als auch auf den Agent-Nodes gemacht. Ich bin nicht sicher, ob es auf den Agents gemacht werden muss, aber ich habe es dort gemacht.

Danach starte Server und Agents neu.

Auf dem Server führe aus:

systemctl restart k3s

Auf dem Agent-Node führe aus:

systemctl restart k3s-agent

Du kannst überprüfen, ob die Änderungen angewendet wurden mit:

crictl info

Es gibt einen Abschnitt namens registry, der die neu erstellte private Registry auflisten sollte.

Die lokale Workstation muss auch von der neuen Registry wissen. Ich benutze macOS mit Docker Desktop. Unter “Preferences Docker Engine” erweitere die Einstellungen mit folgendem Eintrag:

{
...

 "insecure-registries": [
 "registry.domain.de"
 ]
}

Die Registry testen

Um das Pushen eines Images in die neue Registry zu testen, habe ich ein kleines Image gebaut, das Nginx mit einer benutzerdefinierten HTML-Datei enthält:

<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>

Das Dockerfile für das Image:

FROM nginx:alpine
COPY index.html /usr/share/nginx/html

Baue und tagge das Image entsprechend deiner Registry-Domain:

docker build -t registry.domain.de/hello:latest.

Pushe das Image:

docker push registry.domain.de/hello:latest

Wenn das funktioniert hat, kannst du weiter testen, indem du das Image lokal entfernst und es erneut aus der privaten Registry pullst:

docker rmi registry.domain.de/hello:latest
docker pull registry.domain.de/hello:latest

Ressourcen