---
title: "Spring Boot auf SKE mit PostgreSQL Flex und Gateway API"
description: "Spring-Boot-Replatform mit SKE, PostgreSQL Flex, Gateway API, DNS und Observability entwerfen und die getestete Basis von künftigen Erweiterungen klar trennen."
scfAsset:
  managed: false
  category: 'blueprint'
  external: false
  tags: ["design-and-mobilize", "design", "target-architecture", "replatform", "kubernetes", "postgresql", "object-storage", "spring-boot"]
  maintainers:
    - user: "lukas.weberruss"
      role: true
      website: true
source_url: "https://framework.stackit.cloud/de/migration/assetcontainer/stackit/architecture-spring-boot-kubernetes-paas-data-object-storage/"
source_file: "docs/de/migration/assetcontainer/stackit/architecture-spring-boot-kubernetes-paas-data-object-storage.mdx"
---

## Überblick

Diese Architektur überführt die VM-basierte Spring-Boot- und PostgreSQL-Quelle in eine
Kubernetes-Laufzeit mit Managed-Datenbank auf STACKIT. Dasselbe Anwendungs-JAR bleibt erhalten,
während sich Bereitstellung, Deployment, Traffic-Steuerung, Daten-Recovery und Betriebsverantwortung ändern.

Die Referenzbasis verwendet einen SKE-Worker und PostgreSQL Flex mit Envoy Gateway,
STACKIT DNS und Observability. Die zusätzlichen Dienste und die Multi-Zonen-Topologie
des nachfolgenden optionalen Erweiterungsmusters werden nicht bereitgestellt.

## Einsatz

- **Laufzeit standardisieren**: Einen systemd-verwalteten Java-Prozess durch ein reproduzierbares Deployment mit Zustandsprüfungen ersetzen.
- **Datenbankbetrieb verlagern**: PostgreSQL in einen Managed Service überführen, ohne das Anwendungsschema neu zu entwerfen.
- **Plattformwechsel kontrollieren**: Rollout, Skalierung, Netzwerkzugriff und Recovery vor der Produktionsabnahme unabhängig qualifizieren.

## Architekturdiagramm

```d2
direction: right

Source: "Quell-VM" {
  App: "Spring-Music-JAR + systemd"
  DB: "Selbstverwaltetes PostgreSQL"
  App -> DB: "lokales SQL"
}
Evidence: "Freigegebener Dump + Manifest"
Users: "Anwendungsclients"
Target: "STACKIT Anwendungsprojekt" {
  DNS: "STACKIT DNS"
  SKE: "SKE: Ein-Worker-Referenz" {
    Gateway: "Envoy Gateway + HTTPRoutes"
    Service: "ClusterIP Service"
    App: "Dasselbe JAR auf Java 11"
    Metrics: "Boot-2-Adapter + PG-Exporter"
    Client: "Temporärer Migrationsclient"
    ExternalDNS: "Managed ExternalDNS"
    Gateway -> Service -> App
    ExternalDNS -> Gateway: "Routenhostnamen beobachten" {style.stroke-dash: 3}
  }
  Flex: "PostgreSQL Flex" {
    AppDB: "springmusic"
    Rehearsal: "springmusic_rehearsal"
  }
  Obs: "Observability + Grafana"
  SKE.App -> Flex.AppDB: "JDBC / TLS"
  SKE.Client -> Flex.Rehearsal: "Probe / Backup nachweisen"
  SKE.Client -> Flex.AppDB: "freigegebener Cutover / Rollback"
  SKE.Metrics -> Flex.AppDB: "Datenbankmetriken / TLS"
  SKE.ExternalDNS -> DNS: "Gateway-Adresse veröffentlichen"
  Obs -> SKE.Metrics: "Scrape über Gateway 9090 / 9187"
}
Source.DB -> Evidence: "Schreibstopp / Export / Prüfung"
Evidence -> Target.SKE.Client: "geschützte Übertragung über kubectl"
Users -> Target.DNS: "Hostnamen auflösen"
Users -> Target.SKE.Gateway: "HTTP-Basis; HTTPS optional"
```

## Laufzeit- und Datengrenzen

