Warum du ein Kubernetes-Incident-Playbook brauchst
Es ist 3 Uhr nachts. PagerDuty schlägt an. Dein Production-Cluster hat ein Problem. Du klappst dein Laptop auf, verschlafen, und starrst auf ein Terminal.
Und jetzt?
Ohne Playbook sehen die nächsten 45 Minuten so aus:
- 5 Minuten: Dir merken, um welchen Cluster es überhaupt geht
- 10 Minuten: Wahllos kubectl-Kommandos absetzen und hoffen, dass dir was auffällt
- 15 Minuten: Zwischen Grafana, Loki und Terminal hin- und herspringen
- 10 Minuten: Die Fehlermeldung googeln
- 5 Minuten: Es tatsächlich fixen
Mit Playbook dauert derselbe Incident 10–15 Minuten. Mit KI-gestützter Analyse < 5 Minuten.
Das hier ist dieses Playbook.
Phase 1: Triage (0–2 Minuten)
Ziel: Umfang und Schweregrad verstehen. Noch nichts fixen.
Schritt 1: Schneller Cluster-Health-Check
# Are nodes healthy?
kubectl get nodes
# Look for: NotReady, SchedulingDisabled, MemoryPressure, DiskPressure
# What's broken in the affected namespace?
kubectl get pods -n <namespace> --field-selector=status.phase!=Running
# Shows only non-running pods
# Recent events (last 10 minutes)
kubectl get events -n <namespace> --sort-by='.lastTimestamp' | tail -20
Schritt 2: Den Incident klassifizieren
| Schweregrad | Kriterium | Reaktion | |----------|----------|----------| | SEV1 — Outage | Kundenseitiger Service ausgefallen, Datenverlust-Risiko | All hands, sofort eskalieren | | SEV2 — Degraded | Service langsam oder teilweise kaputt | On-Call-Engineer, Team-Lead informieren | | SEV3 — Warning | Nicht-kritischer Service betroffen, kein Kundenimpact | On-Call-Engineer, während der Geschäftszeiten fixen | | SEV4 — Info | Potenzielles Problem erkannt, aktuell kein Impact | Dokumentieren, Untersuchung einplanen |
Schritt 3: Prüfen, ob es schon bekannt ist
Bevor du tiefer einsteigst:
- Schau in den #incidents-Slack-Channel deines Teams
- Prüf, ob in den letzten 30 Minuten ein Deployment lief
- Prüf, ob schon jemand dran ist
# Recent deployments
kubectl rollout history deployment/<name> -n <namespace>
# Who changed what recently?
kubectl get events -n <namespace> --field-selector=reason=ScalingReplicaSet | tail -5
Phase 2: Diagnose (2–10 Minuten)
Ziel: Root Cause finden. Widersteh dem Drang, einfach Dinge neu zu starten.
Das Diagnose-Flowchart
Pod not running?
├── Status: CrashLoopBackOff → Check logs (Phase 2a)
├── Status: ImagePullBackOff → Check image/registry (Phase 2b)
├── Status: Pending → Check scheduling (Phase 2c)
├── Status: OOMKilled → Check resources (Phase 2d)
└── Status: Running but unhealthy → Check probes + metrics (Phase 2e)
Phase 2a: CrashLoopBackOff
Der Pod startet, crasht, startet neu, crasht wieder.
# Check the last crash logs
kubectl logs <pod> -n <namespace> --previous
# Check the exit code
kubectl describe pod <pod> -n <namespace> | grep -A5 "Last State"
# Exit Code 1 = Application error (check logs)
# Exit Code 137 = OOMKilled (increase memory)
# Exit Code 143 = SIGTERM (graceful shutdown, usually fine)
# Check if it's a startup issue
kubectl describe pod <pod> -n <namespace> | grep -A10 "Events"
Häufige Ursachen:
- Fehlende Umgebungsvariable oder Config
- Falscher Datenbank-Connection-String nach einer Rotation
- Neue Image-Version hat einen Bug
- Memory-Limit zu niedrig (OOMKilled)
Phase 2b: ImagePullBackOff
Der Pod kann sein Container-Image nicht pullen.
kubectl describe pod <pod> -n <namespace> | grep -A3 "Events"
# Look for: "unauthorized", "not found", "timeout"
Häufige Ursachen:
- Image-Tag existiert nicht (Tippfehler oder gelöscht)
- Registry-Credentials abgelaufen (imagePullSecret)
- Private Registry nicht erreichbar (Netzwerk/Firewall)
Quick Fix:
# Check which image is requested
kubectl get pod <pod> -n <namespace> -o jsonpath='{.spec.containers[*].image}'
# Check if the secret exists and is valid
kubectl get secret <pull-secret> -n <namespace> -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d
Phase 2c: Pending Pods
Der Pod existiert, kann aber auf keinen Node gescheduled werden.
kubectl describe pod <pod> -n <namespace> | grep -A10 "Events"
# Look for: Insufficient cpu, Insufficient memory, node affinity, taints
Häufige Ursachen:
- Nicht genug Ressourcen auf irgendeinem Node
- Node-Affinity/Anti-Affinity-Constraints zu strikt
- PersistentVolumeClaim nicht gebunden
- Alle Nodes tainted und Pod hat keine Toleration
Quick Check:
# Available resources across all nodes
kubectl describe nodes | grep -A5 "Allocated resources"
# PVC status
kubectl get pvc -n <namespace>
Phase 2d: OOMKilled
Der Container hat sein Memory-Limit überschritten und der Kernel hat ihn gekillt.
# Confirm OOMKilled
kubectl describe pod <pod> -n <namespace> | grep -i "oomkilled"
# Check current memory limit vs actual usage
kubectl top pod <pod> -n <namespace> --containers
# Check memory limit
kubectl get pod <pod> -n <namespace> -o jsonpath='{.spec.containers[*].resources.limits.memory}'
Memory-Leak oder einfach unterdimensioniert?
- Wenn der Speicher über Stunden langsam gewachsen ist → wahrscheinlich Memory-Leak → braucht Code-Fix
- Wenn der Speicher mit Traffic gespiked ist → unterdimensioniert → Limit erhöhen
- Wenn der Speicher nach einem Deployment gespiked ist → neue Version braucht mehr Speicher → Limit erhöhen oder untersuchen
Phase 2e: Running, aber unhealthy
Pod läuft, aber Liveness/Readiness-Probes schlagen fehl oder die Latenz ist hoch.
# Check probe configuration
kubectl describe pod <pod> -n <namespace> | grep -A10 "Liveness\|Readiness"
# Check recent restarts due to probe failures
kubectl get pod <pod> -n <namespace> -o jsonpath='{.status.containerStatuses[*].restartCount}'
# Check application logs for errors
kubectl logs <pod> -n <namespace> --since=10m | grep -i "error\|exception\|timeout"
Phase 3: Fix (10–15 Minuten)
Ziel: Die minimale Änderung anwenden, die den Service wiederherstellt. Um 3 Uhr nachts nichts over-engineeren.
Quick Fixes (jetzt anwenden, Root Cause später)
| Problem | Quick Fix | Permanenter Fix (morgen) |
|---------|-----------|--------------------------|
| OOMKilled | kubectl set resources deploy/<name> --limits memory=1Gi | Memory-Nutzung profilen, saubere Limits setzen |
| Falsches Image | kubectl set image deploy/<name> <container>=<good-image> | CI/CD-Pipeline fixen |
| Zu wenige Replicas | kubectl scale deploy/<name> --replicas=5 | HPA sauber konfigurieren |
| Kaputte Config | kubectl rollout undo deploy/<name> | Config fixen, neu deployen |
| Node-Pressure | kubectl drain <node> --ignore-daemonsets | Kapazität ergänzen oder optimieren |
Die goldene Regel: Erst Rollback, dann untersuchen
Wenn in den letzten 30 Minuten ein Deployment lief und genau dann alles kaputtging:
# Rollback to previous version
kubectl rollout undo deployment/<name> -n <namespace>
# Verify it's recovering
kubectl rollout status deployment/<name> -n <namespace>
Das stellt den Service in 1–2 Minuten wieder her. Die Root Cause untersuchst du während der Geschäftszeiten.
Phase 4: Verifizieren (15–20 Minuten)
Ziel: Bestätigen, dass der Fix funktioniert hat und keine Seiteneffekte aufgetreten sind.
# Pods healthy?
kubectl get pods -n <namespace>
# No new error events?
kubectl get events -n <namespace> --sort-by='.lastTimestamp' | tail -10
# Application responding?
kubectl exec -it <pod> -n <namespace> -- curl -s localhost:<port>/health
# Metrics back to normal?
# Check Grafana dashboard for the affected service
Phase 5: Post-Mortem (nächster Werktag)
Überspring das nicht. Das Post-Mortem verhindert das nächste 3-Uhr-nachts-Aufwachen.
Post-Mortem-Template
## Incident: [Title]
**Date:** [Date] | **Severity:** SEV[1-4] | **Duration:** [X] minutes
### Timeline
- HH:MM — Alert fired
- HH:MM — Engineer responded
- HH:MM — Root cause identified
- HH:MM — Fix applied
- HH:MM — Service recovered
### Root Cause
[One paragraph explaining what actually went wrong]
### What Went Well
- [e.g., "Alert fired within 2 minutes of the issue"]
- [e.g., "Rollback procedure worked smoothly"]
### What Went Poorly
- [e.g., "Took 25 minutes to find the root cause"]
- [e.g., "No runbook existed for this failure mode"]
### Action Items
- [ ] [Fix to prevent recurrence]
- [ ] [Monitoring improvement]
- [ ] [Documentation update]
Wie KI jede Phase verkürzt
| Phase | Manuell | Mit KI-Ops | Ersparnis | |-------|--------|---------|---------| | Triage | 2–5 Min | 30 Sek (auto-klassifiziert) | 80% | | Diagnose | 15–30 Min | <1 Min (auto-analysiert) | 98% | | Empfehlung | 5–10 Min (Recherche) | Sofort | 90% | | Verifizieren | 5 Min | 2 Min (auto-überwacht) | 60% | | Gesamt | 35–60 Min | 3–5 Min | ~90% |
Der größte Hebel liegt in der Diagnose-Phase. KI-Ops läuft in deiner eigenen Infrastruktur, setzt alle Diagnose-Kommandos parallel ab, korreliert Logs mit Metriken und Cluster-State und liefert dir eine präzise Root-Cause-Analyse mit klaren Empfehlungen — das eliminiert 98% der manuellen Untersuchungszeit. Deine Cluster-Daten, Logs und Metriken bleiben dabei in deiner Umgebung, KI-Ops arbeitet read-only.
Erst das Playbook, dann automatisieren
- Druck dieses Playbook aus (oder leg es im Team-Wiki ab). Strukturierte Schritte reduzieren die Panik um 3 Uhr nachts.
- Miss die Zeit bei deinen nächsten 5 Incidents. Wie lange dauert jede Phase, besonders die Diagnose?
- Automatisiere zuerst die Diagnose-Phase. Dort gehen 75% der Zeit verloren.
- Lass KI-Ops die Arbeit übernehmen. KI-Ops erkennt, analysiert und liefert fundierte Root-Cause-Empfehlungen — read-only und nicht-invasiv, dein Team setzt die Recommendations um. Mit Audit-Trail und in deinem Freigabeprozess. Kein blinder Autopilot. Skalenta übernimmt Betrieb und Optimierung. Demo buchen.
Nächster Schritt: So senkt KI-Ops die Diagnosezeit von 30 auf unter 1 Minute