Veröffentlicht am

Kubernetes Backup mit Velero: Disaster Recovery Praxis

Teilen:
Authors

Kubernetes Backup und Disaster Recovery: Velero, etcd und Storage-Snapshots

TL;DR

  • Kubernetes-Backup besteht aus drei Schichten: etcd (Cluster-State), Kubernetes-Ressourcen (Manifests) und Persistent Volumes (Anwendungsdaten).
  • Velero ist das Standardtool fuer Kubernetes-Backups. Es sichert Ressourcen und Volumes in externen Object Storage (S3, GCS, Azure Blob).
  • etcd-Backups sind separat notwendig und die Lebensversicherung des Clusters. Ohne etcd-Snapshot kein Cluster-Restore.
  • Ein Backup ohne regelmaessigen Restore-Test ist wertlos. Automatisieren Sie beides.
  • Definieren Sie RTO und RPO pro Anwendung, bevor Sie die Backup-Strategie festlegen.

Die drei Backup-Schichten

Viele Teams sichern nur eine Schicht und wiegen sich in falscher Sicherheit. Ein vollstaendiges Kubernetes-Backup umfasst drei voneinander unabhaengige Schichten:

Schicht 1: etcd-Datenbank. etcd speichert den gesamten Cluster-Zustand: Deployments, Services, ConfigMaps, Secrets, RBAC-Regeln, Custom Resources. Wenn etcd verloren geht, ist der Cluster weg -- auch wenn alle Nodes noch laufen.

Schicht 2: Kubernetes-Ressourcen. Das sind die YAML-Definitionen Ihrer Workloads. Theoretisch sind diese in Git versioniert (GitOps). In der Praxis gibt es oft Drift: manuell angepasste ConfigMaps, imperativ erstellte Services, Helm-Releases mit custom Values. Velero sichert den tatsaechlichen Cluster-Zustand, nicht den Soll-Zustand aus Git.

Schicht 3: Persistent Volumes. Die eigentlichen Anwendungsdaten: Datenbank-Inhalte, hochgeladene Dateien, Cache-Daten. Diese liegen auf den Storage-Systemen hinter den PersistentVolumes und werden von Kubernetes selbst nicht gesichert.

SchichtWas wird gesichertToolRestore-Szenario
etcdCluster-Stateetcdctl snapshotKompletter Cluster-Verlust
Kubernetes-RessourcenDeployments, Services, Secrets, etc.VeleroNamespace geloescht, Ressource ueberschrieben
Persistent VolumesAnwendungsdatenVelero + CSI SnapshotsDatenbank-Korruption, versehentliches Loeschen

etcd-Backup einrichten

etcd-Backups sind die Grundlage. Bei Managed Kubernetes (AKS, EKS, GKE) uebernimmt der Provider das etcd-Management. Bei self-managed Clustern muessen Sie selbst dafuer sorgen.

Manueller etcd-Snapshot

# Auf einem Control Plane Node ausfuehren
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot-$(date +%Y%m%d-%H%M%S).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 /backup/etcd-snapshot-*.db --write-table

Automatisiertes etcd-Backup als CronJob

Fuer self-managed Cluster koennen Sie einen CronJob verwenden, der den Snapshot auf externen Storage schiebt:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: etcd-backup
  namespace: kube-system
spec:
  schedule: "0 */6 * * *"
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 3
  jobTemplate:
    spec:
      template:
        spec:
          hostNetwork: true
          nodeSelector:
            node-role.kubernetes.io/control-plane: ""
          tolerations:
            - key: node-role.kubernetes.io/control-plane
              effect: NoSchedule
          containers:
            - name: etcd-backup
              image: bitnami/etcd:3.5
              command:
                - /bin/sh
                - -c
                - |
                  SNAPSHOT_FILE="/backup/etcd-$(date +%Y%m%d-%H%M%S).db"
                  etcdctl snapshot save "$SNAPSHOT_FILE" \
                    --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
                  etcdctl snapshot status "$SNAPSHOT_FILE" --write-table
                  # Upload zu S3 (aws cli muss im Image vorhanden sein)
                  # aws s3 cp "$SNAPSHOT_FILE" s3://my-backup-bucket/etcd/
              volumeMounts:
                - name: etcd-certs
                  mountPath: /etc/kubernetes/pki/etcd
                  readOnly: true
                - name: backup-volume
                  mountPath: /backup
          volumes:
            - name: etcd-certs
              hostPath:
                path: /etc/kubernetes/pki/etcd
            - name: backup-volume
              hostPath:
                path: /var/backups/etcd
          restartPolicy: OnFailure

Dieser CronJob laeuft alle 6 Stunden auf einem Control Plane Node. In der Praxis wuerde man den Snapshot anschliessend auf einen externen S3-Bucket oder aehnlichen Object Store hochladen.

Velero: Kubernetes-Ressourcen und Volumes sichern

Velero ist der De-facto-Standard fuer Kubernetes-Backups. Es sichert Kubernetes-Objekte (Deployments, Services, ConfigMaps, Secrets) und kann ueber CSI-Snapshots oder Restic/Kopia auch Persistent Volumes sichern.

