Zum Inhalt

Lab 25: Kubernetes Cluster Plumbing – Unter der Haube

Teil 1: Control Plane Anatomie

Übung 1.1 – Static Pods inspizieren

Die Control-Plane-Komponenten laufen als Static Pods – sie werden nicht über die API, sondern direkt vom Kubelet aus Manifest-Dateien gestartet.

# SSH in die Node
minikube ssh

# Hauptbenutzerberechtigungen erhalten (dies müsst ihr in den folgenden Übungen ebenfalls durchführen)
sudo su -

# Static Pod Manifeste finden
ls -la /etc/kubernetes/manifests/

# Inhalt eines Manifests analysieren
sudo cat /etc/kubernetes/manifests/kube-apiserver.yaml

Aufgaben:

  1. Listet alle Static Pod Manifeste auf
  2. Identifiziert im kube-apiserver.yaml:
    • Welcher Port wird verwendet?
    • Wo liegen die TLS-Zertifikate?
    • Welche etcd-Endpoints sind konfiguriert?
  3. Findet heraus, welche Admission Controller aktiviert sind (--enable-admission-plugins) > Ein Admission Controller ist ein Code-Modul im API-Server, das Anfragen nach der Authentifizierung und > Autorisierung abfängt und entweder validiert (ablehnen/durchlassen) oder mutiert > (Felder hinzufügen/ändern), bevor das Objekt in etcd gespeichert wird. Typische Beispiele sind das > automatische Hinzufügen von Default-Limits (LimitRanger), das Erzwingen von ResourceQuotas oder > das Injizieren von ServiceAccount-Tokens in Pods.
  4. Dokumentiert die wichtigsten Startup-Parameter des API-Servers

Reflexion: Was passiert, wenn ihr eine dieser Dateien editiert?


Übung 1.2 – Kubelet-Konfiguration analysieren

Das Kubelet ist der Agent auf jedem Node, der vom API-Server Pod-Spezifikationen empfängt und dafür sorgt, dass die entsprechenden Container über die Container-Runtime gestartet, überwacht und bei Bedarf neu gestartet werden.

Schauen wir ihn uns näher an:

minikube ssh

# Kubelet-Prozess finden
ps aux | grep kubelet

# Kubelet-Konfiguration
cat /var/lib/kubelet/config.yaml

Aufgaben:

  1. Ermittelt:

    • clusterDNS – Welche DNS-Server-IP ist konfiguriert?
    • clusterDomain – Welche Domain wird für Services verwendet?
    • cgroupDriver – Welcher Cgroup-Treiber ist aktiv?
  2. Findet die staticPodPath-Einstellung – woher weiß das Kubelet, wo die Static Pods liegen? > Der cgroupDriver bestimmt, wie Kubernetes Container-Ressourcen (CPU, Memory, I/O) über Linux Control > Groups begrenzt und überwacht – wobei systemd und cgroupfs die zwei Optionen sind, und beide Seiten > (Kubelet und Container-Runtime) denselben Treiber verwenden müssen.

  3. Prüft den Kubelet-Dienst:

sudo systemctl status kubelet
sudo journalctl -u kubelet --no-pager | tail -50

Übung 1.3 – Zertifikate und PKI

In einem Kubernetes-Cluster kommunizieren alle Komponenten verschlüsselt und authentifizieren sich gegenseitig über Zertifikate. Das nennt sich mTLS (mutual TLS): Nicht nur der Client prüft das Server-Zertifikat (wie beim normalen HTTPS), sondern auch der Server verlangt ein gültiges Client-Zertifikat. So weist sich beispielsweise das Kubelet gegenüber dem API-Server aus, und umgekehrt prüft das Kubelet, dass es wirklich mit dem echten API-Server spricht.

Die gesamte Vertrauenskette basiert auf einer Cluster-eigenen Certificate Authority (CA). Diese CA signiert alle Zertifikate im Cluster – für den API-Server, etcd, die Kubelets, und auch für Benutzer wie den minikube-user in eurer kubeconfig. Wer das CA-Zertifikat besitzt und ihm vertraut, akzeptiert automatisch alle davon signierten Zertifikate.

Für Administratoren ist dieses Wissen aus mehreren Gründen kritisch: Zertifikate laufen ab (typischerweise nach 1-3 Jahren) und müssen rechtzeitig erneuert werden, sonst steht der Cluster still. Bei Troubleshooting von Verbindungsproblemen zwischen Komponenten ist oft ein abgelaufenes oder falsch konfiguriertes Zertifikat die Ursache. Und nicht zuletzt ist das Verständnis der PKI essentiell, um zu begreifen, wie RBAC funktioniert – denn der Username und die Gruppenzugehörigkeit eines Benutzers werden direkt aus dem Zertifikat gelesen (CN für den Namen, O für die Gruppe).

