Phillip, Kubernetes-Betrieb bei Pexon Consulting | 10 Min. Lesezeit | 16.09.2026
TL;DR: spring boot speicher kurz erklärt
Spring Boot Speicher auf Kubernetes ist keine -Xmx-Folie. Der Heap bleibt unter dem Container-Limit, Requests kommen aus Messung, Liveness trifft nicht die Datenbank. Pexon Consulting schneidet das bei Java-Teams, die Limits aus dem Docker-Host übernommen haben. Exit 137 ist dann kein Rätsel. Es ist die Differenz zwischen Heap und Native.
| Zahl | Rolle | Typischer Fehler |
|---|---|---|
requests.memory |
Scheduling | fehlt oder gleich dem Limit |
limits.memory |
OOM-Kante | gleich -Xmx |
MaxRAMPercentage |
Heap-Anteil | 90 Prozent, Native erstickt |
| Liveness | Prozess leben | /actuator/health inkl. DB |
Das Problem: Ready, dann 137
Der Pod war fünf Minuten Ready. Dann Exit 137, Reason OOMKilled. Das Deployment zieht nach. Dieselbe YAML. Dieselbe Zahl. Freitagabend.
Teams kopieren 2Gi aus dem alten Docker-Host. Dort war der Host die Grenze. Im Cluster ist das Limit die Grenze. Daneben sitzen Metaspace, Direct Buffer, Thread-Stacks, die Agent-Attach. Spring Boot 4.1.1 (20.08.2026) ändert diese Rechnung nicht.
Dieser Text ist der Speicher-Schnitt. Der ganze App-Pfad inkl. Shutdown steht im Cluster Review. Die generische Härtung steht in der Checkliste. Hier bleibt Heap gegen Limit.
Wir raten davon ab, zuerst das Image-Tag zu drehen. Erst die letzte Zahl lesen.
1. Was der Container wirklich frisst
Die kurze Antwort: Der Heap ist nur ein Teil. Das Limit gilt für alles.
UseContainerSupport ist seit Java 10 Default. Die JVM sieht cgroup-Memory. Trotzdem setzen viele -Xmx2048m neben limits.memory: 2Gi. Der Heap füllt. Native braucht den Rest. Kubernetes schickt SIGKILL. Spring sieht keinen Heap-Dump, weil der Prozess tot ist.
# Letzter Lauf, Exit und Reason
kubectl describe pod -n shop -l app=shop-api
kubectl logs deploy/shop-api -n shop --previous --tail=80
# Was der Node gerade sieht, nicht was die YAML behauptet
kubectl top pod -n shop -l app=shop-api
Drei Muster kommen in Reviews am häufigsten. Heap gleich Limit. Limit ohne Request. Request aus dem Bauch, weil niemand top gemacht hat.
Unsere klare Empfehlung: erst messen, dann die YAML anfassen. Ein geratenes Limit ist teurer als ein Nachmittag Messung.
2. Eine Rechnung, die aufgeht
Die kurze Antwort: 75 Prozent vom Limit für den Heap sind ein Start, kein Dogma.
resources:
requests:
memory: "768Mi"
cpu: "250m"
limits:
memory: "1536Mi"
env:
- name: JAVA_TOOL_OPTIONS
value: "-XX:MaxRAMPercentage=75.0 -XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError"
ExitOnOutOfMemoryError macht den Heap-OOM sichtbar, bevor der Node killt. Der Dump liegt nur, wenn das Volume ihn überlebt. Ohne Volume ist die Flagge Theater.
Wir raten von MaxRAMPercentage=90 ab. Zehn Prozent für Native reichen bei Actuator, Micrometer und einem JDBC-Pool oft nicht. Lieber Limit hoch oder Heap runter als beides auf Anschlag.
CPU-Limits sind die zweite Falle. Ein niedriges CPU-Limit drosselt den GC. Der Heap füllt langsamer, die Pause wird länger, die Liveness schlägt an. Dann sieht es aus wie ein App-Bug.
3. Probe und Speicher hängen zusammen
Die kurze Antwort: Eine Liveness auf die Datenbank macht aus einem vollen Heap einen Restart-Sturm.
Wenn der Heap voll ist, werden Queries langsam. Health inkl. DB wird rot. Kubernetes killt. Der nächste Pod startet kalt, füllt den Heap, dieselbe Probe. Das ist kein Cluster-Fehler. Das ist eine vermischte Verantwortung.
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
periodSeconds: 10
startupProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
failureThreshold: 36
periodSeconds: 10
36 mal 10 Sekunden sind sechs Minuten Boot. Spring Boot mit Hibernate und einer großen Schema-Prüfung braucht das oft. Wer Liveness ohne startupProbe scharf schaltet, killt den Start.
Kubernetes 1.37.0 (26.08.2026) hat daran nichts Neues erfunden. startupProbe ist der Schnitt, den Java-Teams am häufigsten weglassen.
4. Was das für das Team heißt
Die kurze Antwort: Speicher ist App-Arbeit. RBAC bleibt Cluster-Arbeit. Beides fehlt oft zusammen.
Kleine Softwareteams, oft Töchter, haben den Host verlassen, weil die Datenbank wuchs. Im Cluster bleibt eine YAML mit 2Gi und cluster-admin. Der Heap-Schnitt ist der Einstieg, den Entwickler selbst setzen können. Der Cluster-Schnitt (RBAC, Network Policies) braucht jemand, der Kubernetes wirklich schneidet.
Red Hat 2024 (600 Personen, USA/UK/APAC): 67 Prozent haben Deployments wegen Security verzögert. Speicher ist kein Security-Thema. Aber derselbe Cluster, der OOM restartet, hat oft auch keine Policy. Wer nur den Heap hebt und den Admin-Zugang lässt, hat Freitag gerettet und Montag offen.
CNCF (20.01.2026) nennt 82 Prozent produktive Kubernetes-Nutzung unter Container-Nutzern. Produktiv und dimensioniert sind zwei Sätze.
CPU ist der Nachbar, den niemand auf der Speicherfolie hat. Ein CPU-Limit von 200m bei einer App, die beim Start Hibernate und Flyway dreht, verlängert den Boot. Die startupProbe läuft in die Kappe. Kubernetes killt. Der nächste Start ist kälter, weil der Node throttle. Dann sieht es aus wie ein Speicherproblem. Es ist ein CPU-Limit, das den GC und den Boot erstickt.
Wir raten davon ab, CPU-Limits aus dem Bauch zu setzen, solange niemand kubectl top über eine Woche hat. Requests ja, damit der Scheduler plant. Limits erst, wenn Throttle-Daten da sind. Guaranteed (Request gleich Limit) ist eine QoS-Klasse, keine Speicherstrategie.
# Ob der Node drosselt, nicht nur ob 137 kommt
kubectl get --raw "/api/v1/nodes/${NODE}/proxy/metrics" | grep -E 'container_cpu_cfs|container_memory_working_set' | head
Native Memory bleibt die dunkle Hälfte. Direct Buffer in Netty, Metaspace nach vielen Redeploys, Thread-Stacks bei 200 Tomcat-Threads, ein Java-Agent. -XX:MaxDirectMemorySize und eine Thread-Zahl, die zum Limit passt, sind langweiliger als Heap-Prozent. Sie entscheiden, ob 75 Prozent vom Limit reichen.
Ein Heap-Dump ohne Volume ist weg, sobald der Pod stirbt. emptyDir mit Größenkappe oder ein PVC nur für Dumps. Sonst ist HeapDumpOnOutOfMemoryError Theater. Wir haben das in Reviews gesehen: Flagge an, Volume fehlt, 137 bleibt ein Bauchgefühl.
Spring Boot 3.5 ist seit dem 30.06.2026 ohne OSS-Patches. Ein unpatchtes Image mit richtigem Heap ist trotzdem ein Risiko. Nur ein anderes. Kubernetes 1.37.0 (26.08.2026) ändert die cgroup-Rechnung nicht.
Was wir in der ersten Stunde eines Reviews tun, ist langweilig und reicht oft. describe auf den sterbenden Pod. --previous auf die Logs. top auf den Namespace. Heap-Prozent gegen Limit rechnen. Probe-Pfad lesen. Wenn Liveness /actuator/health ist, ist der Restart erklärt, bevor jemand den Dump öffnet. Wenn Heap gleich Limit ist, auch.
Ein zweiter Durchgang kommt nur, wenn 137 ohne volle Heap bleibt. Dann Native: Direct Buffer, Threads, Agent. Dann CPU-Throttle. Dann erst das Image-Tag. Teams drehen das Image zuerst, weil es sich nach Handlung anfühlt. Handlung ohne Zahl ist ein neuer Tag auf derselben YAML.
Für Entwicklungsleiter reicht eine Regel: keine Speicher-Änderung ohne Messung aus den letzten sieben Tagen. Nicht aus dem Docker-Host. Nicht aus dem Bauch. Nicht aus einem Blog-Beispiel, auch nicht aus diesem. 768Mi Request und 1536Mi Limit oben sind ein Startbild. Ihre App hat andere Zahlen, sobald Hibernate, Caches und der JDBC-Pool mitzählen.
Die CNCF-Zahl vom 20.01.2026 (82 Prozent produktive Nutzung) erklärt nicht, warum Pods nachts sterben. Sie erklärt nur, dass der Cluster schon als Produktiv gilt. Red Hat 2024 (600 Personen, USA/UK/APAC) spricht Security, nicht Heap. Derselbe Cluster, der OOM restartet, hat oft auch keine Policy. Wer nur den Heap hebt, hat Freitag gerettet. Montag bleibt cluster-admin das CI. Den Cluster-Teil lassen wir im Review, nicht in dieser YAML. Zwei Sätze Messung, eine YAML, dann schlafen.
Häufig gestellte Fragen
Was kostet es, Spring Boot Speicher auf Kubernetes richtig zu setzen?
Der Schnitt selbst ist YAML und Messung, kein Lizenzprodukt. Wenn niemand im Team die Zahlen liest, ist der Einstieg der Cluster-Check in 45 Minuten. Das Assessment liegt typisch bei 5.000 EUR je Cluster.
Heap-Dump oder nur `kubectl top`: was zuerst?
Zuerst describe und top. Der Dump kommt, wenn 137 bleibt und Native vs. Heap unklar ist. Ohne Volume ist der Dump weg.
Requests gleich Limits: ist das Guaranteed nicht besser?
Guaranteed verhindert Nachbarn. Es verhindert nicht OOM, wenn Heap gleich Limit ist. Erst die Differenz, dann die QoS-Klasse.
Warum stirbt der Pod, obwohl `-Xmx` frei ist?
Weil Native, Metaspace oder Direct Buffer das Limit füllen. -Xmx ist nicht der Container.
Spring Boot 3.5 und Speicher: zählt die Version?
3.5 ist seit dem 30.06.2026 ohne OSS-Patches. Der Speicher-Schnitt ist derselbe. Ein unpatchtes Image mit richtigem Heap ist trotzdem ein Risiko, nur ein anderes.
Nächster Schritt
Verwandte Themen
→Kubernetes-Härtung ohne Java-Fokus
→VMs nach Kubernetes



