☸️ Kubernetes Lektion 2/20 ~9 Min. Fortgeschritten

API Server und etcd

Wie der API Server Requests verarbeitet und etcd den Cluster-State speichert.

📝 Meine Notizen

Lernziele

Nach dieser Lektion kannst du den Weg eines API-Requests durch Authentication, Authorization und Admission Control Schritt für Schritt erklären und weißt, warum etcd mit dem Raft-Konsens-Algorithmus eine ungerade Anzahl Nodes braucht. Du kannst den Watch-Mechanismus beschreiben, der Controller und kubelet effizient mit Änderungen versorgt, und du hast ein etcd-Backup einmal selbst erstellt — die wichtigste Disaster-Recovery-Fähigkeit im Cluster-Betrieb.

Das Problem: Ein Cluster braucht eine einzige Wahrheit

In Lektion 1 hast du gesehen: Dutzende Komponenten arbeiten parallel am Cluster — Controller, Scheduler, kubelets auf jedem Node, dazu Menschen mit kubectl und CI-Pipelines. Wenn jeder direkt in einen Datenspeicher schreiben dürfte, hättest du sofort drei Probleme: keine einheitliche Zugriffskontrolle, keine Validierung (jeder Tippfehler landet im State) und Race Conditions, wenn zwei Akteure dasselbe Objekt ändern.

Kubernetes löst das mit einer klaren Rollenteilung: Der API Server ist der einzige Entry Point — die einzige Komponente, die überhaupt mit etcd sprechen darf. Er ist dabei selbst zustandslos: Er prüft, validiert und persistiert, aber er merkt sich nichts. Das macht ihn horizontal skalierbar (mehrere Instanzen hinter einem Load Balancer, dazu mehr in Lektion 5) und macht etcd zur alleinigen Quelle der Wahrheit.

Die Request-Pipeline: drei Wächter vor etcd

Jeder Request — ob kubectl apply, ein Controller-Update oder ein kubelet-Statusreport — durchläuft im API Server dieselbe Pipeline. Die drei Stufen solltest du im Schlaf aufzählen können:

1. Authentication — wer bist du? Der API Server prüft die Identität: Client-Zertifikate (typisch für Cluster-Komponenten), Bearer Tokens (ServiceAccounts), oder OIDC-Tokens von einem Identity Provider wie Keycloak oder Entra ID (typisch für menschliche Nutzer in Unternehmen). Schlägt alles fehl: HTTP 401.

2. Authorization — darfst du das? Meist via RBAC: Roles und ClusterRoles definieren erlaubte Verben (get, list, create, delete) auf Ressourcen, Bindings verknüpfen sie mit Identitäten. Keine passende Regel: HTTP 403. RBAC bekommt später eine eigene Lektion — hier reicht: Authorization ist Stufe 2, nicht Stufe 1.

3. Admission Control — ist das, was du willst, in Ordnung? Erst hier wird der Inhalt des Requests geprüft und gegebenenfalls verändert. Mutating Webhooks dürfen Objekte umschreiben (z. B. injiziert ein Service Mesh hier seine Sidecar-Container), Validating Webhooks dürfen ablehnen (z. B. „kein Image ohne Registry-Whitelist”). Auch eingebaute Mechanismen wie ResourceQuota werden als Admission Controller durchgesetzt. Policy-Tools wie Kyverno oder OPA Gatekeeper docken genau hier an.

Erst nach allen drei Stufen schreibt der API Server das Objekt nach etcd. Diese Pipeline ist der Grund, warum die „eine Tür” so wertvoll ist: Security, Compliance und Defaults lassen sich an einer einzigen Stelle durchsetzen — und im Audit-Log nachvollziehen.

etcd und Raft: warum 3 oder 5, nie 4