Ein Init-Container prüft die Prüfsumme des auf einen Commit fixierten JARs, bevor Java startet.
Anwendungscontainer sind austauschbar: Die maßgeblichen Albumdaten liegen in PostgreSQL Flex,
nicht im Pod-Dateisystem oder auf einem Kubernetes PersistentVolume. Kubernetes Secrets liefern
Datenbankzugangsdaten; eine externe Secret-Manager-Integration ist in dieser Basis nicht implementiert.

Die Flex-ACL verwendet standardmäßig die tatsächlichen SKE-Egress-CIDRs. Anwendung und
Migrationsclient benötigen verschlüsselte Datenbankverbindungen. Der Migrationsclient verwendet
eine isolierte Probedatenbank und ersetzt Anwendungsdaten erst nach expliziter Freigabe und
verifiziertem Backup vor dem Cutover. Für den dumpbasierten Pfad sind weder eine Verbindung
zur Datenbank der Quell-VM noch eine temporäre öffentliche Flex-ACL nötig.

## Netzwerkverkehr und Observability

Terraform installiert Envoy Gateway und anschließend ein lokales Routing-Chart. Der
Anwendungs-Service ist vom Typ ClusterIP; Envoy stellt den öffentlichen LoadBalancer bereit.
SKE-verwaltetes ExternalDNS veröffentlicht den HTTPRoute-Hostnamen anhand der Gateway-Adresse.
Dies ist Gateway API, kein älterer Ingress-Controller und kein separat bereitgestellter
STACKIT Application Load Balancer Service.

HTTP ist der getestete Standard. Stellen Sie für HTTPS ein vertrauenswürdiges TLS-Secret bereit
und konfigurieren Sie `gateway_tls_secret_name` nach dem Repository-Verfahren. Ausstellung und
Erneuerung von Zertifikaten bleiben externe Aufgaben. Die separaten Metrik-Listener sind in der
Referenz öffentlich und ohne Authentifizierung erreichbar; schützen Sie sie vor sensibler Nutzung.

Boot 2 Actuator bindet an das pod-lokale Loopback; der Metrikadapter veröffentlicht ausgewählte
Messwerte. PostgreSQL-Exporter und SKE-Monitoring-Integration beliefern Observability.
Terraform erstellt Grafana-Ordner und Dashboard. Dessen Verfügbarkeit allein weist jedoch
weder Anwendungszustand noch durchgängiges Scraping oder funktionierende Alarmzustellung nach.

## Entscheidungen zu Verfügbarkeit und Recovery

Die getestete Worker-Anzahl, der HTTP-Endpunkt und die Beispielanwendung bilden eine funktionale
Basis, keine hochverfügbare Produktionsarchitektur. Wählen Sie eine unterstützte SKE-Version
und passende Zonenkapazität. Bewerten Sie mehrere Worker, Zonenverteilung, Disruption Budgets,
Replikasicherheit, Datenbankverfügbarkeit und das Traffic-Routing als separate Designentscheidungen mit Ausfalltests.

Der Datenbank-Rollback stellt das Ziel vor dem Cutover wieder her; Managed-Flex-Backups dienen
der Service-Recovery. Keiner der beiden Wege leitet Benutzer automatisch zur Quell-VM zurück.
Definieren Sie Schreibverantwortung, Befugnis zur Traffic-Umschaltung, Rollback-Deadline,
Aufbewahrung und Recovery-Ziele vor der Migration.

## Optionales Erweiterungsmuster

Das folgende umfassendere Design zeigt mögliche Ergänzungen, keine vom Referenz-Terraform
erstellten Ressourcen. Weitere Node Pools, Topologieregeln, persistente Volumes, RabbitMQ,
Object Storage und Secret Manager benötigen eigene Implementierung, Verantwortlichkeiten und
Validierung. Nutzen Sie sie nur bei nachgewiesener Workload-Anforderung; leiten Sie aus dem Diagramm keine Hochverfügbarkeit ab.