Verschafft euch zunächst einen Überblick:

minikube ssh

# Zertifikatsverzeichnis
ls -la /var/lib/minikube/certs/

# Ein Zertifikat inspizieren
openssl x509 -in /var/lib/minikube/certs/apiserver.crt -text -noout | head -30

Aufgaben:

  1. Identifiziert das CA-Zertifikat (Certificate Authority)
  2. Für das API-Server-Zertifikat ermitteln:
    • Subject und Issuer
    • Gültigkeitszeitraum
    • Subject Alternative Names (SANs) – warum sind da mehrere?
  3. Findet das Client-Zertifikat, das kubectl verwendet:
# Außerhalb von minikube ssh:
kubectl config view --raw | grep client-certificate-data
# Base64-dekodieren und analysieren

Diskussion: Was passiert, wenn Zertifikate ablaufen? Wie würdet ihr das überwachen?


Teil 2: etcd – Das Cluster-Gedächtnis

Übung 2.1 – etcd direkt abfragen

etcd ist die verteilte Key-Value-Datenbank, in der Kubernetes den gesamten Cluster-Zustand speichert – jedes Objekt, das ihr per kubectl erstellt, landet letztlich als Eintrag in etcd.

Um etcdctl, das CLI für etcd, zu nutzen, müssen wir es zunächst installieren:

minikube ssh

sudo su -

ETCD_VER=v3.5.9
curl -LO https://github.com/etcd-io/etcd/releases/download/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar xzf etcd-${ETCD_VER}-linux-amd64.tar.gz
sudo mv etcd-${ETCD_VER}-linux-amd64/etcdctl /usr/local/bin/
rm -rf etcd-${ETCD_VER}-linux-amd64*

Wir wollen uns etcd nun näher anschauen mit seinem CLI:

minikube ssh

# etcdctl mit den richtigen Zertifikaten
alias etcdctl='etcdctl --endpoints=https://127.0.0.1:2379 \
  --cacert=/var/lib/minikube/certs/etcd/ca.crt \
  --cert=/var/lib/minikube/certs/etcd/server.crt \
  --key=/var/lib/minikube/certs/etcd/server.key'

# Cluster-Gesundheit prüfen
etcdctl endpoint health
etcdctl endpoint status --write-out=table

# Alle Keys anzeigen (Vorsicht: viel Output!)
etcdctl get / --prefix --keys-only | head -50

Aufgaben:

  1. Prüft die etcd-Cluster-Gesundheit
  2. Wie viele Members hat der etcd-Cluster?
  3. Listet alle Keys auf, die zu Deployments gehören:
etcdctl get /registry/deployments --prefix --keys-only
  1. Lest die Rohdaten eines Secrets aus etcd:
# Erst ein Test-Secret erstellen (außerhalb SSH):
kubectl create secret generic test-secret --from-literal=password=geheim

# In minikube ssh:
etcdctl get /registry/secrets/default/test-secret

⚠️ Sicherheitsdiskussion: Was fällt euch bei den Secret-Daten auf? Warum ist "etcd encryption at rest" wichtig?


Übung 2.2 – etcd Backup und Restore

Backups von etcd sind wichtig, um sich für einen potentiellen Ausfall der Control Plane vorzubereiten. Zum Glück nimmt uns etcdctl einen Teil der Aufgaben ab.

minikube ssh

# Snapshot erstellen
etcdctl snapshot save /tmp/etcd-backup.db

# Snapshot verifizieren
etcdctl snapshot status /tmp/etcd-backup.db --write-out=table

Aufgaben:

  1. Erstellt einen etcd-Snapshot
  2. Notiert die Snapshot-Metadaten (Revision, Total Keys, Size)
  3. Erstellt ein neues Deployment:
# Außerhalb SSH:
kubectl create deployment backup-test --image=nginx --replicas=3
  1. Erstellt einen weiteren Snapshot – was hat sich geändert?
  2. Gedankenexperiment: Skizziert den Restore-Prozess:
    • Was muss gestoppt werden?
    • Wie wird der Snapshot eingespielt?
    • Was passiert mit Ressourcen, die nach dem Backup erstellt wurden?

Teil 3: Container Runtime & Networking

Übung 3.1 – containerd und crictl

Kubernetes nutzt die Container Runtime Interface (CRI). Hier lernt ihr den Umgang mit diesem Low-Level-Tool.

minikube ssh

# Laufende Container anzeigen (nicht Pods!)
sudo crictl ps

# Alle Pods anzeigen
sudo crictl pods

# Container-Details
sudo crictl inspect <container-id>

Aufgaben:

  1. Listet alle laufenden Container auf – wie unterscheidet sich das von kubectl get pods?
  2. Findet die Container, die zum kube-system Namespace gehören
  3. Inspiziert einen Container und findet:
    • Das verwendete Image (mit SHA)
    • Die Prozess-ID (PID) auf dem Host
    • Die Mount-Points
  4. Stoppt einen Container manuell:
