Bevor man einen Produktions-Cluster anfasst, braucht man einen Ort, an dem Fehler billig sind. Ein lokaler Kubernetes-Cluster auf dem Laptop ist genau das. Man kann Dinge kaputtmachen, löschen und dieselben kubectl-Befehle ausführen, die man später braucht — ohne Rechnungsalarme oder Incident Bridge.
Dieser Beitrag richtet sich an die Phase, in der man von Pods und Deployments gehört hat, vielleicht ein Tutorial gelesen hat und jetzt einen echten Cluster auf der eigenen Maschine laufen lassen möchte. Ich werde nicht so tun, als wären lokale Cluster identisch mit verwalteten Produktionsumgebungen. Das sind sie nicht. Aber sie reichen aus, um Muskelgedächtnis für kubectl, YAML und die grundlegende Objekt-Kette aufzubauen.
Warum zuerst ein lokaler Cluster
Cloud-Kubernetes ist ausgezeichnet, bringt aber an Tag eins Reibung mit sich. Man braucht ein Konto, Netzwerk-Entscheidungen, Node Pools, IAM-Rollen und oft eine Rechnung, bevor kubectl get nodes zum ersten Mal funktioniert. Das ist viel Kontext, bevor man versteht, was ein Pod ist.
Ein lokaler Cluster nimmt den Großteil davon weg. Man installiert ein Tool, erstellt einen Cluster, und kubectl spricht mit ihm auf der eigenen Maschine. Man kann ein Deployment anwenden, Pods hochfahren beobachten, alles löschen und in Minuten von vorn beginnen.
Lokale Cluster sind auch der Ort, an dem ich Befehle gelernt habe, die ich in Produktion noch nutze:
kubectl get nodes
kubectl get pods -A
kubectl describe pod <name>
kubectl logs <name>
kubectl apply -f manifest.yaml
kubectl delete -f manifest.yaml
Die Objekte verhalten sich ähnlich genug, dass das mentale Modell übertragbar ist. Unterschiede zeigen sich später: Storage Classes, Load Balancer, Ingress, Quotas und Node-Kapazität. Das ist in Ordnung. All das braucht man am ersten Nachmittag nicht.
Ein häufiger Irrtum: „Wenn ich auf kind lerne, kann ich nicht mit EKS oder GKE arbeiten.“ Doch, kann man. kubectl und die zentralen API-Objekte sind dieselben. Plattformspezifische Details kommen mit der Plattform, nicht mit dem ersten Cluster.
kind vs minikube: kurzer Vergleich
Zwei beliebte Optionen für lokale Cluster sind kind (Kubernetes IN Docker) und minikube. Beide sind legitim. Keines ist für jede Person die „richtige“ Wahl.
kind führt Kubernetes-Nodes als Docker-Container aus. Es ist leichtgewichtig, schnell zu erstellen und zu zerstören und in CI-Pipelines verbreitet. Wer Docker Desktop oder eine andere Docker-Engine nutzt, findet in kind eine natürliche Ergänzung. Es fühlt sich eher nach „kleinem Cluster in Containern“ an als nach „kleiner VM mit Kubernetes darin“.
minikube kann je nach Treiber als VM, Container oder auf Bare Metal laufen. Es hat eine lange Tutorial-Tradition, eingebaute Addons (z. B. Ingress oder metrics-server) und einen freundlichen minikube start-Ablauf. Manche Teams standardisieren darauf, weil die Dokumentation überall ist.
Mein ehrlicher Rat: eines wählen und ein paar Wochen dabei bleiben. Das Tool täglich zu wechseln erzeugt Rauschen. Ich habe beides genutzt. Für schnelle Experimente und kinds Tempo greife ich oft zu kind. Wer geführte Addons und einen einheitlichen Binary-Workflow möchte, ist mit minikube gut bedient.
Grobe Gegenüberstellung:
| kind | minikube | |
|---|---|---|
| Läuft auf | Docker (typisch) | VM, Docker oder andere Treiber |
| Cluster-Erstellung | Meist schnell | Abhängig vom Treiber |
| Gut für CI | Sehr verbreitet | Möglich |
| Addons | Selbst installieren | Eingebaute Addon-Befehle |
| Cluster löschen | kind delete cluster | minikube delete |
Diese Entscheidung muss man nicht monatelang optimieren. Eines installieren, Cluster erstellen und anfangen zu lernen.
Installationshinweise
Man braucht zwei Dinge: kubectl und ein Cluster-Tool (kind oder minikube). kubectl separat installieren. Das Cluster-Tool ersetzt es nicht.
kubectl — offizielle Installationsdokumentation für das jeweilige OS befolgen. Prüfen:
kubectl version --client
kind — typischerweise über Paketmanager oder Go install. Eine funktionierende Docker-Engine wird ebenfalls benötigt. Prüfen:
docker version
kind version
Cluster erstellen:
kind create cluster --name learning
minikube — minikube-Binary installieren, Treiber wählen (Docker ist auf macOS und Linux üblich). Prüfen:
minikube version
minikube start
Schlägt minikube start fehl, zuerst die Fehlermeldung lesen, bevor man blind sucht. Häufige Ursachen: Docker läuft nicht, zu wenig Speicher, Virtualisierung deaktiviert oder ein altes minikube-Profil kollidiert mit einem neuen Versuch.
Auf Apple-Silicon-Macs funktionieren die meisten modernen Images und Tools auf arm64, aber bei ImagePullBackOff immer die Image-Architektur prüfen. Das ist nicht nur lokal ein Thema — Anfänger treffen es hier aber oft zuerst.
kubectl config und Kontext
kubectl liest Verbindungsdaten aus einer kubeconfig-Datei, meist ~/.kube/config. Mehrere Cluster können in einer Datei stehen. Jeder Cluster-Eintrag ist mit einem Kontext verknüpft, der auch einen User und oft einen Standard-Namespace benennt.
Nach dem Erstellen eines lokalen Clusters prüfen, ob kubectl darauf zeigt:
kubectl config current-context
kubectl config get-contexts
kubectl cluster-info
kubectl get nodes
Bei kind heißt der Kontext oft kind-<cluster-name>, zum Beispiel kind-learning. Bei minikube oft minikube.
Schlagen Befehle mit „connection refused“ oder „Unable to connect to the server“ fehl, liegt es meist an einem dieser Punkte:
- Der Cluster läuft nicht (
docker psfür kind-Nodes oderminikube status). - kubectl zeigt auf den falschen Kontext.
- Die kubeconfig wurde von einem anderen Tool überschrieben.
Kontext explizit wechseln:
kubectl config use-context kind-learning
kind-learning durch den tatsächlichen Kontextnamen aus kubectl config get-contexts ersetzen.
Das klingt banal. Es ist auch die Ursache einer überraschend großen Zahl von „nichts funktioniert“-Threads. Man wendet ein Deployment auf Cluster A an und beobachtet Pods in Cluster B.
Der erste Pod (und warum man schnell weitergehen sollte)
Man kann einen einzelnen Pod für einen schnellen Test erstellen:
apiVersion: v1
kind: Pod
metadata:
name: hello-pod
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
Anwenden:
kubectl apply -f hello-pod.yaml
kubectl get pods
kubectl describe pod hello-pod
Wird der Status Running, funktioniert der Cluster. Bleibt er bei Pending oder ContainerCreating, hilft kubectl describe pod. Unten bei Events nachsehen.
Ein standalone Pod ist aber ein Lernschritt, kein Ziel. Löscht man ihn manuell, bringt nichts ihn zurück. Für alles über ein fünfminütiges Experiment hinaus nutzt man ein Deployment.
Das erste Deployment
Ein Deployment hält die Anwendung am Laufen, auch wenn Pods ersetzt werden:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-web
spec:
replicas: 2
selector:
matchLabels:
app: hello-web
template:
metadata:
labels:
app: hello-web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
Anwenden und prüfen:
kubectl apply -f hello-web.yaml
kubectl get deploy,rs,pods
kubectl describe deployment hello-web
kubectl logs deployment/hello-web
Man sollte ein Deployment, ein ReplicaSet und zwei Pods sehen. Die Pod-Namen wirken zufällig. Das ist normal. Das Deployment besitzt das ReplicaSet, das ReplicaSet die Pods.
Skalieren:
kubectl scale deployment hello-web --replicas=3
kubectl get pods -l app=hello-web
Einen Pod löschen und beobachten, wie er zurückkommt:
kubectl delete pod <pod-name>
kubectl get pods -l app=hello-web
Genau dieses Ersatzverhalten ist der Punkt. Man ändert nichts in der Deployment-Vorlage; der Controller bemerkt den fehlenden Pod und erstellt ihn neu.
Optional mit einem Service im Cluster erreichbar machen (sinnvolle Übung):
apiVersion: v1
kind: Service
metadata:
name: hello-web
spec:
selector:
app: hello-web
ports:
- port: 80
targetPort: 80
kubectl apply -f hello-web-service.yaml
kubectl get svc hello-web
kubectl run curl-test --rm -it --image=curlimages/curl -- curl -s http://hello-web
Liefert curl HTML zurück, funktioniert der Pfad von Pod zu Service im Cluster. Vom Browser auf dem Laptop aus erreichbar ist das ein anderes Thema (port-forward, NodePort, Ingress). Das sollte Tag eins nicht blockieren.
Häufige Fehler am Anfang
Die meiste Anfänger-Schmerzen auf einem lokalen Cluster fallen in wenige Kategorien.
Falscher Kontext. Symptome: leere Namespaces, fehlende Deployments, die man gerade angewendet hat, oder Verbindungsfehler. Lösung: kubectl config current-context und kubectl config use-context ....
Image-Pull-Fehler. Status ImagePullBackOff oder ErrImagePull. Ursachen: Tippfehler im Image-Namen, private Registry ohne Credentials oder falsche CPU-Architektur. Lösung: kubectl describe pod und Events lesen.
Zu wenig Ressourcen. Pods bleiben Pending mit Scheduling-Events zu CPU oder Speicher. Lokale Cluster haben kleine Nodes. Lösung: Requests im Manifest reduzieren oder Docker Desktop / minikube mehr Speicher geben.
Port bereits belegt. Häufig bei minikube tunnel, NodePort-Experimenten oder kubectl port-forward. Lösung: konfliktierenden Prozess stoppen oder anderen Port wählen.
Namespace vergessen. kubectl get pods in default, obwohl man nach -n dev angewendet hat. Lösung: kubectl get pods -A oder Namespace im Kontext setzen.
RBAC und Berechtigungen. Auf lokalen Single-User-Clustern seltener, aber aus dem Internet kopierte Manifeste enthalten manchmal RoleBindings, die scheitern. Lösung: Fehler von kubectl apply lesen und Manifest vereinfachen.
Eine praktische Debug-Reihenfolge:
kubectl config current-context
kubectl get nodes
kubectl get deploy,pods,svc -A
kubectl describe pod <pod-name>
kubectl get events --sort-by='.lastTimestamp'
Von oben nach unten: Cluster erreichbar, Nodes ready, Controller vorhanden, Pods eingeplant, Container laufen.
Aufräumen
Lokale Cluster sammeln Ballast: alte Namespaces, vergessene Deployments, Docker-Volumes und kubeconfig-Einträge. Bewusst aufräumen.
Einzelne Ressourcen löschen:
kubectl delete deployment hello-web
kubectl delete service hello-web
kubectl delete pod hello-pod
Oder über die verwendeten Manifest-Dateien:
kubectl delete -f hello-web.yaml
kubectl delete -f hello-web-service.yaml
Den gesamten Cluster löschen, wenn der Tag vorbei ist oder ein Neustart gewünscht ist.
kind:
kind delete cluster --name learning
minikube:
minikube delete
Stoppt man minikube nur ohne zu löschen, bleiben Ressourcen für das nächste Mal erhalten. Das kann hilfreich oder verwirrend sein — je nach Ziel.
Auch Docker prüfen. kind-Nodes sind Container. Nach dem Löschen eines kind-Clusters prüfen, ob nichts Altes übrig bleibt:
docker ps -a
Ich lösche lokale Cluster öfter, als ich sie behalte. Ein sauberer Cluster nimmt Zweifel an alten Experimenten weg. Wenn sich etwas seltsam verhält und ich es in zwei Minuten nicht erklären kann, erstelle ich den Cluster neu und reproduziere aus einem bekannten Manifest. Das ist kein Scheitern. Das ist günstiges Lernen.
Abschließender Gedanke
Der erste Kubernetes-Cluster muss nicht produktionsförmig sein. Er muss eigen sein, mit kubectl erreichbar und wegwerfbar.
kubectl installieren. kind oder minikube wählen. Kontext prüfen. Deployment anwenden. Kaputtmachen. Events lesen. Löschen. Wiederholen, bis die Befehle langweilig wirken.
Diese Langeweile ist Fortschritt. Wenn kubectl get pods und kubectl describe automatisch laufen, ist man bereit für die nächsten Schichten — Services, Ingress, Storage und irgendwann einen echten Cloud-Cluster mit eigenen Eigenheiten. Der lokale Cluster hat die erste Hürde genommen: nicht die API fürchten, sondern lernen, der API klare Fragen zu stellen.