Veröffentlicht am

Kubernetes Disaster Recovery: RPO, RTO und Failover-Strategien

Teilen:
Authors

Kubernetes Disaster Recovery: RPO, RTO und Failover-Strategien erklärt

TL;DR: Disaster Recovery beginnt mit zwei Zahlen: RPO (wie viel Datenverlust ist akzeptabel?) und RTO (wie schnell muss der Cluster wieder laufen?). Dieser Artikel erklärt die DR-Konzepte, zeigt etcd-Backup und -Restore, vergleicht Failover-Strategien und gibt ein Template für euren DR-Plan.


RPO und RTO: Die zwei wichtigsten Kennzahlen

Bevor man eine DR-Strategie wählt, muss man zwei Fragen beantworten:

  • RPO (Recovery Point Objective): Wie viel Datenverlust ist tolerierbar? Ein RPO von 1 Stunde bedeutet: Im Worst Case verliert man maximal 1 Stunde an Daten.
  • RTO (Recovery Time Objective): Wie lange darf die Wiederherstellung dauern? Ein RTO von 30 Minuten bedeutet: Nach 30 Minuten müssen die Systeme wieder laufen.

RPO/RTO-Matrix für verschiedene Strategien

StrategieRPORTOKostenKomplexität
Velero Scheduled Backup4-24h1-4hNiedrigNiedrig
etcd Snapshot + Velero1-6h30min-2hNiedrigMittel
Aktiv/Passiv Cluster5-15min10-30minMittelMittel
Aktiv/Aktiv Multi-Cluster~0 (near-zero)unter 5minHochHoch
GitOps + Stateless0 (kein Verlust)10-30minMittelMittel

Die richtige Wahl hängt vom Business ab. Nicht jeder Workload braucht Aktiv/Aktiv -- aber jeder braucht einen getesteten DR-Plan.

etcd: Das Herz des Clusters sichern

etcd speichert den gesamten Cluster-State. Ohne etcd kein Cluster. Deshalb ist das etcd-Backup die Grundlage jeder DR-Strategie.

etcd Snapshot erstellen

# Auf einem Control-Plane Node:
ETCDCTL_API=3 etcdctl snapshot save /tmp/etcd-snapshot-$(date +%Y%m%d-%H%M).db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

# Snapshot verifizieren
ETCDCTL_API=3 etcdctl snapshot status /tmp/etcd-snapshot-20260210-0200.db --write-table

Output:

+----------+----------+------------+------------+
|   HASH   | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| 9db5a43c |  1285034 |       1247 |     5.4 MB |
+----------+----------+------------+------------+

etcd Snapshot automatisieren (CronJob)

apiVersion: batch/v1
kind: CronJob
metadata:
  name: etcd-snapshot
  namespace: kube-system
spec:
  schedule: "0 */6 * * *"  # Alle 6 Stunden
  jobTemplate:
    spec:
      template:
        spec:
          hostNetwork: true
          nodeSelector:
            node-role.kubernetes.io/control-plane: ""
          tolerations:
            - effect: NoSchedule
              key: node-role.kubernetes.io/control-plane
          containers:
            - name: etcd-snapshot
              image: registry.k8s.io/etcd:3.5.15-0
              command:
                - /bin/sh
                - -c
                - |
                  etcdctl snapshot save /snapshots/etcd-$(date +%Y%m%d-%H%M).db \
                    --endpoints=https://127.0.0.1:2379 \
                    --cacert=/etc/kubernetes/pki/etcd/ca.crt \
                    --cert=/etc/kubernetes/pki/etcd/server.crt \
                    --key=/etc/kubernetes/pki/etcd/server.key
                  # Alte Snapshots aufräumen (älter als 7 Tage)
                  find /snapshots -name "etcd-*.db" -mtime +7 -delete
              volumeMounts:
                - name: etcd-certs
                  mountPath: /etc/kubernetes/pki/etcd
                  readOnly: true
                - name: snapshots
                  mountPath: /snapshots
          volumes:
            - name: etcd-certs
              hostPath:
                path: /etc/kubernetes/pki/etcd
            - name: snapshots
              hostPath:
                path: /var/lib/etcd-snapshots
          restartPolicy: OnFailure

etcd Restore