sudo crictl stop <container-id>

Was passiert? (Beobachtet mit kubectl get pods -w)

Erkenntnis: Das Kubelet stellt sicher, dass der gewünschte Zustand wiederhergestellt wird.


Übung 3.2 – Pod-Networking und DNS verstehen

Hintergrund: Was ist DNS und warum braucht Kubernetes es?

DNS (Domain Name System) übersetzt Namen in IP-Adressen. Statt sich 142.250.185.78 zu merken, tippt ihr google.com – ein DNS-Server erledigt die Übersetzung.

In Kubernetes ist DNS noch wichtiger: Pods kommen und gehen ständig, ihre IP-Adressen ändern sich. Wenn euer Frontend-Pod mit dem Backend sprechen will, kann er nicht eine feste IP verwenden. Stattdessen fragt er: "Wo finde ich den Service backend?" – und der Cluster-DNS antwortet mit der aktuellen Service-IP.

Kubernetes hat einen eigenen DNS-Server (CoreDNS), der nur innerhalb des Clusters funktioniert und automatisch alle Services und Pods kennt.

Für diese Übung ist es sinnvoll, einen ClusterIP-Service namens backend anzulegen.


Schritt 1: Einen Debug-Pod starten

# Außerhalb der Minikube-VM
kubectl run netdebug --image=nicolaka/netshoot --rm -it -- bash

Dieses Image enthält Netzwerk-Tools wie nslookup, dig, ip und traceroute.


Schritt 2: Die DNS-Konfiguration des Pods ansehen

# Innerhalb des oben gestarteten Pods
cat /etc/resolv.conf

Erwartete Ausgabe:

nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

Was bedeutet das?

Zeile Bedeutung
nameserver 10.96.0.10 Die IP des CoreDNS-Services – hierhin gehen alle DNS-Anfragen
search default.svc.cluster.local ... Suchdomänen, die automatisch angehängt werden (siehe unten)
ndots:5 Wenn ein Name weniger als 5 Punkte hat, werden erst die Suchdomänen probiert

Schritt 3: Die Suchdomänen verstehen

Die search-Zeile ist der Schlüssel zur Kubernetes-DNS-Magie. Wenn ihr nach backend fragt, probiert der Resolver automatisch:

  1. backend.default.svc.cluster.local ← Service "backend" im eigenen Namespace
  2. backend.svc.cluster.local
  3. backend.cluster.local
  4. backend (falls nichts gefunden)

Das bedeutet: Ihr könnt Services im eigenen Namespace einfach beim Namen nennen!

# Diese Anfragen sind alle äquivalent (für einen Service im default Namespace):
nslookup backend
nslookup backend.default
nslookup backend.default.svc
nslookup backend.default.svc.cluster.local

Schritt 4: DNS-Auflösung testen

Cluster-internen Service auflösen:

nslookup kubernetes

Erwartete Ausgabe:

Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   kubernetes.default.svc.cluster.local
Address: 10.96.0.1

Interpretation:

  • Server: 10.96.0.10 – Die Anfrage ging an CoreDNS
  • kubernetes.default.svc.cluster.local – Der vollständige DNS-Name
  • Address: 10.96.0.1 – Die ClusterIP des kubernetes-API-Services

Externe Domain auflösen:

nslookup google.com

CoreDNS leitet externe Anfragen an die DNS-Server des Hosts weiter.


Schritt 5: Service-Discovery in Aktion

Erstellt einen Test-Service (in einem separaten Terminal):

kubectl create deployment webserver --image=nginx
kubectl expose deployment webserver --port=80

Zurück im netdebug-Pod:

# Service per DNS finden
nslookup webserver

# Und direkt ansprechen!
curl http://webserver

Das ist Service-Discovery: Euer Pod weiß nichts über IPs – er fragt DNS und bekommt eine Antwort.


Schritt 6: Namespaces und DNS

Services in anderen Namespaces brauchen den Namespace-Namen:

# CoreDNS läuft im Namespace kube-system
nslookup kube-dns.kube-system

Erwartete Ausgabe:

Name:   kube-dns.kube-system.svc.cluster.local
Address: 10.96.0.10

Merkhilfe für DNS-Namen:

<service>.<namespace>.svc.cluster.local
    │         │       │       │
    │         │       │       └── Cluster-Domain (aus Kubelet-Config)
    │         │       └── Kennzeichnung: ist ein Service
    │         └── Namespace des Services
    └── Service-Name

Schritt 7: Was passiert wenn DNS ausfällt?

Ohne DNS ist euer Cluster praktisch blind – Pods können sich gegenseitig nicht mehr finden.

# In separatem Terminal: CoreDNS stoppen
kubectl scale deployment coredns -n kube-system --replicas=0

