Das Problem: Invisible Anomalien
Klassisches Szenario:
- 10:00 — Pod hat Memory-Leak (unbemerkt)
- 10:15 — Pod nutzt 90% seines Limits (unbemerkt)
- 10:30 — Pod OOMKilled, crasht
- 10:31 — Alert feuert (endlich sichtbar)
- 10:40 — SRE wacht auf, checkt Logs
- 10:50 — SRE rätselt: "Was hat den OOM verursacht?"
- 11:05 — Memory erhöht (Symptom behandelt, nicht Ursache)
Die Root Cause (Memory-Leak im Code) bleibt unbehandelt. Incident wiederholt sich in 2 Wochen.
Besserer Weg: Mit Patterns, die Anomalien früh sichtbar machen, können intelligente Diagnose-Tools (wie KI-Ops) Ursachen schnell klären. Dein Team versteht dann: Ist es ein Leak, ein Spike oder ein echtes Feature-Weight-Wachstum?
Pattern 1: Liveness Probes (frühes Erkennen von Deadlocks)
Eine Liveness Probe prüft, ob ein Container noch "lebt". Wenn die Probe fehlschlägt, wird das sichtbar – und KI-Ops kann analysieren, WARUM.
apiVersion: v1
kind: Pod
metadata:
name: api-service
spec:
containers:
- name: api
image: my-api:v1
ports:
- containerPort: 8080
# Liveness Probe: Check every 10 seconds if /health returns OK
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30 # Give the container time to start
periodSeconds: 10 # Check every 10 seconds
timeoutSeconds: 2 # Timeout after 2 seconds
failureThreshold: 3 # Restart only after 3 consecutive failures
Was die Probe macht:
- Alle 10 Sekunden schickt Kubernetes ein HTTP GET an
http://localhost:8080/health - Antwortet der Container mit Status 200, ist alles gut
- Schlägt die Probe fehl, wird das in kubectl und Prometheus sichtbar
- KI-Ops sieht diese Anomalie und analysiert, WARUM die Probe fehlschlägt
- Deadlock im Code? → Code-Review nötig
- Abhängigkeit (DB) ist down? → Diagnose für DB-Problem
- GC stoppt die Welt? → Heap-Analyse nötig
Häufiger Fehler: Probe zu aggressiv
# WRONG: Restarts the container every second for minor issues
livenessProbe:
periodSeconds: 1 # Too frequent!
failureThreshold: 1 # Too strict!
# RIGHT: Gives the container time to recover
livenessProbe:
periodSeconds: 10 # Every 10 seconds
failureThreshold: 3 # Restart after 3 failures
initialDelaySeconds: 30 # 30s for startup
Praxisbeispiel:
# Node.js Express service
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 15
periodSeconds: 10
failureThreshold: 3
// In your app code:
app.get('/health', (req, res) => {
// Check if the database is still reachable
if (db.connection.isConnected) {
res.status(200).json({ status: 'alive' });
} else {
res.status(503).json({ status: 'unhealthy' });
}
});
Pattern 2: Readiness Probes (Ist der Service bereit für Traffic?)
Der Unterschied zu Liveness Probes:
- Liveness: "Lebt der Container noch?" → Wenn nicht, restart
- Readiness: "Kann dieser Container Traffic verarbeiten?" → Wenn nicht, schick ihm keinen Traffic
# Readiness: Check if the service can process traffic
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5 # Check after 5 seconds
periodSeconds: 5 # Every 5 seconds
successThreshold: 1 # At least 1 success
failureThreshold: 2 # After 2 failures: no traffic
Klassisches Szenario ohne Readiness Probe:
10:00 - Pod starts
10:00 - Kubernetes asks Liveness: "Are you alive?" → YES
10:00 - Kubernetes sends traffic
10:02 - Database connection pool is still initializing (takes 2 min)
10:02 - Container can't process database queries yet
10:02 - Error rate 100% because API isn't ready
With Readiness Probe:
10:00 - Pod starts
10:00 - Kubernetes asks Liveness: "Are you alive?" → YES
10:00 - Kubernetes asks Readiness: "Can you handle traffic?" → NO (DB pool not ready)
10:00 - Kubernetes does NOT send traffic
10:02 - Readiness says YES (DB pool ready)
10:02 - Now Kubernetes sends traffic
10:02 - Error rate 0% because everything is ready
In deinem Code:
// Readiness endpoint
app.get('/ready', async (req, res) => {
const checks = {
database: await db.isConnected(),
cache: await redis.ping(),
externalAPI: await checkExternalServiceHealth(),
};
if (Object.values(checks).every(c => c === true)) {
res.status(200).json({ ready: true });
} else {
res.status(503).json({ ready: false, details: checks });
}
});
Pattern 3: Pod Disruption Budgets (PDB)
Wenn Kubernetes deinen Cluster updatet, drained es Nodes — und verschiebt Pods auf andere Nodes. Ohne PDB können all deine Pods gleichzeitig untergehen.
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-service-pdb
spec:
minAvailable: 2 # At least 2 replicas must always be running
selector:
matchLabels:
app: api-service
Was es macht:
- Wenn dein Cluster 5 api-service-Pods hat und Kubernetes updaten muss
- hält Kubernetes jederzeit mindestens 2 Replicas am Laufen
- Es stoppt maximal 3 Pods gleichzeitig
- Der Service bleibt während des Updates verfügbar
Ohne PDB:
Before: 5 API pods running
Cluster update starts
Kubernetes: "I'll stop all 5 pods to update them"
All 5 pods down
Service has 100% downtime for 5 minutes
Mit PDB (minAvailable: 2):
Before: 5 API pods running
Cluster update starts
Kubernetes: "I need to keep at least 2 running"
Stops 3 pods → 2 pods still running
Traffic goes to the 2 running pods
3 pods update and restart
Remaining 2 pods update
Service had ~0% downtime
Best Practice:
# For stateless services
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-pdb
spec:
minAvailable: 2 # At least 2 must run
selector:
matchLabels:
tier: api
---
# For databases or stateful services
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: db-pdb
spec:
minAvailable: 1 # Only 1 needs to run (important for quorum)
selector:
matchLabels:
tier: database
Pattern 4: Horizontal Pod Autoscaling (HPA)
Steigt die Last, skaliere hoch. Sinkt die Last, skaliere runter.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-service-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # Scale when CPU > 70%
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80 # Scale when memory > 80%
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # Wait 5 min before scaling down
scaleUp:
stabilizationWindowSeconds: 0 # Scale up immediately
Szenario:
10:00 - Normal traffic: 2 pods running
10:05 - Black Friday sale starts: traffic 10x
10:06 - CPU reaches 75%
10:07 - HPA detects it, creates 2 new pods
10:08 - 4 pods running, traffic better distributed
10:09 - CPU drops to 65%, everything stable
11:00 - Sale over, traffic returns to normal
11:05 - CPU under 70%, HPA starts downscaling
11:10 - Back to 2 pods (saving costs)
Häufiger Fehler:
# WRONG: Too aggressive thresholds
metrics:
- resource:
name: cpu
target:
averageUtilization: 30 # Scales up and down constantly (flapping)
# RIGHT: Reasonable thresholds
metrics:
- resource:
name: cpu
target:
averageUtilization: 70 # Gives you buffer
Pattern 5: Resource Limits und Requests
Resource Limits verhindern, dass ein einzelner Pod alle Ressourcen eines Nodes frisst und andere Pods aushungert.
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-service
spec:
replicas: 3
template:
spec:
containers:
- name: api
image: my-api:v1
resources:
# Request: Minimum resources the pod needs
# Kubernetes schedules on a node with enough capacity
requests:
cpu: 250m # 250 milliCPU = 1/4 CPU
memory: 256Mi # 256 MB
# Limit: Maximum the pod is allowed to use
# If the pod exceeds the limit, it gets killed
limits:
cpu: 500m # Maximum 500 milliCPU
memory: 512Mi # Maximum 512 MB
Ohne Limits:
10:00 - Pod has a memory leak, uses more and more memory
10:15 - Pod uses 90% of node memory
10:16 - Other pods can't start
10:17 - Cluster is effectively down
10:30 - SRE finds the leak
Total impact: 30+ minutes
With limits (512Mi):
10:00 - Pod has a memory leak
10:05 - Pod reaches 512Mi (= limit)
10:06 - Kubernetes kills the pod (OOMKilled)
10:07 - Kubernetes starts a new pod replica
10:08 - New instance runs, old one is gone
10:09 - SRE sees OOMKilled events and investigates the root cause
Downtime: ~1-2 minutes instead of 30 minutes
Best Practices für Limits:
# Node has 4 CPUs, 16GB RAM
# You plan 5 pods on it
# Per pod
requests:
cpu: 700m # 5 x 700m = 3500m = 3.5 CPUs (under 4)
memory: 2Gi # 5 x 2Gi = 10Gi (under 16Gi)
limits:
cpu: 1000m # Give some buffer
memory: 3Gi
Wie KI-Ops Anomalien nutzt
KI-Ops läuft in deiner Infrastruktur (read-only) und nutzt diese Patterns, um Anomalien früh zu erkennen und zu analysieren:
$ ki-ops analyze --namespace production
🔴 api-service: Liveness Probe schlägt fehl (47 Fehler in 10 Min)
├─ Ursachen-Hypothesen (priorisiert):
│ ├─ 92% Konfidenz: Deadlock im Connection-Pool
│ ├─ 6% Konfidenz: Abhängigkeit (DB) antwortet langsam
│ └─ 2% Konfidenz: GC-Freeze
├─ Logs zeigen: "Connection pool exhausted"
└─ KI-Empfehlung: Connection-Pool-Größe überprüfen, DB-Queries optimieren
⚠️ api-service: Memory nutzt 87% des Limits (war gestern 45%)
├─ Trend: Steigend über 6 Stunden
├─ Hypothesen:
│ ├─ 78% Konfidenz: Memory-Leak in Cache-Layer
│ ├─ 15% Konfidenz: Höhere Last (legitimate)
│ └─ 7% Konfidenz: GC-Overhead
└─ KI-Empfehlung: Heap-Dump vor nächstem OOM, Leak-Analyze
✅ api-service: HPA und Resource Limits passen zusammen
└─ Schkalierung funktioniert wie erwartet
KI-Ops analysiert Anomalien, präsentiert Hypothesen mit Konfidenz. Dein Team versteht dann, ob sie "HPA scale hochfahren" oder "Code-Leak beheben" müssen.
Messbare Ergebnisse
Mit allen 5 Patterns korrekt konfiguriert + KI-Ops Analyse:
| Metrik | Vorher | Nachher | Verbesserung | |--------|--------|---------|--------------| | MTTD (Alert bis Diagnose) | 30 Min | <5 Min | 85% schneller | | % Incidents mit klarer Root Cause | 30% | 85% | 3x mehr Klarheit | | Repeat-Incidents (gleiche Ursache) | 60% innerhalb 2 Wochen | 10% | 84% weniger Wiederholungen | | SRE-Zeit für Troubleshooting | 80h/Monat | 15h/Monat | 81% weniger Toil | | False-Alert-Rate | 40% | 8% | Weniger Noise |
Die Checkliste
Für jeden Production-Service:
- [ ] Liveness Probe (prüft, ob der Container lebt)
- [ ] Readiness Probe (prüft, ob der Container Traffic verarbeiten kann)
- [ ] Resource Requests gesetzt (fürs Scheduling)
- [ ] Resource Limits gesetzt (keine noisy neighbors)
- [ ] HPA konfiguriert (Auto-Scaling)
- [ ] PDB mit minAvailable (Cluster-Updates)
- [ ] Mindestens 2 Replicas (High Availability)
Wenn das alles gesetzt ist, ist dein Service zu 99,9% self-healing.
Nächster Schritt: Zeig mir deine Cluster-Anomalien – KI-Ops analysiert sie in Echtzeit, ohne invasiv zu sein. Demo buchen und sieh, wie Root-Cause-Analyse deine Incident-Response revolutioniert.