Von der ersten App zur Produktionsplattform: Datenbanken, HTTPS und Autoscaling auf ITSH
Von der ersten App zur Produktionsplattform
Dein erster Container läuft auf Kubernetes. Ein Deployment, ein Service, eine HTTPRoute, fertig. Aber eine produktionsreife Anwendung braucht mehr: eine Datenbank, HTTPS mit automatischen Zertifikaten, persistenten Speicher und die Fähigkeit, unter Last zu skalieren.
Auf einem selbst betriebenen Cluster bedeutet das Tage an Konfiguration. Auf einem ITSH-Namespace sind es ein paar YAML-Dateien.
Dieser Artikel zeigt, was die Plattform über das einfache Container-Deployment hinaus bietet, und warum du dafür keinen Cluster-Admin brauchst.
Automatisches HTTPS mit Let’s Encrypt
Auf einem selbst verwalteten Cluster sieht der Weg zu HTTPS so aus: cert-manager installieren, ClusterIssuer konfigurieren, Ingress-Controller anpassen, Annotations debuggen. Auf ITSH ist cert-manager bereits installiert und vorkonfiguriert. Du setzt an deiner HTTPRoute eine Annotation, um automatisches TLS zu aktivieren:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: myapp
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
parentRefs:
- name: default
namespace: nginx-gateway
sectionName: https-myapp-example-com
hostnames:
- "myapp.example.com"
rules:
- backendRefs:
- name: myapp
port: 80
Das TLS-Zertifikat wird automatisch provisioniert. Kein manuelles Eingreifen, kein Renewal-Monitoring.
Die Annotation ist dabei reines Opt-in: Der Controller, der die Gateway-Listener anlegt, prüft nur, ob sie vorhanden ist. Ihr Wert wählt keinen Issuer aus. Welcher ClusterIssuer die Zertifikate ausstellt, legt die Annotation am Gateway selbst fest.
HTTP → HTTPS Redirect
Damit HTTP-Anfragen automatisch auf HTTPS umgeleitet werden, fügst du eine zweite HTTPRoute hinzu:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: myapp-redirect
spec:
parentRefs:
- name: default
namespace: nginx-gateway
sectionName: http
hostnames:
- "myapp.example.com"
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
backendRefs: []
DNS einrichten
Zeige deine Domain auf den Cluster-Ingress:
- A-Record:
91.98.6.3 - AAAA-Record:
2a01:4f8:1c1f:7bfa::1
Das Gateway setzt X-Forwarded-For und X-Real-IP mit der originalen Client-IP. Konfiguriere deine Anwendung so, dass sie diese Header ausschließlich von der Gateway-Adresse akzeptiert, die dir im Kundenportal angezeigt wird. Akzeptiert sie die Header von beliebigen Absendern, kann jeder Client seine IP fälschen.
Zwei YAML-Dateien, ein DNS-Eintrag, und deine App ist per HTTPS erreichbar mit automatischer Zertifikatsverlängerung.
Managed Datenbanken
PostgreSQL mit CloudNativePG
CloudNativePG läuft auf dem Cluster und verwaltet PostgreSQL-Instanzen als Kubernetes-Ressource. Eine Datenbank erstellen:
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: myapp-db
spec:
instances: 1
storage:
size: 10Gi
storageClass: hcloud-volumes
postgresql:
parameters:
max_connections: "100"
Der Operator erstellt automatisch ein Secret myapp-db-app mit dem Connection-String. In deinem Deployment referenzierst du es direkt:
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: myapp-db-app
key: uri
10 Zeilen YAML für eine lauffähige PostgreSQL-Instanz mit persistentem Storage. Auf einem eigenen Cluster müsstest du den Operator installieren, Storage Classes konfigurieren und Backup-Policies definieren.
Das Beispiel ist ein Startpunkt, keine produktionsreife Datenbank: eine einzelne Instanz ohne Backup-Konfiguration. Für den Produktionsbetrieb setzt du instances auf mindestens 3 und hinterlegst unter backup ein Ziel (etwa einen S3-Bucket) samt Aufbewahrungsdauer.
Redis-kompatibler Cache mit Dragonfly
Für Caching oder Session-Storage:
apiVersion: dragonflydb.io/v1alpha1
kind: Dragonfly
metadata:
name: myapp-cache
spec:
replicas: 1
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
Erreichbar unter redis://myapp-cache:6379. Dragonfly spricht das Redis-Protokoll, die meisten bestehenden Redis-Clients funktionieren damit unverändert. Es gibt allerdings dokumentierte Unterschiede im Verhalten einzelner Kommandos, teste deine Anwendung also vor dem Umzug.
Zusätzlich steht MariaDB als Datenbank-Option zur Verfügung, falls deine Anwendung MySQL-Kompatibilität benötigt.
Persistenter Speicher und Object Storage
Block Storage für Datenbanken und Einzelpod-Apps
Für Workloads, die schnellen, dedizierten Speicher brauchen:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myapp-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: hcloud-volumes
resources:
requests:
storage: 20Gi
hcloud-volumes liefert SSD-basierten Block Storage von Hetzner Cloud. Ideal für Datenbanken und Anwendungen mit einem Pod. Die Storage Class steht nur in bezahlten Namespaces zur Verfügung. Im Free Tier nutzt du nfs-rwx. Volumes können auch automatisch skalieren, wenn der Speicherbedarf wächst. Für Multi-Pod-Szenarien mit gemeinsam genutztem Dateisystem steht zusätzlich NFS-Storage (ReadWriteMany) zur Verfügung.
S3 Object Storage
Für S3-kompatiblen Object Storage erstellst du ein Secret mit deinen Zugangsdaten und referenzierst es im Deployment:
env:
- name: S3_ENDPOINT
valueFrom:
secretKeyRef:
name: s3-credentials
key: endpoint
- name: S3_BUCKET
valueFrom:
secretKeyRef:
name: s3-credentials
key: bucket
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: s3-credentials
key: access_key
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: s3-credentials
key: secret_key
Funktioniert mit jedem S3-kompatiblen SDK: AWS SDK, MinIO Client, Boto3. Ideal für Uploads, Media-Dateien und Backups.
Autoscaling
Horizontal Pod Autoscaler
Deine Anwendung soll bei Lastspitzen automatisch skalieren und danach wieder herunterfahren? Ein HPA reicht:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
Bei 70% CPU-Auslastung skaliert Kubernetes automatisch hoch, bis maximal 10 Replicas. Sinkt die Last, wird zurückskaliert.
Für fortgeschrittene Szenarien (Skalierung basierend auf Queue-Länge, HTTP-Requests oder Prometheus-Metriken) steht KEDA (Kubernetes Event-Driven Autoscaling) zur Verfügung.
Storage Autoscaling
Auch Block-Storage-Volumes können automatisch skalieren. Wenn deine Datenbank über ihre anfängliche Größe hinauswächst, musst du nicht manuell vergrößern, drei Annotations an deinem PVC reichen:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myapp-data
annotations:
resize.topolvm.io/threshold: "20%"
resize.topolvm.io/increase: "5Gi"
resize.topolvm.io/storage_limit: "50Gi"
spec:
storageClassName: hcloud-volumes
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
threshold ist ein Schwellwert für den freien Speicher, nicht für die Auslastung. Erweitert wird, sobald weniger als 20% frei sind, das Volume also zu über 80% gefüllt ist. Dann wächst es um 5 GiB, bis zum gesetzten Limit. Die Erweiterung läuft online, kein Pod-Neustart nötig. Das funktioniert für eigenständige PVCs und Datenbank-Volumes (CloudNativePG, MariaDB).
Verwechsle den Wert nicht mit einer Füllstandsgrenze: "80%" würde bedeuten, dass schon bei 20% Füllstand erweitert wird. Das Volume wächst dann Schritt für Schritt bis ans Limit, und du bezahlst den Speicher.
Storage wird zum Standardtarif abgerechnet (mindestens 10 GiB pro Volume). Volumes können nur wachsen, nie schrumpfen. Wie der Block Storage selbst setzt Autoresize hcloud-volumes voraus und steht damit nur in bezahlten Namespaces zur Verfügung.
Ressourcen-Empfehlungen mit dem Vertical Pod Autoscaler
Unsicher, wie viel CPU und Memory deine App wirklich braucht? Erstelle einen VPA im Empfehlungsmodus: Er analysiert das tatsächliche Verhalten und gibt Empfehlungen, ohne etwas zu ändern:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: myapp
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
updatePolicy:
updateMode: "Off"
# Nach ein paar Minuten: Empfehlungen abrufen
kubectl describe vpa myapp -n mein-namespace
Für automatische Anpassung stelle updateMode auf InPlaceOrRecreate. Pods werden nach Möglichkeit im laufenden Betrieb resized; wenn das nicht geht, werden sie neu erstellt.
Alles zusammen: Eine produktionsreife Plattform
Konkretes Szenario: Du betreibst eine SaaS-Anwendung mit API, Hintergrund-Worker und Web-Frontend.
Was in deinem Namespace läuft:
- API-Deployment mit HPA (2–10 Replicas je nach Last)
- Worker-Deployment für asynchrone Jobs
- PostgreSQL via CloudNativePG für die Hauptdatenbank
- Dragonfly als Session- und Cache-Layer
- S3-Bucket für User-Uploads und Media
- HTTPRoute mit automatischem TLS-Zertifikat
Was du nicht verwaltest:
- Cluster-Updates und Node-Patches
- cert-manager, Gateway-Controller, Monitoring-Stack
- Backup-Infrastruktur und Storage-Provisioning
- Netzwerk-Policies und Sicherheits-Patches
Alles wird per GitOps über ArgoCD deployed. Ein git push rollt Änderungen automatisch aus. Ein git revert macht sie rückgängig.
Fazit
Ein Kubernetes Namespace auf ITSH ist mehr als ein Ort, um Container zu starten. Managed Datenbanken, automatisches HTTPS, persistenter Speicher und Autoscaling machen ihn zu einer vollständigen Produktionsplattform, ohne dass du dich um Cluster-Infrastruktur kümmern musst.
Die Arbeit liegt dort, wo sie hingehört: bei deiner Anwendung. Die Plattform übernimmt den Rest.