# Im netdebug-Pod: DNS-Anfrage hängt
nslookup webserver
# ... wartet ... Timeout nach ~15 Sekunden

# Aber: Direkte IP funktioniert noch!
curl http://10.96.x.x  # (die Service-IP, falls bekannt)

# DNS wiederherstellen
kubectl scale deployment coredns -n kube-system --replicas=2

Zusammenfassung: DNS im Kubernetes-Cluster

Konzept Bedeutung
CoreDNS Der DNS-Server des Clusters (läuft als Pod in kube-system)
ClusterIP des DNS Typischerweise 10.96.0.10 (in jedem Pod als nameserver eingetragen)
Service-Auflösung <service><service>.<namespace>.svc.cluster.local
Suchdomänen Erlauben Kurzformen wie backend statt dem vollen Namen
Externe Anfragen Werden von CoreDNS an Upstream-DNS weitergeleitet

Teil 4: Node-Operationen

Übung 4.1 – Node Drain und Wartung

Vor einem Update eines Nodes muss dieser "evakuiert werden": alle Pods werden gestoppt und vom Scheduler einem neuen Node zugewiesen. Dazu wird der Node zuerst als "nicht schedulbar" markiert und anschließend die Pods gestoppt. Im Folgenden seht ihr die einzelnen Schritte:

# Bei Minikube mit mehreren Nodes:
# minikube node add

# Oder: Simulation mit Cordon/Uncordon auf dem einzigen Node

# Node als nicht-schedulable markieren
kubectl cordon minikube

# Status prüfen
kubectl get nodes

# Pods "evakuieren" (bei Single-Node: werden pending)
kubectl drain minikube --ignore-daemonsets --delete-emptydir-data --force

# Node wieder freigeben
kubectl uncordon minikube

Aufgaben:

Führt die obigen Schritte aus. Beobachtet, was mit den Pods nach dem cordon und nach dem drain passiert.


Teil 5: Incident Simulation

Übung 5.1 – Control Plane Komponente "kaputt machen"

⚠️ Nur in Testumgebungen!

minikube ssh

# API-Server temporär stoppen
sudo mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/

# Was passiert?
# (Außerhalb SSH - wird fehlschlagen!)
kubectl get nodes

Aufgaben:

  1. Stoppt den API-Server durch Entfernen des Manifests
  2. Beobachtet:

    • Was könnt ihr noch mit kubectl machen?
    • Laufen die Workloads weiter?
    • Was zeigt crictl ps?
  3. Stellt den API-Server wieder her

  4. Wiederholt mit dem Scheduler – was passiert mit neuen Pods?

Dokumentiert: Welche Komponente hat welche Auswirkung bei Ausfall?

Komponente Workloads laufen? Neue Pods möglich? kubectl funktioniert?
API-Server
Scheduler
Controller-Manager
etcd

Übung 5.2 – Node-Failure simulieren

# Node "Not Ready" simulieren durch Kubelet-Stop
minikube ssh
sudo systemctl stop kubelet

# Außerhalb beobachten
kubectl get nodes -w

# Nach ~40 Sekunden: Node wird NotReady
# Nach ~5 Minuten: Pods werden evakuiert (auf Multi-Node Cluster)

Aufgaben:

  1. Stoppt das Kubelet und messt:

    • Wann wird der Node NotReady?
    • Wann beginnt die Pod-Evakuierung?
  2. Startet das Kubelet wieder – was passiert?

  3. Findet die zugehörigen Konfigurationsparameter:

    • node-monitor-grace-period (Controller-Manager)
    • pod-eviction-timeout (Controller-Manager)

Zusammenfassung: Admin-Checkliste

Nach diesen Übungen solltet ihr diese Fragen beantworten können:

  • [ ] Wo liegen die Static Pod Manifeste?
  • [ ] Wie greife ich auf etcd zu und erstelle Backups?
  • [ ] Welche Zertifikate nutzt der Cluster und wann laufen sie ab?
  • [ ] Wie debugge ich mit crictl auf Container-Ebene?
  • [ ] Wie funktioniert die DNS-Auflösung im Cluster?
  • [ ] Wie bereite ich einen Node für Wartung vor?
  • [ ] Was passiert bei Ausfall einzelner Control-Plane-Komponenten?

Quick Reference: Wichtige Pfade

Was Pfad
Static Pods /etc/kubernetes/manifests/
Kubelet Config /var/lib/kubelet/config.yaml
Zertifikate /var/lib/minikube/certs/ oder /etc/kubernetes/pki/
etcd Daten /var/lib/etcd/
CNI Config /etc/cni/net.d/
Container Logs /var/log/containers/
Kubelet Logs journalctl -u kubelet

Diese Übungen geben euch das Verständnis, das ihr braucht, um Cluster nicht nur zu nutzen, sondern wirklich zu administrieren.