Ich bin ein Pod. Wahrscheinlich hast du meinen Namen schon in einem Terminal gesehen — so etwas wie checkout-api-7f4b9c8d6-xk2lm — und dich gefragt, warum er aussieht wie ein Passwort, das jemand auf der Tastatur verloren hat.
Berechtigte Frage.
Bevor es mich gab, existierte nur eine stabile Anwendung: Code, der zuverlässig als Container-Image in einer Registry lief. Jemand hat ihn gebaut, getaggt und gepusht. Das Image bin nicht ich. Es ist mein Bauplan. Ich bin das, was passiert, wenn Kubernetes beschließt, diesen Bauplan zu einem bestimmten Zeitpunkt auf einem bestimmten Node auszuführen.
Dieser Beitrag ist meine Version der Geschichte: wie ich entstehe, wer meine Ansprechpartner sind, wie Traffic zu mir kommt — und warum ich verschwinde, ohne dass das Drama sein muss.
Bevor ich existiere: die App kommt als gewünschter Zustand
In Kubernetes beginnt nichts mit „starte diesen Container auf genau dieser Maschine“. Es beginnt mit einer Beschreibung.
Ein Platform Engineer, ein Entwickler oder eine GitOps-Pipeline reicht ein Deployment ein — meist YAML, manchmal Helm, manchmal ein Klick in OpenShift, der am Ende trotzdem YAML wird. Das Deployment sagt unter anderem:
- Starte drei Kopien dieser App.
- Nutze Image
registry.example.com/checkout-api:2.4.1. - Jede Kopie lauscht auf Port 8080.
- Hänge Konfiguration aus dieser ConfigMap ein.
- Injiziere Zugangsdaten aus diesem Secret.
- Label mich so, dass der Service mich findet.
Das Manifest geht an den API-Server, die Eingangstür des Clusters. Der API-Server validiert es, speichert es in etcd und meldet Erfolg. Zu diesem Zeitpunkt ist noch kein Container gestartet. Der Cluster hat nur einen gewünschten Zustand festgehalten.
Diese Unterscheidung finde ich beruhigend. Geburt ist nicht augenblicklich. Geburt ist eine Kette von Entscheidungen.
Meine Vorgesetzten: Deployment und ReplicaSet
Ich berichte nicht direkt an Menschen. Ich berichte an Controller.
Der Deployment-Controller liest das Deployment und erstellt oder aktualisiert ein ReplicaSet. Dessen Aufgabe ist schlicht und nützlich: Halte genau N Pods am Leben, die zu einer Vorlage passen. Fällt einer von uns aus, entsteht ein neuer. Ändert sich die Vorlage, steuert er den Übergang.
Der ReplicaSet-Controller erstellt dann mein Pod-Objekt — noch immer nur Daten in der API, noch kein laufender Prozess. Mein Name bekommt ein zufälliges Suffix. Das ist Absicht. Ich bin kein Haustier mit dauerhaftem Namensschild. Ich bin Vieh mit Dienstplan.
Wenn du debuggst, warum kein Pod da ist, schau die Kette an:
kubectl get deployment,rs,pods -n <namespace> -l app=checkout-api
kubectl describe deployment checkout-api -n <namespace>
Das Deployment sieht gut aus, aber ich erscheine nicht? Oft endet die Spur beim ReplicaSet oder bei Admission-Richtlinien.
Ein Zuhause finden: Scheduler und Node
Mein Pod-Objekt existiert, aber ich habe noch keinen Node. Ich bin Pending.
Der Scheduler beobachtet nicht zugewiesene Pods. Er liest meine Resource Requests, Tolerations, Affinity-Regeln und den Zustand aller Nodes. Er wählt einen Node, der mich aufnehmen kann — genug CPU und RAM, passende Labels, keine blockierenden Taints, erfüllte Volume-Bedingungen.
Wenn er entschieden hat, schreibt er meine Node-Zuweisung zurück in die API. Jetzt ist das Kubelet auf diesem Node für mich verantwortlich.
Der Scheduler ist für mich die Flugleitung, die ein Gate zuweist. Das Kubelet ist das Bodenpersonal, das die Jetbridge wirklich anschließt.
Aufwachen: Image ziehen, Mounts, erster Atemzug
Das Kubelet auf meinem Node sieht, dass ich existieren soll. Seine Aufgabe: Ist-Zustand an Spec angleichen.
Typische Abfolge:
- Container-Image aus der Registry ziehen (falls nicht schon auf dem Node gecacht).
- Meinen Netzwerk-Namespace anlegen und mich ans Cluster-Netzwerk (CNI) hängen.
- ConfigMaps und Secrets als Dateien oder Umgebungsvariablen einbinden.
- PersistentVolumeClaims anbinden, wenn ich dauerhaften Speicher brauche.
- Meinen Container mit konfiguriertem Command, Args und Security Context starten.
Meine ConfigMap ist der Briefing-Ordner: Feature Flags, Log-Level, öffentliche URLs. Mein Secret ist die verschlossene Schublade: Datenbankpasswörter, API-Tokens, TLS-Schlüssel. Fehlt ein Secret oder stimmt ein Mount-Pfad nicht, erreiche ich vielleicht nie Running. Das Kubelet versucht es erneut; Events an meinem Pod-Objekt erzählen Menschen die Geschichte.
kubectl describe pod <pod-name> -n <namespace>
kubectl get events -n <namespace> --field-selector involvedObject.name=<pod-name>
Wenn mein Hauptprozess startet, lebe ich im Linux-Sinn. Kubernetes hält mich trotzdem noch für NotReady. Diese Lücke ist wichtig.
Mein Adressbuch: Labels, Service und DNS
Im Cluster wählt niemand meine Pod-IP aus dem Kopf. Pod-IPs ändern sich bei Ersetzung. Man ruft einen Service an.
Der Service wählt Pods über Labels — Schlüssel/Wert-Paare, die die ReplicaSet-Vorlage bei meiner Entstehung gesetzt hat, etwa app=checkout-api. Der Service bekommt eine stabile ClusterIP und einen DNS-Namen:
checkout-api.<namespace>.svc.cluster.local
Löst ein anderer Pod diesen Namen auf, antwortet CoreDNS mit der Service-IP. kube-proxy (oder ein CNI mit gleicher Wirkung) leitet Traffic an einen von uns weiter — meist an einen Pod, der die Readiness-Probe bestanden hat.
Mein soziales Netz für eingehenden Traffic:
| Ansprechpartner | Rolle für mich |
|---|---|
| Service | Feste Telefonnummer; verteilt an bereite Pods wie mich |
| CoreDNS | Telefonbuch; macht aus Namen Service-Adressen |
| Andere Pods | Clients, Backends, Sidecars im selben Pod |
| Ingress / Route | Optionale Außentür von außerhalb des Clusters |
Ausgehend nutze ich dasselbe DNS. Ein Kurzname wie postgres funktioniert, weil das Kubelet Search Domains in meiner /etc/resolv.conf gesetzt hat. Diese Bequemlichkeit verbirgt auch Namespace-Fehler — relevant, wenn eine Verbindung „in Staging klappt, in Production nicht“.
Die Gesundheitschecks: wann ich arbeiten darf
Nicht jeder laufende Pod bekommt sofort Traffic.
Die Readiness-Probe fragt: „Ist diese Instanz bereit für ihren Job?“ Vielleicht wärmt meine JVM noch auf. Vielleicht brauche ich beim ersten Start Migrationen. Bis Readiness erfolgreich ist, überspringt mich der Service. Ich kann Running sein und für Kunden unsichtbar — besser als Traffic an einen halb gestarteten Prozess.
Die Liveness-Probe stellt eine härtere Frage: „Ist diese Instanz nicht mehr zu retten?“ Hänge ich in einem Deadlock oder hängt mein Prozess, tötet das Kubelet meinen Container und startet mich gemäß restartPolicy neu. Readiness schützt andere vor mir. Liveness schützt den Cluster vor einem feststeckenden mir.
Was das Kubelet sieht:
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.status.conditions}'
kubectl logs <pod-name> -n <namespace> --previous
Ein Arbeitstag: Logs, Metriken und exec
Sobald ich Ready bin, kommen Anfragen auf meinen Container-Port. Die Anwendung in mir bearbeitet HTTP, gRPC, Queue-Nachrichten — was auch immer sie kann. Kubernetes versteht meine Fachlogik nicht. Es versteht Container, Probes und Resource Limits.
Logs gehen nach stdout/stderr. Das Kubelet sammelt sie; eure Plattform leitet sie an Loki, Elasticsearch oder CloudWatch weiter. Wenn Menschen kubectl logs ausführen, lesen sie mein Tagebuch — kein SSH auf ein VM-Dateisystem.
Metriken kommen vielleicht von einem /metrics-Endpoint, den Prometheus scraped, oder von einem Sidecar im selben Pod. Wir teilen einen Netzwerk-Namespace — localhost zwischen Containern ist echt.
kubectl exec ist ein Mensch, der zu Debugging-Zwecken in meinen Container springt. Im Incident nützlich; kein Alltags-Betriebsmodell. Wenn Production jede Woche exec braucht, fehlt vermutlich etwas in Config, Probes oder Deployment-Vorlage.
Meine Resource Requests und Limits sind der Treibstoffplan für Scheduling und die Decke, die das Kubelet durchsetzt. Out-of-Memory-Kills sind abrupt. CPU-Drosselung ist langsamer und tückischer. Ich spüre beides, auch wenn die App darin das als mysteriöse Latenz meldet.
Wer sonst noch weiß, dass es mich gibt?
Neben meinen direkten Vorgesetzten beobachten oder beeinflussen mich weitere Cluster-Komponenten:
- API-Server — Quelle der Wahrheit; jeder Controller liest und schreibt hier.
- etcd — wo gewünschter und beobachteter Zustand dauerhaft liegt.
- Admission Controller / Webhooks — können meine Spec mutieren oder ablehnen, bevor ich entstehe.
- ServiceAccount — meine Identität, wenn ich von innen die Kubernetes-API aufrufe.
- NetworkPolicy — Firewall-Regeln zwischen Pods; kann erwarteten Traffic still blockieren.
- Horizontal Pod Autoscaler — sagt dem Deployment, die Replikate zu ändern; mehr Geschwister, kein größeres Ich.
Ich bin eine Zeile in einer großen Tabelle, die der Cluster dauernd angleicht.
Updates: wenn eine neue Version von mir kommt
Das App-Image war stabil — bis es das nicht mehr war. Jemand liefert checkout-api:2.5.0.
Man ändert die Deployment-Vorlage, nicht mich persönlich. Der Deployment-Controller erstellt ein neues ReplicaSet mit der aktualisierten Vorlage und skaliert es hoch, während das alte runterfährt. Das ist ein Rolling Update.
Neue Pods erscheinen mit dem neuen Image. Alte Pods wie ich bekommen SIGTERM. Handhabt die App das Signal sauber — laufende Requests beenden, Verbindungen schließen — merken Kunden wenig. Sonst läuft terminationGracePeriodSeconds ab und das Kubelet sendet SIGKILL.
Optionale preStop-Hooks geben mir Sekunden zum Abfahren, bevor der Service mich aus der Rotation nimmt. Dieser kleine Hook verhindert erstaunlich viele 502-Fehler.
Nach dem Rollout bin ich weg; meine Nachfolger antworten auf denselben Service-Namen. Für Clients hat sich die Telefonnummer nicht geändert — nur die Crew dahinter.
kubectl rollout status deployment/checkout-api -n <namespace>
kubectl rollout history deployment/checkout-api -n <namespace>
Wie mein Leben endet
Pods sterben aus vielen normalen Gründen:
- Rolling Update hat mich ersetzt.
- Node wurde für Wartung drained.
- Replikate wurden reduziert.
- Liveness-Probe ist wiederholt fehlgeschlagen.
- Node ist ausgefallen; mein Ersatz wurde woanders eingeplant.
- Jemand hat das Deployment gelöscht — dann gehen wir alle.
Löschung ist ein Prozess, kein Schalter. Ich werde Terminating. Endpoint-Controller entfernen mich aus Service-Backends. Das Kubelet sendet SIGTERM, wartet, dann bei Bedarf SIGKILL. Volumes hängen ab. Meine IP wird recycelt. Mein Name kommt nicht zurück — ein neuer Pod mit neuem Suffix übernimmt.
Das ist kein Fehler. Das ist das Design.
Was ich dir mitgeben möchte
Beim Lernen hilft es, den Blickwinkel umzudrehen. Menschen starten bei kubectl und YAML. Ich starte bei einem Node, den der Scheduler gewählt hat, und einer Vorlage, die das Deployment geschrieben hat.
Die praktischen Gewohnheiten aus meiner Geschichte:
- Deployment ändern, nicht den Pod — außer für bewusste Einmal-Experimente.
- Dem Service-Namen vertrauen, nicht meiner IP — beides behalte ich nicht lange.
- Events und describe lesen — so erzähle ich, warum ich Pending, CrashLoopBackOff oder NotReady bin.
- Probes und graceful shutdown zur App dazuzählen — sie entscheiden, ob Updates ruhig oder chaotisch wirken.
- Ersetzung erwarten — „dieser eine Pod“ zählt im Moment; Betrieb heißt Replikate und gewünschter Zustand.
Ich bin ein Pod. Ich führe eine stabile Anwendung eine Weile aus, mache meinen Job hinter einem stabilen Service-Namen — und mache Platz für die nächste Kopie, wenn der Cluster weitergeht.
Das ist ein volles Leben in Kubernetes-Begriffen. Ehrlich gesagt: ein ziemlich gutes.