etcd ist ein verteilter Key-Value-Store, und „verteilt” wirft sofort die Frage auf: Wenn drei etcd-Nodes laufen und einer eine andere Version der Daten hat — wer hat Recht? Die Antwort liefert der Raft-Konsens-Algorithmus: Die Nodes wählen einen Leader, alle Schreiboperationen laufen über ihn, und ein Schreibvorgang gilt erst als bestätigt, wenn die Mehrheit (Quorum) ihn persistiert hat.

Daraus folgt die wichtigste Betriebsregel: Ein etcd-Cluster mit (n) Mitgliedern toleriert (\lfloor (n-1)/2 \rfloor) Ausfälle. Drei Nodes überstehen einen Ausfall, fünf Nodes zwei. Und deshalb ist eine gerade Anzahl sinnlos: Vier Nodes tolerieren genauso nur einen Ausfall wie drei (Quorum ist 3 von 4) — du bezahlst einen Node mehr für null zusätzliche Ausfallsicherheit, bei mehr Replikations-Overhead. Verliert etcd das Quorum, wird der Cluster read-only: Bestehende Workloads laufen weiter, aber nichts lässt sich mehr ändern.

Zwei Betriebskonsequenzen gehören in jede Interview-Antwort: etcd ist latenzempfindlich (jeder Schreibvorgang wartet auf Quorum-Bestätigung und fsync — schnelle SSDs sind Pflicht, etcd-Nodes über Kontinente zu verteilen ist ein Anti-Pattern). Und etcd-Backups sind die DR-Strategie schlechthin: Ein Snapshot enthält den kompletten Cluster-Zustand.

# Snapshot erstellen (auf einem etcd-Node, Pfade je nach Setup)
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot.db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

Dieser Befehl ist CKA-Prüfungsstoff und gehört in jedes Control-Plane-Runbook.

Der Watch-Mechanismus: warum niemand pollen muss

Wie erfährt der Deployment Controller von einem neuen Deployment? Naive Antwort: Er fragt alle paar Sekunden nach. Bei tausenden Objekten und Dutzenden Controllern würde das den API Server unter Last begraben — und Änderungen kämen trotzdem verzögert an.

Stattdessen bietet der API Server Watches: Ein Client öffnet eine langlebige HTTP-Verbindung („benachrichtige mich über alle Änderungen an Pods ab ResourceVersion X”), und der API Server streamt jedes Add/Update/Delete-Event sofort hinaus. Jedes Objekt trägt eine ResourceVersion; bricht die Verbindung ab, setzt der Client genau dort wieder auf, wo er stand. In der Praxis nutzen Controller dafür Informer aus client-go, die List+Watch kombinieren und einen lokalen Cache pflegen — Lesezugriffe treffen dann den Cache statt den API Server.

Das ist die technische Antwort auf die Frage, wie das entkoppelte Modell aus Lektion 1 effizient sein kann: Der Scheduler watched ungeplante Pods, das kubelet watched „seine” Pods, jeder Controller watched seine Ressourcen — alle reagieren in Millisekunden, ohne sich gegenseitig zu kennen.

Praxis: die Pipeline und den State selbst sehen

kind create cluster --name apilab

# 1. Die API direkt ansprechen — kubectl ist nur ein HTTP-Client
kubectl get --raw /healthz
kubectl get --raw /version

# 2. Authorization testen, ohne etwas zu tun
kubectl auth can-i create deployments
kubectl auth can-i delete nodes --as=system:serviceaccount:default:default

# 3. Einen Watch live erleben (Terminal 1)
kubectl get pods --watch

In einem zweiten Terminal:

# Terminal 2: Pod anlegen — Terminal 1 zeigt die Events sofort
kubectl run watchtest --image=nginx
kubectl delete pod watchtest

Und der Blick in etcd selbst — in kind läuft es als Pod:

