Newsletter

    Newsletter abonnieren

    Neue Infrastruktur-Guides, Vergleichsberichte und Migrationshinweise direkt ins Postfach.

    Infrastruktur-Notizen, Guides und neue Tools. Jederzeit abbestellbar.

    Zurück zum Blog
    Kubernetes
    DevOps
    Infrastruktur

    Es funktioniert... Aber es fühlt sich falsch an - Der richtige Weg, einen Java-Monolithen auf Kubernetes zu betreiben, ohne sich den Kopf zu zerbrechen

    18. Februar 2026
    5 Min. Lesezeit

    „Es funktioniert… Aber es fühlt sich falsch an“ — Der richtige Weg, einen Java-Monolithen auf Kubernetes zu betreiben, ohne sich den Kopf zu zerbrechen

    Sie haben:

    • Ubuntu-Host
    • Apache2, das SSL übernimmt
    • kind-Cluster
    • Moqui + OpenSearch in Pods
    • MySQL auf dem Host
    • Service-Typ: NodePort
    • Apache als Reverse-Proxy zu 172.x.x.x:30083

    Und es funktioniert.

    Aber es fühlt sich zusammengeklebt an.

    Dieser Instinkt? Er ist richtig.

    Räumen wir das ordentlich auf — im Produktionsstil, selbstverwaltet, keine Cloud-Load-Balancer, keine Magie.


    1️⃣ NodePort + Apache-Reverse-Proxy — Ist das schlecht?

    Kurze Antwort:

    Für lokale Entwicklung? In Ordnung.

    Für Produktion? Fragil.

    Aktuell proxyt Apache zu einer internen kind-IP.

    Das ist brüchig, weil:

    • kind nicht für Produktion gedacht ist
    • Control-Plane-IPs keine stabilen Design-Grenzen sind
    • Sie das vorgesehene Ingress-Modell von Kubernetes umgehen

    Sie sagten, Sie wollen keine cloud-verwalteten Load Balancer und betreiben alles auf Ihrer eigenen Maschine. Das ist völlig in Ordnung.

    Das saubere, produktionsartige Setup auf Bare Metal sieht so aus:

    Empfohlene Architektur (selbstverwaltet)

    Internet
       ↓
    Apache (or Nginx) — TLS termination
       ↓
    Kubernetes Ingress Controller
       ↓
    Service (ClusterIP)
       ↓
    Pods
    

    Statt NodePort installieren Sie einen Ingress-Controller wie:

    • NGINX (nginx-ingress)
    • Traefik

    Dann:

    • Apache proxyt zum Ingress-Controller (nicht zu NodePort)
    • Oder noch besser: Apache ganz entfernen und TLS über den Ingress mit cert-manager handhaben lassen

    Wenn Sie vollständig selbstverwaltet auf einer einzigen Maschine bleiben, ist die einfachste saubere Version:

    • nginx-ingress installieren
    • hostNetwork oder MetalLB nutzen, falls Sie später auf mehrere Nodes skalieren
    • TLS am Ingress terminieren

    NodePort ist nicht „falsch“. Es ist nur Low-Level-Verrohrung. Ingress existiert, damit Sie nicht für immer manuell Ports verdrahten müssen.


    2️⃣ Autoscaling eines Java-Monolithen — Die harte Wahrheit

    Sie sehen:

    400–500 MB RAM pro Pod

    Skalierung von 1 → 3 Replicas = ~1,5 GB Arbeitsspeicher

    Ja.

    So funktioniert horizontales Skalieren.

    Kubernetes teilt den JVM-Heap nicht magisch zwischen Replicas.

    Jede Replica = vollständige JVM.

    Das ist kein Kubernetes-Problem. Das ist Java-Architektur.

    Aber hier können Sie optimieren.

    🧠 JVM-Tuning

    Wenn Sie nicht explizit setzen:

    -XX:MaxRAMPercentage
    -Xms
    -Xmx
    

    Kann die JVM überallozieren.

    Setzen Sie Speicherlimits in Kubernetes:

    resources:
      requests:
        memory: "512Mi"
      limits:
        memory: "512Mi"
    

    Stimmen Sie dann die JVM darauf ab, den Container-Speicher zu respektieren.

    Sonst nutzt Ihr Pod mehr Speicher, als Sie denken.


    ⚙ HPA-Strategie

    HPA funktioniert besser mit CPU als mit Speicher.

    Speicher-Skalierung ist träge. CPU-Skalierung reagiert schneller.

    Ihre Idee eines Ziels von 90 % CPU-Auslastung ist vernünftig.

    Aber die eigentliche Optimierungsfrage lautet:

    Wie viele gleichzeitige Requests kann ein Moqui-Pod handhaben?

    Messen Sie das. Das ist Ihre Skalierungseinheit.


    🚫 Die größere Frage

    Brauchen Sie 3 Replicas für Verfügbarkeit — in Ordnung.

    Brauchen Sie 3 Replicas für Traffic — in Ordnung.

    Aber skalieren Sie, weil der Speicher wegen Session-Storage wächst?

    Das ist Architektur-Smell.

    Das bringt uns zu Ihrem eigentlichen Schmerzpunkt.


    3️⃣ Sessions, Logs, Locks und PVC-Engpässe

    Sie erwähnten:

    • logs/
    • txlogs/
    • sessions/
    • Mehrere Replicas
    • RWX-PVC
    • LOCK-Probleme

    Das ist der eigentliche Blocker.

    Und es ist nicht die Schuld von Kubernetes.

    Es ist die Semantik gemeinsam genutzter Dateisysteme.

    Mehrere Java-Pods, die auf dasselbe RWX-Volume schreiben, verursachen definitiv Lock-Contention. Besonders bei Sessions.

    So lässt sich sauber darüber nachdenken:


    🔥 Sessions sollten NICHT auf der Disk liegen

    Disk-basierte Sessions skalieren nicht horizontal.

    Richtiges Produktions-Setup:

    Nutzen Sie Redis.

    • Externes Redis
    • Oder Redis in Kubernetes
    • Oder Redis-Cluster

    Der Session-Store wird zu einem zentralisierten In-Memory-Key-Value-Store.

    Kein File-Locking.

    Keine RWX-Probleme.

    Kein Nutzer-Logout beim Pod-Wechsel.

    Das ist der Industriestandard für die Skalierung von Java-Monolithen.


    📁 Logs sollten NICHT auf gemeinsam genutztem PVC liegen

    Logs gehen an stdout.

    Dann nutzen Sie:

    • Fluent Bit
    • Loki
    • ELK-Stack

    Das Kubernetes-Logging-Modell erwartet Logs auf stdout, nicht in gemeinsam genutzten Dateien.

    Wenn Sie Transaktions-Tracing brauchen, senden Sie Logs an zentralisiertes Logging — nicht auf gemeinsam genutzte Disk.


    📦 Statische Dateien / Uploads

    Jetzt trennen wir die Zuständigkeiten:

    • Sessions → Redis
    • Logs → zentralisiertes Logging
    • Uploads → Object Storage

    Object Storage ist ideal, weil:

    • Es replica-sicher ist
    • Kein Locking
    • Keine Datei-Korruption
    • Unabhängig skaliert

    Wenn Sie vollständig self-hosted sind, betreiben Sie:

    • MinIO (S3-kompatibel)
    • Oder NFS (aber NFS ist im Vergleich zu Object Storage Legacy)

    RWX-PVC ist hier die am wenigsten skalierbare Option.


    4️⃣ Sollte MySQL innerhalb von Kubernetes laufen?

    Sie betreiben MySQL derzeit auf dem Host.

    Das ist eigentlich in Ordnung.

    Datenbanken innerhalb von Kubernetes zu betreiben ist möglich (StatefulSet), bringt aber zusätzliche Komplexität:

    • Volume-Management
    • Backup-Orchestrierung
    • HA-Komplexität

    Wenn Sie auf einer einzelnen Bare-Metal-Maschine sind, ist es völlig vernünftig, MySQL außerhalb von Kubernetes zu behalten.

    Gehen Sie zu Multi-Node über, überdenken Sie das.


    5️⃣ Kubernetes über eine UI verwalten

    Ja.

    Sie können nutzen:

    • Lens
    • Kubernetes Dashboard
    • Portainer

    Lens bietet mit Abstand das sauberste Erlebnis für die Remote-Cluster-Verwaltung.

    Sie laden einfach die kubeconfig herunter und verbinden sich.

    Kein Grund, sich auf fragile NodePort-Freigabe zu verlassen.


    Die echte Produktionsform für Ihren Fall

    Da Sie self-hosted auf lokaler Hardware sind und volle Kontrolle wollen:

    Saubere Architektur

    • Bare-Metal-Server
    • Richtige Kubernetes-Distribution (nicht kind) RKE2, Talos, k3s usw.
    • nginx-ingress installiert
    • TLS am Ingress gehandhabt
    • Moqui-Pods (kein gemeinsam genutztes Dateisystem für Sessions)
    • Redis für Sessions
    • Object Storage (MinIO) für Uploads
    • MySQL entweder außerhalb von k8s oder als StatefulSet
    • Zentralisiertes Logging

    Kein NodePort.

    Keine Control-Plane-IP-Abhängigkeiten.

    Keine RWX-Locks.


    Die harte, aber ehrliche Einschätzung

    Sie stecken nicht wegen Kubernetes fest.

    Sie stecken fest, weil Monolithen gemeinsam genutzte Disk erwarten.

    Kubernetes erwartet zustandslose Pods.

    Sobald Sie verschieben:

    • Sessions → Redis
    • Logs → stdout
    • Uploads → Object Storage

    Wird Skalieren langweilig.

    Und langweilig ist gut.

    Aktuell funktioniert Ihre Architektur.

    Aber sie ist eng an ein Single-Machine-Denkmodell gekoppelt.

    Kubernetes glänzt, wenn Sie die Dateisystem-Kopplung entfernen.

    Das ist der Schlüssel.