Velero installieren

# Velero CLI installieren (macOS)
brew install velero

# Oder manuell
wget https://github.com/vmware-tanzu/velero/releases/download/v1.13.0/velero-v1.13.0-linux-amd64.tar.gz
tar -xvf velero-v1.13.0-linux-amd64.tar.gz
mv velero-v1.13.0-linux-amd64/velero /usr/local/bin/

# Velero auf dem Cluster installieren (Beispiel fuer AWS S3)
velero install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.9.0 \
  --bucket my-velero-backups \
  --backup-location-config region=eu-central-1 \
  --snapshot-location-config region=eu-central-1 \
  --secret-file ./credentials-velero \
  --use-node-agent \
  --default-volumes-to-fs-backup

Die credentials-velero-Datei enthaelt AWS Access Key und Secret Key mit Schreibzugriff auf den S3-Bucket. Verwenden Sie in Produktion eine IAM-Rolle statt statischer Credentials.

Backup erstellen

# Komplettes Cluster-Backup
velero backup create full-backup-$(date +%Y%m%d)

# Namespace-spezifisches Backup
velero backup create app-backup \
  --include-namespaces production,staging \
  --ttl 720h

# Backup mit Label-Selektor
velero backup create critical-apps \
  --selector tier=critical

# Backup-Status pruefen
velero backup describe full-backup-20260210
velero backup logs full-backup-20260210

Automatische Backups mit Schedules

apiVersion: velero.io/v1
kind: Schedule
metadata:
  name: daily-full-backup
  namespace: velero
spec:
  schedule: "0 2 * * *"
  template:
    includedNamespaces:
      - production
      - staging
      - monitoring
    excludedResources:
      - events
      - events.events.k8s.io
    defaultVolumesToFsBackup: true
    ttl: 168h
    storageLocation: default
    snapshotVolumes: true
---
apiVersion: velero.io/v1
kind: Schedule
metadata:
  name: hourly-critical-backup
  namespace: velero
spec:
  schedule: "0 * * * *"
  template:
    includedNamespaces:
      - production
    labelSelector:
      matchLabels:
        backup-priority: critical
    defaultVolumesToFsBackup: true
    ttl: 48h

Damit laeuft jede Nacht ein vollstaendiges Backup der wichtigsten Namespaces mit 7 Tagen Aufbewahrungsfrist. Zusaetzlich werden kritische Workloads stuendlich gesichert.

Fuer Storage-Konfiguration und CSI-Treiber: Kubernetes Storage.

Restore: Der Teil, den die meisten vergessen

Ein Backup ist nur so gut wie sein letzter erfolgreicher Restore-Test. Hier die wichtigsten Restore-Szenarien:

Einzelnen Namespace wiederherstellen

# Namespace zunaechst loeschen (oder in einen neuen Namespace restoren)
velero restore create restore-production \
  --from-backup daily-full-backup-20260210020000 \
  --include-namespaces production

# Restore-Status pruefen
velero restore describe restore-production
velero restore logs restore-production

In einen anderen Namespace restoren

Nuetzlich fuer Tests oder wenn der Original-Namespace noch existiert:

velero restore create restore-to-staging \
  --from-backup daily-full-backup-20260210020000 \
  --include-namespaces production \
  --namespace-mappings production:staging-restored

etcd-Restore (Kompletter Cluster)

Dieses Szenario ist der worst case: Die Control Plane ist verloren.

# Auf dem (neuen) Control Plane Node:
# 1. etcd stoppen
systemctl stop etcd

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

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

# 4. etcd starten
systemctl start etcd

# 5. Cluster-Zustand verifizieren
kubectl get nodes
kubectl get pods --all-namespaces

RTO und RPO festlegen

Bevor Sie die Backup-Frequenz konfigurieren, definieren Sie RTO und RPO fuer jede Anwendung:

AnwendungRPO (max. Datenverlust)RTO (max. Ausfallzeit)Backup-FrequenzStrategie
Produktions-Datenbank15 Minuten1 StundeStuendlich + WAL-ArchivierungVelero + DB-eigenes Backup
Web-Frontend (stateless)24 Stunden15 MinutenTaeglichVelero (nur Ressourcen)
Internes Wiki4 Stunden4 StundenAlle 4 StundenVelero + Volume-Snapshot
CI/CD-System24 Stunden2 StundenTaeglichVelero + GitOps-Recovery

Ein wichtiger Punkt: Fuer Datenbanken ist Velero allein nicht ausreichend. Datenbank-eigene Backup-Mechanismen (pg_dump, mysqldump, mongodump) liefern konsistentere Backups als Filesystem-Snapshots. Velero sichert in diesem Fall die Kubernetes-Ressourcen (Deployment, Service, ConfigMap), waehrend das Datenbank-Backup separat laeuft.

Backup-Verschluesselung

Backups enthalten sensible Daten: Kubernetes Secrets, Datenbank-Inhalte, Konfigurationen. Die Verschluesselung muss auf mehreren Ebenen greifen.

