Kubernetes Grundlagen und Cluster Aufbau

Aus Xinux Wiki
Zur Navigation springen Zur Suche springen

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=3 startet 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 -d nach 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
  • kubectl ist 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, um docker-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, curl und open-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.11 und 192.168.56.12 (Agents), 192.168.56.20 (Client).

Installation des Server-Node

Auf der Maschine k8s-server:

k3s im Server-Modus installieren
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 von k8s-server ersetzen, <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-server beide Agents als Ready erscheinen.
  • sudo k3s kubectl get nodes

kubectl auf dem Client einrichten

Auf der Maschine k8s-client, die nicht Teil des Clusters ist:

kubectl installieren
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 von k8s-server geändert werden.
  • In ~/.kube/config die Zeile server: https://127.0.0.1:6443 auf server: https://<SERVER_IP>:6443 ändern.
Verbindung testen
  • kubectl get nodes
  • Es sollten alle drei Nodes (Server und beide Agents) mit Status Ready erscheinen.

Übung: Cluster verifizieren

  1. Meldet euch auf k8s-client an und prüft mit kubectl get nodes -o wide, welche interne IP-Adresse jeder Node hat.
  2. Ermittelt mit kubectl cluster-info, unter welcher Adresse die Control Plane erreichbar ist.
  3. 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.
  4. Führt kubectl describe node k8s-agent-1 aus und sucht im Abschnitt Allocatable nach 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.

  1. Startet eine einfache Test-Anwendung: kubectl create deployment webtest --image=nginx:1.25 --replicas=1
  2. Prüft mit kubectl get pods -o wide, auf welchem Agent-Node der Pod gelandet ist.
  3. Löscht den Pod gezielt (nicht das Deployment): kubectl delete pod <pod-name>
  4. Prüft sofort danach erneut mit kubectl get pods -o wide und beobachtet: Ein neuer Pod ist automatisch entstanden – möglicherweise sogar auf dem anderen Agent-Node.
  5. Ü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.)
  6. Räumt zum Abschluss auf: kubectl delete deployment webtest

Übung: Grenzen von Compose selbst erleben

  1. Simuliert einen Node-Ausfall, indem ihr k8s-agent-1 in VirtualBox herunterfahrt, während dort Pods laufen.
  2. Beobachtet mit kubectl get nodes, wie lange es dauert, bis der Node als NotReady markiert wird.
  3. Beobachtet mit kubectl get pods -o wide, was mit den Pods passiert, die vorher auf k8s-agent-1 liefen.
  4. Startet k8s-agent-1 wieder und prüft, ob der Node wieder automatisch dem Cluster beitritt.