Kubernetes Grundlagen und Cluster Aufbau
Dieser Artikel erklärt, warum der Schritt von Docker Compose zu Kubernetes notwendig wird, wie ein Kubernetes-Cluster aufgebaut ist, und baut anschließend einen eigenen Cluster mit k3s auf vier virtuellen Maschinen auf: einem Server-Node, zwei Agent-Nodes und einem separaten Client.
Warum reicht Docker Compose nicht mehr
Mit Docker Compose lässt sich eine Anwendung aus mehreren Containern zuverlässig auf einem Host beschreiben und starten. Für Entwicklung und kleine Tests ist das ausreichend. Sobald eine Anwendung produktiv läuft, tauchen aber Fragen auf, die Compose grundsätzlich nicht beantworten kann.
- Was passiert bei einem Host-Ausfall
- Fällt der Host aus, auf dem Compose läuft, ist die gesamte Anwendung nicht mehr erreichbar. Es gibt keinen zweiten Host, auf den automatisch ausgewichen wird.
- Wie wird über mehrere Maschinen skaliert
docker compose up --scale web=3startet drei Instanzen – aber immer auf demselben Host. Reicht dessen CPU oder RAM nicht mehr aus, gibt es keinen Mechanismus, der auf eine zweite Maschine ausweicht.
- Was passiert, wenn ein Container abstürzt
- Compose kann einen abgestürzten Container auf demselben Host neu starten (
restart: always). Es gibt aber keine Instanz, die aktiv überwacht, ob genügend Kapazität für einen Neustart überhaupt noch vorhanden ist.
- Wie läuft ein Update ohne Downtime
- Ein
docker compose up -dnach einem Image-Wechsel ersetzt Container in der Regel abrupt. Ein kontrolliertes, schrittweises Update über mehrere Instanzen hinweg, bei dem immer genügend laufende Instanzen übrig bleiben, ist mit Compose nicht vorgesehen.
Der eigentliche Sprung ist konzeptioneller Natur: Bei Compose startet man Container. Bei Kubernetes beschreibt man einen gewünschten Zielzustand ("es sollen drei Instanzen dieser Anwendung laufen") – und ein fortlaufend aktiver Kontrollmechanismus sorgt dafür, dass dieser Zustand über beliebig viele Maschinen hinweg eingehalten wird, auch wenn einzelne Maschinen ausfallen.
Dieses Prinzip nennt sich Self-Healing: Stirbt eine Instanz, wird sie automatisch neu gestartet – bei Bedarf auf einer anderen Maschine. Genau dieses Verhalten wird am Ende dieses Artikels in einer Übung selbst provoziert und beobachtet.
Ziel dieses Kurses
Am Ende versteht ihr, warum eine Compose-Anwendung bei Skalierung und Ausfallsicherheit an ihre Grenzen stößt, und könnt dieselbe Anwendung so beschreiben, dass ein Cluster sie selbstständig am Laufen hält – auch wenn Nodes ausfallen, Images wechseln oder die Last steigt. Es geht nicht darum, jeden Kubernetes-Befehl auswendig zu können, sondern zu verstehen, was im Cluster passiert, wenn ein Pod stirbt, ein neues Image ausgerollt wird oder Traffic hereinkommt.
Architektur eines Kubernetes-Clusters
Ein Kubernetes-Cluster besteht aus zwei Arten von Maschinen (Nodes) mit unterschiedlichen Aufgaben.
- Control Plane (Server-Node)
- Trifft alle Entscheidungen: Wo soll ein Container laufen, ist der gewünschte Zustand noch erfüllt, was passiert bei einem Ausfall. Der Server-Node führt selbst normalerweise keine Anwendungs-Container aus.
- Worker-Nodes (Agent-Nodes)
- Hier laufen die eigentlichen Container. Ein Agent meldet sich beim Server-Node an, bekommt Arbeit zugewiesen und führt sie aus.
- Der Client
kubectlist das Kommandozeilenwerkzeug, mit dem der Cluster gesteuert wird. Es läuft bewusst nicht auf einem der Cluster-Nodes, sondern auf einem separaten Rechner (oder dem eigenen Laptop), der über das Netzwerk mit dem Server-Node spricht. Das ist ein wichtiger Unterschied zu einer Gewohnheit aus der Docker-Welt: Bei Docker meldet man sich häufig direkt auf dem Host an, umdocker-Befehle auszuführen. Bei Kubernetes steuert man den Cluster von außen.
In diesem Kurs werden vier Maschinen aufgesetzt:
| Maschine | Rolle | Beschreibung |
|---|---|---|
| k8s-server | Control Plane | Server-Node, hier läuft k3s im Server-Modus |
| k8s-agent-1 | Worker | Erster Agent-Node |
| k8s-agent-2 | Worker | Zweiter Agent-Node |
| k8s-client | Client | Kein Cluster-Node, nur kubectl und die Kubeconfig
|
k3s als Kubernetes-Distribution
Für den Cluster wird k3s verwendet, eine schlanke, aber vollständig zu Kubernetes kompatible Distribution.
- Ein einziges Binary
- Statt vieler einzelner Komponenten (
kube-apiserver,kube-scheduler,kube-controller-manager,etcd…) steckt bei k3s alles in einem Go-Binary.
- SQLite statt etcd
- Als Standard-Datenspeicher nutzt k3s SQLite statt des ressourcenhungrigen etcd. Für ein Lab-Setup völlig ausreichend.
- Geringer Ressourcenbedarf
- k3s läuft mit deutlich weniger RAM pro Node als ein klassischer Kubeadm-Aufbau – ideal für VirtualBox-VMs mit begrenzten Ressourcen.
- Vollständig kompatible API
- Alle
kubectl-Befehle, Manifeste und Konzepte funktionieren bei k3s exakt so wie bei jedem anderen Kubernetes-Cluster. Was in diesem Kurs gelernt wird, gilt uneingeschränkt auch für größere Cluster.
Vorbereitung der virtuellen Maschinen
- Empfohlene VM-Ausstattung
- 1 vCPU, 2 GB RAM, 10 GB Festplatte je Node reichen für dieses Lab aus.
- Basis-Image
- Ein minimales Debian oder Rocky Linux als Grundlage. Empfehlenswert: eine VM einmal vorbereiten (Betriebssystem installieren,
curlundopen-vm-tools/Gastadditionen einrichten) und anschließend dreimal klonen.
- Netzwerk-Konfiguration in VirtualBox
- Für die Kommunikation der Nodes untereinander wird ein Internal Network oder Host-only Adapter verwendet. Zusätzlich braucht jede VM einen zweiten Adapter im NAT-Modus, damit Pakete und Container-Images aus dem Internet geladen werden können.
- Feste IP-Adressen vergeben
- Damit sich die Nodes zuverlässig finden, sollten feste IP-Adressen im internen Netz vergeben werden, zum Beispiel
192.168.56.10(Server),192.168.56.11und192.168.56.12(Agents),192.168.56.20(Client).
Installation des Server-Node
Auf der Maschine k8s-server:
- k3s im Server-Modus installieren
curl -sfL https://get.k3s.io | sh -
- Installation prüfen
sudo k3s kubectl get nodes
- Join-Token auslesen
- Das Token wird für den Beitritt der Agent-Nodes benötigt.
sudo cat /var/lib/rancher/k3s/server/node-token
Installation der Agent-Nodes
Auf jeder der beiden Maschinen k8s-agent-1 und k8s-agent-2:
- k3s im Agent-Modus installieren und dem Cluster beitreten
<SERVER_IP>durch die IP-Adresse vonk8s-serverersetzen,<NODE_TOKEN>durch das zuvor ausgelesene Token.curl -sfL https://get.k3s.io | K3S_URL=https://<SERVER_IP>:6443 K3S_TOKEN=<NODE_TOKEN> sh -
- Beitritt vom Server aus prüfen
- Nach kurzer Zeit sollten auf
k8s-serverbeide Agents alsReadyerscheinen. sudo k3s kubectl get nodes
kubectl auf dem Client einrichten
Auf der Maschine k8s-client, die nicht Teil des Clusters ist:
- kubectl installieren
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
- Kubeconfig vom Server-Node holen
- Die Datei enthält die Zugangsdaten für den Cluster. Sie wird vom Server-Node kopiert und angepasst.
scp k8s-server:/etc/rancher/k3s/k3s.yaml ~/.kube/config
- Server-Adresse in der Kubeconfig anpassen
- Die kopierte Datei verweist standardmäßig auf
127.0.0.1. Das muss auf die tatsächliche IP-Adresse vonk8s-servergeändert werden. - In
~/.kube/configdie Zeileserver: https://127.0.0.1:6443aufserver: https://<SERVER_IP>:6443ändern.
- Verbindung testen
kubectl get nodes- Es sollten alle drei Nodes (Server und beide Agents) mit Status
Readyerscheinen.
Übung: Cluster verifizieren
- Meldet euch auf
k8s-clientan und prüft mitkubectl get nodes -o wide, welche interne IP-Adresse jeder Node hat. - Ermittelt mit
kubectl cluster-info, unter welcher Adresse die Control Plane erreichbar ist. - Prüft mit
kubectl get pods -A, welche System-Pods bereits ohne euer Zutun im Cluster laufen (unter anderem CoreDNS und Traefik). Notiert euch, in welcher Namespace diese laufen. - Führt
kubectl describe node k8s-agent-1aus und sucht im AbschnittAllocatablenach der verfügbaren CPU- und Speicherkapazität dieses Nodes.
Übung: Self-Healing beobachten
Diese Übung provoziert bewusst den zentralen Unterschied zu Docker Compose: Ein Pod stirbt, und der Cluster reagiert von selbst.
- Startet eine einfache Test-Anwendung:
kubectl create deployment webtest --image=nginx:1.25 --replicas=1 - Prüft mit
kubectl get pods -o wide, auf welchem Agent-Node der Pod gelandet ist. - Löscht den Pod gezielt (nicht das Deployment):
kubectl delete pod <pod-name> - Prüft sofort danach erneut mit
kubectl get pods -o wideund beobachtet: Ein neuer Pod ist automatisch entstanden – möglicherweise sogar auf dem anderen Agent-Node. - Überlegt gemeinsam: Was genau hat gemerkt, dass ein Pod fehlt, und wer hat entschieden, ihn neu zu starten? (Antwort wird im weiteren Kursverlauf beim Thema Deployments und Controller vertieft.)
- Räumt zum Abschluss auf:
kubectl delete deployment webtest
Übung: Grenzen von Compose selbst erleben
- Simuliert einen Node-Ausfall, indem ihr
k8s-agent-1in VirtualBox herunterfahrt, während dort Pods laufen. - Beobachtet mit
kubectl get nodes, wie lange es dauert, bis der Node alsNotReadymarkiert wird. - Beobachtet mit
kubectl get pods -o wide, was mit den Pods passiert, die vorher aufk8s-agent-1liefen. - Startet
k8s-agent-1wieder und prüft, ob der Node wieder automatisch dem Cluster beitritt.