Object Storage: S3-Buckets mit Server-Side Encryption (SSE-S3 oder SSE-KMS) konfigurieren. Bei DSGVO-relevanten Daten empfiehlt sich SSE-KMS mit einem eigenen Key, den Sie kontrollieren.

Velero: Velero verschluesselt Backups nicht selbst, verlässt sich aber auf die Verschluesselung des Ziel-Storage. Stellen Sie sicher, dass der S3-Bucket so konfiguriert ist, dass unverschluesselte Uploads abgelehnt werden:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyUnencryptedUploads",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::my-velero-backups/*",
      "Condition": {
        "StringNotEquals": {
          "s3:x-amz-server-side-encryption": "aws:kms"
        }
      }
    }
  ]
}

etcd-Snapshots: Diese enthalten alle Secrets im Klartext (bzw. base64-kodiert, was kein Schutz ist). Verschluesseln Sie etcd-Snapshots vor dem Upload mit GPG oder age:

# Mit age verschluesseln
age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p \
  etcd-snapshot.db > etcd-snapshot.db.age

# Entschluesseln
age -d -i key.txt etcd-snapshot.db.age > etcd-snapshot.db

Mehr zu Secrets Management: Kubernetes Secrets Management mit Vault.

Restore-Tests automatisieren

Ein manueller Restore-Test alle paar Monate reicht nicht. Automatisieren Sie den Test:

#!/bin/bash
set -euo pipefail

BACKUP_NAME=$(velero backup get -o json | jq -r '.items | sort_by(.metadata.creationTimestamp) | last | .metadata.name')
RESTORE_NS="restore-test-$(date +%s)"

echo "Teste Restore von Backup: $BACKUP_NAME"

# Restore in temporaeren Namespace
velero restore create "test-restore-$(date +%s)" \
  --from-backup "$BACKUP_NAME" \
  --include-namespaces production \
  --namespace-mappings "production:$RESTORE_NS" \
  --wait

# Pruefen ob Pods starten
echo "Warte auf Pods..."
kubectl -n "$RESTORE_NS" wait --for=condition=ready pod --all --timeout=300s

READY_PODS=$(kubectl -n "$RESTORE_NS" get pods --field-selector=status.phase=Running --no-headers | wc -l)
TOTAL_PODS=$(kubectl -n "$RESTORE_NS" get pods --no-headers | wc -l)

echo "Ergebnis: $READY_PODS/$TOTAL_PODS Pods ready"

# Aufraeumen
kubectl delete namespace "$RESTORE_NS" --wait=false

if [ "$READY_PODS" -eq "$TOTAL_PODS" ] && [ "$TOTAL_PODS" -gt 0 ]; then
  echo "RESTORE TEST PASSED"
  exit 0
else
  echo "RESTORE TEST FAILED"
  exit 1
fi

Dieses Skript laesst sich in eine CI/CD-Pipeline einbinden oder als woechentlicher CronJob ausfuehren. Bei Fehlschlag wird das Team per Alert benachrichtigt.

Fuer die Monitoring-Integration: Kubernetes Monitoring.

Haeufige Fehler

Backup nur fuer Kubernetes-Ressourcen, nicht fuer Volumes. Velero sichert standardmaessig nur Kubernetes-Objekte. Persistent Volumes muessen explizit eingeschlossen werden (--default-volumes-to-fs-backup oder Annotationen).

Kein separates Datenbank-Backup. Filesystem-Snapshots einer laufenden Datenbank koennen inkonsistent sein. Nutzen Sie immer den nativen Backup-Mechanismus der Datenbank zusaetzlich zu Velero.

Backup-Bucket im selben Account/Region wie der Cluster. Wenn der gesamte Account kompromittiert wird (Ransomware, versehentliches Loeschen), sind auch die Backups weg. Nutzen Sie einen separaten Account oder Cross-Region-Replikation.

Restore nie getestet. Der haeufigste Fehler. Backups laufen seit Monaten, aber niemand hat je einen Restore durchgefuehrt. Beim echten Ausfall stellt sich heraus, dass der Restore-Prozess nicht funktioniert.

Secrets im Backup nicht verschluesselt. Velero-Backups enthalten Kubernetes Secrets im Klartext. Wenn der Backup-Bucket nicht verschluesselt ist, liegen Passwoerter und API-Keys offen.

Zusammenfassung

Kubernetes-Backup ist kein einzelnes Tool, sondern eine Strategie aus drei Schichten: etcd, Ressourcen und Volumes. Velero deckt die zweite und dritte Schicht ab, etcd muss separat gesichert werden. Die Backup-Frequenz ergibt sich aus den RTO/RPO-Anforderungen der einzelnen Anwendungen.

Der wichtigste Punkt: Testen Sie Ihre Restores. Regelmaessig. Automatisiert. Ein Backup, das nie getestet wurde, ist kein Backup -- es ist eine Hoffnung.

Fuer weitergehende Themen zur Cluster-Resilienz: Kubernetes Resilienz.


Sie moechten Ihre Backup-Strategie pruefen lassen oder brauchen Unterstuetzung beim Aufbau einer DR-Loesung? Melden Sie sich bei uns.

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