# 1. etcd stoppen (auf ALLEN Control-Plane Nodes)
sudo systemctl stop etcd
# oder bei kubeadm: static Pod manifest verschieben
sudo mv /etc/kubernetes/manifests/etcd.yaml /tmp/

# 2. Altes Datenverzeichnis sichern
sudo mv /var/lib/etcd /var/lib/etcd.bak

# 3. Snapshot wiederherstellen
ETCDCTL_API=3 etcdctl snapshot restore /tmp/etcd-snapshot-20260210-0200.db \
  --data-dir=/var/lib/etcd \
  --name=control-plane-1 \
  --initial-cluster=control-plane-1=https://192.168.1.10:2380 \
  --initial-advertise-peer-urls=https://192.168.1.10:2380

# 4. etcd wieder starten
sudo mv /tmp/etcd.yaml /etc/kubernetes/manifests/

# 5. Cluster-Status prüfen
kubectl get nodes
kubectl get pods --all-namespaces

Stateful Workloads absichern

Stateless Workloads (Deployments aus Git) lassen sich per GitOps jederzeit neu deployen. Stateful Workloads sind das eigentliche Problem.

Datenbank-Backups innerhalb des Clusters

Verlasst euch nicht allein auf Volume Snapshots. Datenbanken brauchen konsistente Backups:

# CronJob für PostgreSQL Logical Backup
apiVersion: batch/v1
kind: CronJob
metadata:
  name: postgres-backup
  namespace: database
spec:
  schedule: "30 1 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: pg-dump
              image: postgres:16
              command:
                - /bin/bash
                - -c
                - |
                  pg_dump -h postgres-service -U $PGUSER -Fc $PGDATABASE \
                    > /backups/db-$(date +%Y%m%d-%H%M).dump
                  # Upload zu S3
                  aws s3 cp /backups/db-$(date +%Y%m%d-%H%M).dump \
                    s3://db-backups-prod/$(date +%Y%m%d)/
              envFrom:
                - secretRef:
                    name: postgres-credentials
              volumeMounts:
                - name: backup-volume
                  mountPath: /backups
          volumes:
            - name: backup-volume
              emptyDir: {}
          restartPolicy: OnFailure

Strategie nach Workload-Typ

Workload-TypBackup-MethodeRPO erreichbarHinweis
Stateless DeploymentGitOps (ArgoCD/Flux)0Kein Datenverlust möglich
PostgreSQL / MySQLpg_dump/mysqldump + S31-24hLogische Backups bevorzugen
MongoDBmongodump + S31-24hOplog für Point-in-Time
Redis (Cache)Kein Backup nötign/aCache wird neu aufgebaut
Redis (Persistent)RDB Snapshot + S31-6hAOF für kleineres RPO
ElasticsearchSnapshot API + S31-6hSnapshot Repository konfigurieren
PV (generisch)Velero + CSI Snapshots4-24hFür unbekannte Workloads

Multi-Cluster Failover

Aktiv/Passiv Setup

Der Passiv-Cluster steht bereit, übernimmt aber erst bei einem Ausfall. Typisches Setup:

                    ┌──────────────┐
DNS / LB                    └──────┬───────┘
              ┌────────────┼────────────┐
              v                         v
     ┌─────────────┐          ┌─────────────┐
Cluster A  │          │  Cluster B        (Aktiv)-----*/}   (Standby)FrankfurtVeleroMünchen   │
     └─────────────┘  Sync    └─────────────┘

Umsetzung mit Velero Cross-Cluster Restore:

# Auf Cluster A: Backup erstellen
velero backup create failover-backup --include-namespaces production

# Auf Cluster B: Backup-Storage konfigurieren (gleicher S3 Bucket)
velero backup-location create shared \
  --provider aws \
  --bucket k8s-backups-prod \
  --config region=eu-central-1

# Auf Cluster B: Restore starten
velero restore create --from-backup failover-backup

GitOps-basiertes Failover

Wer GitOps (ArgoCD, Flux) einsetzt, hat einen natürlichen Vorteil: Der Cluster-State liegt in Git. Ein neuer Cluster lässt sich schnell bootstrappen:

# Neuen Cluster aufsetzen (z.B. via kubeadm oder Terraform)
# ArgoCD installieren
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# App-of-Apps Pattern: Gesamtes Setup aus Git deployen
argocd app create cluster-bootstrap \
  --repo https://git.internal.example.com/infra/k8s-apps.git \
  --path environments/production \
  --dest-server https://kubernetes.default.svc