kubectl exec -n kube-system etcd-apilab-control-plane -- sh -c \
  'ETCDCTL_API=3 etcdctl \
   --cacert=/etc/kubernetes/pki/etcd/ca.crt \
   --cert=/etc/kubernetes/pki/etcd/server.crt \
   --key=/etc/kubernetes/pki/etcd/server.key \
   get /registry/deployments --prefix --keys-only'

Du siehst: Jedes Kubernetes-Objekt ist ein Key unter /registry/.... Danach kind delete cluster --name apilab.

Typische Stolperfallen

401 und 403 verwechseln: 401 heißt „Identität unklar” (Authentication), 403 heißt „Identität klar, aber keine Berechtigung” (Authorization). Wer beim Troubleshooting bei 403 am Zertifikat schraubt, sucht in der falschen Pipeline-Stufe.

Admission Webhooks als Single Point of Failure: Ein Validating Webhook mit failurePolicy: Fail, dessen Backend down ist, blockiert alle betroffenen API-Operationen — ein klassischer selbstgebauter Cluster-Ausfall. Die Wahl zwischen Fail (sicher, aber riskant für Verfügbarkeit) und Ignore (verfügbar, aber Policy-Lücke) ist ein echter Trade-off, kein Detail.

etcd-Backup vergessen, weil „managed”: Bei EKS/GKE/AKS übernimmt der Provider etcd — bei kubeadm-Clustern bist du es. Wer self-hosted betreibt und keinen getesteten Restore-Prozess hat, hat kein Backup, sondern eine Hoffnung.

Quorum-Verlust falsch deuten: Wenn 2 von 3 etcd-Nodes weg sind, ist der Cluster nicht „kaputt”, sondern read-only. Workloads laufen weiter. Die richtige Reaktion ist Quorum wiederherstellen, nicht panisch Nodes neu aufsetzen.

Interview-Vorbereitung

Die Standardfrage „Wie verarbeitet der API Server einen Request?” beantwortest du als Pipeline: Authentication (wer? — Zertifikate, Tokens, OIDC) → Authorization (darf? — RBAC) → Admission (Inhalt okay? — mutating, dann validating) → Persistierung in etcd. Dann ein Satz zur Architektur: API Server zustandslos und skalierbar, etcd als einzige Quelle der Wahrheit, Watch-Mechanismus für effiziente Verteilung von Änderungen.

Typische Follow-ups:

  • „Warum 3 oder 5 etcd-Nodes, nie 4?” — Raft braucht Mehrheit; 4 Nodes tolerieren wie 3 nur einen Ausfall, kosten aber mehr.
  • „Was passiert bei etcd-Quorum-Verlust?” — Cluster wird read-only; laufende Pods unbeeinflusst, keine Änderungen mehr möglich.
  • „Wozu Mutating vs. Validating Webhooks?” — Mutating verändert Objekte (Sidecar-Injection, Defaults), Validating lehnt ab (Policies); Mutating läuft zuerst.
  • „Wie bekommen Controller Änderungen mit, ohne zu pollen?” — Watch-Verbindungen mit ResourceVersion, in der Praxis über Informer mit lokalem Cache.

Zusammenfassung

Der API Server ist die eine Tür zum Cluster: zustandslos, horizontal skalierbar, mit der dreistufigen Pipeline aus Authentication, Authorization und Admission Control vor jedem Schreibzugriff. Dahinter hütet etcd als Raft-basierter Key-Value-Store den gesamten Cluster-Zustand — mit Quorum-Arithmetik (3 oder 5 Nodes), Latenz-Sensibilität und dem Snapshot-Backup als wichtigster DR-Maßnahme. Der Watch-Mechanismus verteilt Änderungen in Echtzeit an alle Controller und kubelets, ohne Polling.

Damit kennst du Speicher und Eingangstür des Clusters. In der nächsten Lektion schauen wir uns an, wer auf dieser Basis die eigentlichen Entscheidungen trifft: der Scheduler mit seinem Filtering-Scoring-Binding-Zyklus und der Controller Manager mit seinen Control Loops.