```d2
vars: {
  d2-config: {
    pad: 32
  }
}

style.font-size: 22

direction: down
grid-columns: 1

Internet: "Internet" {
  icon: ../../../../../../../public/stackit-icons/networking/ip.svg
  link: https://docs.stackit.cloud/products/network/core-networking/
}

SKEProject: "Anwendungsprojekt" {
  direction: down
  grid-columns: 1

  Access: "Zugriff" {
    direction: right
    grid-columns: 2

    ExternalLB: "Externer Load Balancer" {
      icon: ../../../../../../../public/stackit-icons/networking/application-load-balancer.svg
      link: https://docs.stackit.cloud/products/network/load-balancing-and-content-delivery/application-load-balancer/
    }

    DNS: "DNS" {
      icon: ../../../../../../../public/stackit-icons/networking/dns.svg
      link: https://docs.stackit.cloud/products/network/core-networking/dns/
    }
  }

  Kubernetes: "Kubernetes (SKE)" {
    link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
    icon: ../../../../../../../public/stackit-icons/runtime/kubernetes.svg
    direction: down
    grid-columns: 1

    EntryLayer: "Zugangsebene" {
      direction: right
      grid-columns: 2

      Ingress: "Gateway API" {
        icon: ../../../../../../../public/stackit-icons/networking/application-load-balancer.svg
        link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
      }

      ExternalDNS: "ExternalDNS" {
        icon: ../../../../../../../public/stackit-icons/networking/dns.svg
        link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
      }
    }

    ServiceLayer: "Service-Ebene" {
      direction: right

      K8sService: "K8s Service" {
        icon: ../../../../../../../public/stackit-icons/networking/network.svg
        link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
      }
    }

    WorkloadLayer: "Workload-Ebene" {
      WorkloadRow: "" {
        direction: right

        Deployment: "Deployment" {
          link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
          grid-columns: 2

          PodA: "Pod A" {
            icon: ../../../../../../../public/stackit-icons/runtime/kubernetes.svg
            link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
          }

          PodB: "Pod B" {
            icon: ../../../../../../../public/stackit-icons/runtime/kubernetes.svg
            link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
          }
        }

        HPA: "HPA" {
          icon: ../../../../../../../public/stackit-icons/runtime/kubernetes.svg
          link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
        }
      }
    }

    PlatformLayer: "Plattformebene" {
      direction: right

      Compute: "" {
        direction: right

        NodePoolA: "Node Pool AZ-1" {
          link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
          grid-columns: 2

          VM1: "VM" {
            icon: ../../../../../../../public/stackit-icons/computing/virtual-machine.svg
            link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
          }
        }

        NodePoolB: "Node Pool AZ-2" {
          link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
          grid-columns: 2

          VM2: "VM" {
            icon: ../../../../../../../public/stackit-icons/computing/virtual-machine.svg
            link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
          }
        }

        NodeAutoscaler: "Node Autoscaler" {
          icon: ../../../../../../../public/stackit-icons/runtime/kubernetes.svg
          link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
        }
      }

      Storage: "Persistenter Speicher" {
        link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
        grid-columns: 2

        PV1: "PV" {
        icon: ../../../../../../../public/stackit-icons/computing/archive.svg
        link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/

        }

        PV2: "PV" {
          icon: ../../../../../../../public/stackit-icons/computing/archive.svg
          link: https://docs.stackit.cloud/products/runtime/kubernetes-engine/
        }
      }
    }

  }

}

Backend: "Backend-Dienste" {
  direction: right
  grid-columns: 5

  PG: "PostgreSQL" {
      icon: ../../../../../../../public/stackit-icons/databases/postgresql-flex.svg
      link: https://docs.stackit.cloud/products/databases/postgresql-flex/
  }

  Rabbit: "RabbitMQ" {
      icon: ../../../../../../../public/stackit-icons/messaging/rabbit-mq.svg
      link: https://docs.stackit.cloud/products/messaging/rabbitmq/
  }

  Obj: "Object Storage" {
      icon: ../../../../../../../public/stackit-icons/computing/object-storage.svg
      link: https://docs.stackit.cloud/products/storage/object-storage/
  }

  Secrets: "Secret Manager" {
      icon: ../../../../../../../public/stackit-icons/security/secrets-manager.svg
      link: https://docs.stackit.cloud/products/security/secrets-manager/
  }

  Obs: "Observability" {
      icon: ../../../../../../../public/stackit-icons/logging-monitoring/observability.svg
      link: https://docs.stackit.cloud/products/logging-and-monitoring/observability/
  }
}

SKEProject.Kubernetes.ServiceLayer -> SKEProject.Kubernetes.WorkloadLayer: { style.opacity: 0 }

Internet -> SKEProject.Access.ExternalLB
Internet -> SKEProject.Access.DNS
SKEProject.Access.DNS -> SKEProject.Kubernetes.EntryLayer.ExternalDNS
SKEProject.Access.ExternalLB -> SKEProject.Kubernetes.EntryLayer.Ingress
SKEProject.Kubernetes.EntryLayer.Ingress -> SKEProject.Kubernetes.ServiceLayer.K8sService
SKEProject.Kubernetes.ServiceLayer.K8sService -> SKEProject.Kubernetes.WorkloadLayer.WorkloadRow.Deployment
SKEProject.Kubernetes.WorkloadLayer -> SKEProject.Kubernetes.PlatformLayer
SKEProject.Kubernetes -> Backend

SKEProject.Kubernetes.PlatformLayer.Compute.NodePoolA -> SKEProject.Kubernetes.PlatformLayer.Compute.NodeAutoscaler: { style.opacity: 0 }
```