Stateful Daten müssen trotzdem separat restored werden (Datenbank-Dumps, PV-Backups).

DR-Plan Template

Ein DR-Plan gehört dokumentiert und getestet. Hier ein praxistaugliches Template:

1. Szenario-Klassifizierung

SzenarioSchwereMaßnahme
Einzelner Pod/Node fällt ausNiedrigKubernetes Self-Healing (automatisch)
Namespace versehentlich gelöschtMittelVelero Restore des Namespace
Control Plane nicht erreichbarHochetcd Restore oder Failover auf Cluster B
Gesamter Cluster / AZ AusfallKritischFailover auf Standby-Cluster
Ransomware / DatenkorruptionKritischRestore aus Offline-Backup

2. Runbook: Namespace gelöscht

# 1. Letztes verfügbares Backup identifizieren
velero backup get --selector environment=production

# 2. Backup-Inhalt prüfen
velero backup describe daily-production-20260209020000 --details

# 3. Restore starten
velero restore create ns-restore \
  --from-backup daily-production-20260209020000 \
  --include-namespaces production

# 4. Restore-Status prüfen
velero restore describe ns-restore
kubectl get pods -n production

3. Runbook: Cluster Totalausfall

# 1. Standby-Cluster aktivieren (DNS umschalten)
# 2. etcd Snapshot auf neuem Control Plane restoren (falls kein Standby vorhanden)
# 3. Velero Restore für Workloads
# 4. Datenbank-Backups restoren (pg_restore, mongorestore)
# 5. Smoke Tests durchführen
# 6. DNS / LoadBalancer umschalten
# 7. Monitoring validieren

DR-Tests: Vertrauen durch Praxis

Ein DR-Plan, der nie getestet wurde, ist Fiktion. Empfohlener Testrhythmus:

TestFrequenzDauerBeschreibung
Velero Restore in Test-NSMonatlich30 minRestore in separaten Namespace, Smoke Test
etcd Snapshot + RestoreQuartalsweise2hAuf Staging-Cluster durchführen
Full Failover DrillHalbjährlich4-8hKompletter Schwenk auf Standby-Cluster
Tabletop ExerciseJährlich2hSzenario-Durchsprache mit dem Team
# Einfacher monatlicher Restore-Test
velero restore create monthly-test-$(date +%Y%m) \
  --from-schedule daily-production \
  --namespace-mappings production:dr-test

# Prüfen ob Pods laufen
kubectl wait --for=condition=ready pods --all -n dr-test --timeout=300s

# Aufräumen
kubectl delete namespace dr-test

DSGVO-Aspekte bei Disaster Recovery

Für deutsche Unternehmen gelten besondere Anforderungen:

  • Speicherort: Backup-Daten müssen in der EU (idealerweise eu-central-1) liegen
  • Verschlüsselung: Server-Side Encryption (SSE-S3 oder SSE-KMS) im S3 Bucket aktivieren
  • Löschfristen: Backup-Retention muss mit Löschkonzept übereinstimmen. Wer Daten nach 30 Tagen löschen muss, darf keine 90-Tage-Backups vorhalten, die diese Daten enthalten
  • Zugriffsprotokollierung: Wer hat wann auf Backup-Daten zugegriffen?
  • Dokumentation: DR-Plan und Backup-Prozesse müssen im Verzeichnis der Verarbeitungstätigkeiten stehen

Fazit

Disaster Recovery ist kein Tool-Problem, sondern ein Prozess-Problem. Die Technik (Velero, etcd Snapshots, Multi-Cluster) ist verfügbar und gut dokumentiert. Der schwierige Teil ist: RPO/RTO definieren, einen DR-Plan schreiben, ihn regelmäßig testen und die Ergebnisse dokumentieren.

Fangt mit dem Einfachen an: etcd-Snapshots + Velero-Schedules. Testet monatlich einen Restore. Das allein ist besser als 99% der Setups, die wir in der Praxis sehen.


Verwandte Artikel:


Ihr braucht einen getesteten DR-Plan? Wir unterstützen beim Design eurer Disaster-Recovery-Strategie, bei der Implementierung und beim ersten Failover-Drill. Kontaktiert uns oder schreibt an kontakt@pexon-consulting.de.

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