- Authors

- Name
- Phillip Pham
- @ddppham
Kubernetes Performance Probleme: Diagnose und Loesung komplexer Bottlenecks
TL;DR
- Kubernetes Performance Probleme lassen sich in sechs Kategorien einteilen: CPU, Memory, Network, Storage, etcd und API Server
- CPU-Throttling ist der haeufigste unsichtbare Performance-Killer -- Pods werden gedrosselt, ohne dass ein OOMKill sichtbar wird
- Prometheus-Queries und kubectl-Befehle liefern die noetige Datenbasis fuer systematische Diagnose
- Oft liegt das Problem nicht an Kubernetes selbst, sondern an falschen Resource Requests, ueberladenen Nodes oder ineffizientem Application Code
- Eine Performance Baseline zu definieren ist die Voraussetzung, um Abweichungen ueberhaupt erkennen zu koennen
Warum Performance-Diagnose in Kubernetes komplex ist
In einer traditionellen VM-Umgebung laeuft eine Anwendung auf einem Server mit bekannten Ressourcen. Ist sie langsam, schaut man auf CPU, RAM, Disk I/O und Netzwerk dieses einen Servers.
In Kubernetes ist das anders. Eine Anwendung laeuft als Pod auf einem Node, der sich Ressourcen mit Dutzenden anderen Pods teilt. Dazwischen liegt ein CNI-Plugin fuer Netzwerk, ein CSI-Treiber fuer Storage, ein kubelet fuer die Container-Verwaltung und der API-Server fuer jede Steuerungsoperation. Jede dieser Schichten kann zum Bottleneck werden.
Hinzu kommt: Kubernetes Performance Probleme aeussern sich oft indirekt. Eine langsame Antwortzeit kann an CPU-Throttling liegen, an DNS-Aufloesung, an einem ueberlasteten Service Mesh, an IOPS-Limits des PersistentVolumes oder an einem etcd, der unter Compaction-Last steht.
Systematisches Vorgehen ist der Schluessel. Wir gehen die sechs Hauptkategorien durch und zeigen fuer jede die Diagnose-Werkzeuge und Loesungen.
1. CPU-Bottlenecks
Das Problem
CPU-Probleme in Kubernetes haben zwei Ursachen: Throttling durch zu niedrige CPU-Limits und Node-Overcommitment durch zu niedrige CPU-Requests.
CPU-Throttling passiert, wenn ein Container sein CPU-Limit erreicht. Der Linux CFS Scheduler (Completely Fair Scheduler) drosselt den Container dann aktiv. Das ist oft unsichtbar, weil kein Error-Log und kein OOMKill entsteht -- die Anwendung wird einfach langsamer.
Node-Overcommitment passiert, wenn die Summe aller CPU-Requests auf einem Node die verfuegbare CPU uebersteigt. Das sollte der Scheduler eigentlich verhindern, kann aber durch Burstable QoS-Klassen (Requests kleiner als Limits) entstehen.
Diagnose
# CPU-Throttling pro Container anzeigen
kubectl top pods -n production --sort-by=cpu
# Detaillierte CPU-Auslastung eines Pods
kubectl exec -n production my-app-pod -- cat /sys/fs/cgroup/cpu/cpu.stat
Prometheus-Queries fuer CPU-Throttling:
# Throttling-Rate pro Container (Anteil der gedrosselten Perioden)
sum by (pod, container) (
rate(container_cpu_cfs_throttled_periods_total[5m])
) /
sum by (pod, container) (
rate(container_cpu_cfs_periods_total[5m])
) * 100
# CPU-Auslastung vs. Request (sollte unter 100% liegen)
sum by (pod, container) (
rate(container_cpu_usage_seconds_total[5m])
) /
sum by (pod, container) (
kube_pod_container_resource_requests{resource="cpu"}
) * 100
# Nodes mit hohem CPU-Overcommitment
sum by (node) (kube_pod_container_resource_requests{resource="cpu"})
/
sum by (node) (kube_node_status_allocatable{resource="cpu"}) * 100
Loesung
- Throttling reduzieren: CPU-Limits erhoehen oder ganz entfernen. Viele Teams setzen mittlerweile nur noch CPU-Requests und verzichten auf CPU-Limits, weil CPU im Gegensatz zu Memory eine kompressible Ressource ist.
- Requests korrekt dimensionieren: P95-Wert der tatsaechlichen Nutzung aus Prometheus nehmen. Mehr dazu unter Kubernetes Capacity Planning.
- HPA aktivieren: Bei variabler Last ist horizontale Skalierung oft besser als groessere Limits.
- Application-Code optimieren: Manchmal ist nicht Kubernetes das Problem, sondern ineffizienter Code (N+1 Queries, fehlende Caches, synchrone Calls).
2. Memory-Probleme
Das Problem
Memory-Probleme in Kubernetes aeussern sich als OOMKilled-Pods, als langsame Anwendungen wegen Swap-Nutzung (falls aktiviert) oder als Evictions auf ueberlasteten Nodes.
Im Gegensatz zu CPU ist Memory eine nicht-kompressible Ressource. Wenn ein Container sein Memory-Limit ueberschreitet, wird er sofort vom OOM-Killer beendet. Es gibt keine Drosselung.
Diagnose
# OOMKilled-Pods finden
kubectl get pods -A -o json | \
jq -r '.items[] |
select(.status.containerStatuses[]?.lastState.terminated.reason == "OOMKilled") |
"\(.metadata.namespace)/\(.metadata.name)"'
# Memory-Nutzung der Nodes pruefen
kubectl top nodes
# Memory-Details eines spezifischen Pods
kubectl top pod my-app-pod -n production --containers
Prometheus-Queries:
# Working Set Memory vs. Limit (nah an 100% = OOMKill-Gefahr)
sum by (pod, container) (
container_memory_working_set_bytes
) /
sum by (pod, container) (
kube_pod_container_resource_limits{resource="memory"}
) * 100
# OOMKill-Events pro Namespace in der letzten Stunde
sum by (namespace) (
increase(kube_pod_container_status_restarts_total[1h])
)
# Node Memory Pressure
kube_node_status_condition{condition="MemoryPressure", status="true"}
Loesung
- Memory-Limits basierend auf Monitoring setzen: Nicht raten, sondern
container_memory_working_set_bytesueber mindestens eine Woche beobachten. Limit auf P99 plus 20% Buffer. - Memory Leaks identifizieren: Stetig steigendes
container_memory_working_set_bytesueber Stunden oder Tage deutet auf ein Leak hin. Das ist kein Kubernetes-Problem, sondern ein Application-Problem. - Vertical Pod Autoscaler (VPA): Passt Requests und Limits automatisch an die tatsaechliche Nutzung an. Empfehlenswert im Recommendation-Modus als Orientierung.
- Java-Anwendungen: JVM-Heap-Size explizit setzen und auf Container-Memory abstimmen.
-XX:MaxRAMPercentage=75statt fester-Xmx-Werte.
3. Netzwerk-Latenz
Das Problem
Netzwerk-Performance in Kubernetes wird durch mehrere Schichten beeinflusst: das CNI-Plugin, DNS-Aufloesung, Service-Routing (iptables/IPVS) und optional ein Service Mesh.
Typische Symptome: Erhoehte Antwortzeiten zwischen Services, DNS-Timeouts, Connection Timeouts bei Service-zu-Service-Kommunikation.
Diagnose
# DNS-Aufloesung testen (sollte unter 5ms sein)
kubectl exec -n production my-app-pod -- \
nslookup kubernetes.default.svc.cluster.local
# Netzwerk-Latenz zwischen Pods messen
kubectl exec -n production pod-a -- \
curl -w "DNS: %{time_namelookup}s, Connect: %{time_connect}s, Total: %{time_total}s\n" \
-s -o /dev/null http://service-b:8080/health
# CoreDNS-Pods pruefen
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl logs -n kube-system -l k8s-app=kube-dns --tail=50
Prometheus-Queries:
# CoreDNS Latenz (P99)
histogram_quantile(0.99,
sum by (le) (
rate(coredns_dns_request_duration_seconds_bucket[5m])
)
)
# CoreDNS Error-Rate
sum(rate(coredns_dns_responses_total{rcode="SERVFAIL"}[5m]))
/
sum(rate(coredns_dns_responses_total[5m])) * 100
# Service-Mesh-Latenz (Istio-Beispiel)
histogram_quantile(0.99,
sum by (destination_service, le) (
rate(istio_request_duration_milliseconds_bucket[5m])
)
)
Loesung
- DNS-Caching: NodeLocal DNSCache deployen, um DNS-Lookups zu beschleunigen und CoreDNS zu entlasten.
- ndots-Einstellung optimieren: Der Standard
ndots: 5fuehrt dazu, dass jede DNS-Abfrage bis zu fuenf Suchdomains durchprobiert, bevor die tatsaechliche Domain aufgeloest wird. Fuer externe Domainnamen ein.am Ende anhaengen oderndots: 2setzen. - CNI-Plugin evaluieren: Cilium mit eBPF ist messbar schneller als iptables-basierte Loesungen bei hoher Pod-Anzahl.
- Service Mesh Overhead: Wenn Istio oder Linkerd eingesetzt wird, den Sidecar-Overhead messen. Fuer latenz-kritische Pfade Direct-Pod-to-Pod-Kommunikation in Betracht ziehen.
Vertiefende Informationen zu DNS-Problemen finden Sie in unserem CoreDNS Troubleshooting Guide.
4. Storage I/O
Das Problem
Persistent Volumes (PVs) in Kubernetes unterliegen den IOPS- und Throughput-Limits des zugrunde liegenden Storage-Systems. Cloud-basierte Block-Storage-Volumes (EBS, Azure Disk, Persistent Disk) haben oft niedrigere Default-IOPS als erwartet.
Typische Symptome: Langsame Datenbankabfragen, hohe Write-Latenz, Timeouts bei dateiintensiven Operationen.
Diagnose
# I/O-Statistiken eines Pods anzeigen
kubectl exec -n production db-pod -- iostat -x 1 5
# PV-Kapazitaet und Auslastung pruefen
kubectl get pv -o custom-columns=\
NAME:.metadata.name,\
CAPACITY:.spec.capacity.storage,\
STORAGECLASS:.spec.storageClassName,\
STATUS:.status.phase
# StorageClass-Details (IOPS, Throughput)
kubectl get storageclass -o yaml
Prometheus-Queries:
# Disk I/O Latenz pro Pod (Write)
rate(container_fs_writes_total[5m])
# Disk Throughput pro Pod
sum by (pod) (
rate(container_fs_writes_bytes_total[5m])
)
# PV-Auslastung (Prozent)
kubelet_volume_stats_used_bytes
/
kubelet_volume_stats_capacity_bytes * 100
Loesung
- StorageClass mit hoeheren IOPS verwenden: In AWS z.B.
gp3stattgp2, mit explizit konfigurierten IOPS. - Local SSDs fuer latenz-kritische Workloads: Fuer Datenbanken wie PostgreSQL oder Elasticsearch bringen lokale NVMe-SSDs dramatische Verbesserungen.
- ReadWriteMany vermeiden: NFS-basierte RWX-Volumes sind deutlich langsamer als Block-Storage. Wo moeglich, auf ReadWriteOnce umstellen.
- I/O-Scheduling optimieren:
fio-Benchmarks auf dem PV ausfuehren, um die tatsaechlichen IOPS zu ermitteln und mit den Anforderungen abzugleichen.
5. etcd-Performance
Das Problem
etcd ist die zentrale Datenbank von Kubernetes. Wenn etcd langsam wird, wird der gesamte Cluster langsam. Typische Ursachen: Zu viele Objects im Cluster, fehlende Compaction, langsame Disk-I/O oder Netzwerk-Latenz zwischen etcd-Membern.
Diagnose
# etcd-Metriken direkt abfragen
kubectl exec -n kube-system etcd-master-0 -- \
etcdctl endpoint status --write-out=table \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# Anzahl Keys in etcd
kubectl exec -n kube-system etcd-master-0 -- \
etcdctl get / --prefix --keys-only | wc -l
Prometheus-Queries:
# etcd Disk Sync Duration (sollte unter 10ms liegen)
histogram_quantile(0.99,
sum by (le) (
rate(etcd_disk_wal_fsync_duration_seconds_bucket[5m])
)
)
# etcd Backend Commit Duration
histogram_quantile(0.99,
sum by (le) (
rate(etcd_disk_backend_commit_duration_seconds_bucket[5m])
)
)
# Slow Requests (ueber 100ms)
rate(etcd_server_slow_apply_total[5m])
# etcd Database Size
etcd_mvcc_db_total_size_in_bytes
Loesung
- Dedizierte SSDs fuer etcd: etcd ist extrem latenz-sensitiv. SATA-SSDs reichen oft nicht, NVMe ist empfohlen.
- Compaction und Defragmentierung: Automatische Compaction aktivieren und regelmaessige Defragmentierung einplanen.
- Anzahl Objects reduzieren: Abgelaufene Leases, alte ConfigMaps, verwaiste Endpoints bereinigen.
- etcd von Workload-Nodes trennen: In Produktionsclustern sollte etcd auf dedizierten Nodes laufen, nicht zusammen mit dem API-Server.
6. API-Server-Bottlenecks
Das Problem
Der API-Server wird zum Bottleneck, wenn zu viele Clients gleichzeitig teure Operationen ausfuehren: List-Requests ohne Label-Selector auf grosse Resourcen, zu viele Watch-Connections, oder Controller, die in einer Retry-Schleife haengen.
Diagnose
# API-Server Audit Logs auf langsame Requests pruefen
# (falls Audit Logging aktiviert ist)
kubectl logs -n kube-system kube-apiserver-master-0 --tail=100
# Aktuelle API-Server-Metriken
kubectl get --raw /metrics | grep apiserver_request_duration
Prometheus-Queries:
# API-Request-Latenz P99 nach Verb und Resource
histogram_quantile(0.99,
sum by (verb, resource, le) (
rate(apiserver_request_duration_seconds_bucket[5m])
)
)
# Anzahl aktiver Watch-Connections
apiserver_registered_watchers
# API-Server Request Rate
sum by (verb) (
rate(apiserver_request_total[5m])
)
# Abgelehnte Requests (Rate Limiting)
sum by (client) (
rate(apiserver_dropped_requests_total[5m])
)
Loesung
- List-Requests optimieren: Label-Selectors und Field-Selectors verwenden, um die Ergebnismenge einzuschraenken.
kubectl get pods -l app=frontendstattkubectl get pods. - Watch-Connections konsolidieren: Shared Informers in Custom Controllern verwenden statt individuelle Watches.
- API Priority and Fairness konfigurieren: Kubernetes bietet FlowSchemas und PriorityLevelConfigurations, um wichtige API-Calls zu priorisieren.
- Client-seitige Caching: Controller und Operatoren sollten Informer-Caches nutzen statt bei jedem Reconcile-Loop den API-Server abzufragen.
Weitere Troubleshooting-Tipps finden Sie in unserem Kubernetes Troubleshooting Guide.
Performance-Baseline-Checkliste
Bevor Sie Probleme diagnostizieren koennen, muessen Sie wissen, was normal ist. Diese Baseline-Checkliste hilft dabei:
| Metrik | Gesunder Wert | Warnung | Kritisch |
|---|---|---|---|
| CPU-Throttling-Rate | Unter 5% | 5-25% | Ueber 25% |
| Memory Working Set vs. Limit | Unter 70% | 70-85% | Ueber 85% |
| CoreDNS P99-Latenz | Unter 5ms | 5-50ms | Ueber 50ms |
| etcd WAL Sync P99 | Unter 10ms | 10-50ms | Ueber 50ms |
| API-Server P99-Latenz | Unter 200ms | 200ms-1s | Ueber 1s |
| Node CPU-Auslastung | 40-70% | 70-85% | Ueber 85% |
| PV IOPS-Auslastung | Unter 70% | 70-90% | Ueber 90% |
Richten Sie Alerting auf diese Metriken ein. Ein guter Startpunkt ist das Kubernetes Monitoring und Observability Setup.
Systematisches Vorgehen bei Performance-Problemen
Wenn ein Kubernetes Performance Problem gemeldet wird, gehen Sie in dieser Reihenfolge vor:
Schritt 1: Symptom eingrenzen. Ist das Problem global (alle Services betroffen) oder lokal (ein Service, ein Namespace)? Seit wann tritt es auf? Korreliert es mit einem Deployment oder einer Konfigurationsaenderung?
Schritt 2: Ressourcen-Layer identifizieren. Pruefen Sie CPU, Memory, Network und Storage in dieser Reihenfolge. Die meisten Probleme liegen bei CPU-Throttling oder Memory-Knappheit.
Schritt 3: Infrastructure vs. Application. Ist das Problem auf Kubernetes-Ebene (Node-Overcommitment, CNI, Storage) oder auf Application-Ebene (ineffiziente Queries, fehlende Caches, Memory Leaks)?
Schritt 4: Fix implementieren und validieren. Aenderungen einzeln vornehmen und die Auswirkung messen. Nicht mehrere Aenderungen gleichzeitig.
Schritt 5: Baseline aktualisieren. Nach dem Fix die Performance-Baseline neu definieren und Alerting anpassen.
Fazit
Kubernetes Performance Probleme sind loesbar, wenn man systematisch vorgeht. Die sechs Kategorien CPU, Memory, Network, Storage, etcd und API-Server decken die grosse Mehrheit aller Bottlenecks ab. Prometheus-basiertes Monitoring ist die Grundlage fuer jede Diagnose.
Der wichtigste Rat: Definieren Sie eine Performance Baseline, bevor das erste Problem auftritt. Ohne Baseline wissen Sie nicht, was normal ist, und koennen Abweichungen nicht zuverlaessig erkennen.
Verwandte Artikel
- Kubernetes Capacity Planning
- Kubernetes Monitoring und Observability
- CoreDNS Troubleshooting Guide
- Kubernetes Autoscaling und Kostenoptimierung
- Kubernetes CrashLoopBackOff Troubleshooting
Sie haben Performance-Probleme in Ihrem Kubernetes-Cluster und kommen mit der Diagnose nicht weiter? Wir analysieren Ihre Infrastruktur und identifizieren die Bottlenecks systematisch. Kontaktieren Sie uns unter /kontakt.
Kubernetes-Beratung gesucht?
Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.
📖 Verwandte Artikel
Weitere interessante Beiträge zu ähnlichen Themen
Kubernetes CPU Throttling finden und beheben
CPU-Throttling in Kubernetes erkennen und lösen. Limits richtig setzen, Performance-Engpässe mit Prometheus diagnostizieren und QoS-Klassen verstehen.
Kubernetes Incident Management: Runbooks erstellen
Effektive Runbooks für Kubernetes-Incidents erstellen: Vorlagen für CrashLoopBackOff, OOMKilled und Node-Ausfälle mit konkreten Debugging-Befehlen.
Prometheus Recording Rules für Kubernetes optimieren
Prometheus Recording Rules beschleunigen PromQL-Abfragen in Kubernetes. Konfiguration, Naming Conventions und praktische Beispiele.
Java Kubernetes OOMKilled: JVM Heap richtig setzen
Java-Pods werden auf Kubernetes mit OOMKilled (Exit Code 137) beendet. So setzt ihr JVM Heap, MaxRAMPercentage und Container-Limits korrekt für stabile Java-Workloads.
Kubernetes GPU-Auslastung optimieren: MIG und Time-Slicing
GPU-Auslastung in Kubernetes von 30% auf über 75% steigern mit MIG und Time-Slicing. NVIDIA GPU Operator Setup und DCGM Monitoring Anleitung.