## Designprinzipien

- **Freigaben für Laufzeit und Datenmigration entkoppeln**: Datenbankmigration und Laufzeit-Rollout unabhängig validieren.
- **Secret-Bereitstellung explizit entwerfen**: Die Referenz nutzt Kubernetes Secrets und geschützten Terraform-State; bei Bedarf eine geprüfte externe Secret-Integration ergänzen.
- **Observability-Labels und Dashboards standardisieren**: Betrieb und Incident-Behandlung über Anwendungen hinweg vereinheitlichen.
- **RabbitMQ bewusst optional halten**: Nur bei Bedarf an asynchroner Integration oder Pufferung ergänzen.
- **Verfügbarkeit separat qualifizieren**: Ein Multi-Zonen-Design benötigt geeignete Worker-Kapazität, Platzierungsregeln, Disruption Budgets und Ausfalltests für Anwendung und Datenbank; die Basis aktiviert dies nicht.

## Weiterführendes

<LinkCard
  title="Spring Boot mit Terraform auf eine neue Plattform umstellen"
  description="Den ausführbaren Workflow für Bereitstellung, Quellnachweise, Probe, Cutover und Rollback dieser Architektur nutzen."
  href="/de/migration/assetcontainer/stackit/replatform-automation-spring-boot-vm-to-kubernetes-terraform/"
/>

## Repository

<LinkCard
  title="STACKIT CMF Replatform Spring Boot Kubernetes Repository"
  href="https://github.com/stackitcloud/stackit-cmf-replatform-springboot-k8s"
/>

1. Datei aus dem Beispiel kopieren: `cp env.tfvars.example env.tfvars`
2. Erforderliche Werte für Identität und Projekt setzen:

```hcl
service_account_key_path    = "/path/to/stackit-sa-key.json"
create_project              = true
target_project_owner_email  = "owner@sa.stackit.cloud"
parent_container_id         = "cmf-parent-container-id"
ske_cluster_name            = "rpltfk8s01"
observability_instance_name = "cmf-rpltf-observability"
dns_zone_name               = "cmf-example.runs.onstackit.cloud"
dns_zone_display_name       = "cmf-example"
```

3. Zielarchitektur-Flags setzen:

```hcl
observability_enabled         = true
create_observability_instance = true
dns_enabled                   = true
create_dns_zone               = true
deploy_workload               = true
enable_postgres_flex          = true
enable_springboot_hpa         = false
enable_load_generator         = false
springboot_replicas           = 1
deploy_postgres_migration_job = false
create_grafana_dashboard     = true
```

4. Optionaler CMF-Flag-Wrapper (`flags.env`):

```dotenv
setup_project=true
setup_observability=true
setup_database=true
setup_workload=true
setup_loadgen=false
setup_dns=true
```

5. Ausführen:

```bash
terraform init
terraform validate
terraform plan -var-file=env.tfvars -out=tfplan
terraform apply tfplan
```

Erwartetes Ergebnis: `springboot_url` erreicht die Anwendung über das Gateway, die Anwendung
nutzt PostgreSQL Flex und `grafana_dashboard_url` öffnet das verwaltete Dashboard. Die
Bereitstellung importiert keine Quelldaten. Führen Sie nach der Zielvalidierung den separaten
Probe- und Cutover-Workflow aus; lassen Sie HPA während der gesamten Migration deaktiviert.

<LinkCard
  title="Implementierte Topologie und Voraussetzungen"
  description="Genaue Ressourcendefinitionen und betriebliche Grenzen im Spring-Boot-Replatform-Repository prüfen."
  href="https://github.com/stackitcloud/stackit-cmf-replatform-springboot-k8s#readme"
/>
