TL;DR — Kurzzusammenfassung

etcd Backup und Wiederherstellung für Kubernetes: Snapshot-Methoden, Verifikation, Multi-Node-Restore, kubeadm-Zertifikate, Monitoring und Produktionsskript.

etcd ist das Herzstück jedes Kubernetes-Clusters: ein stark konsistenter, verteilter Schlüssel-Wert-Speicher, der den vollständigen — gewünschten und beobachteten — Zustand Ihres Clusters enthält. Wenn etcd ordnungsgemäß funktioniert, antworten kubectl-Befehle in Millisekunden und Controller reconcilieren kontinuierlich. Wenn etcd ohne Backup verloren geht, ist Ihr Cluster weg — jede Deployment-Definition, jedes Secret, jede RBAC-Richtlinie, jede CRD und jede ConfigMap verschwindet. Dieser Leitfaden behandelt alles, was Sie benötigen, um eine produktionsreife etcd-Backup-und-Wiederherstellungsstrategie aufzubauen.

Voraussetzungen

  • Ein mit kubeadm (v1.22+) verwalteter Kubernetes-Cluster oder Zugriff auf etcd-Zertifikate
  • etcdctl auf dem Control-Plane-Node installiert (Version muss zur etcd-Version passen)
  • Root- oder sudo-Zugriff auf dem Control-Plane-Node
  • kubectl mit cluster-admin-Berechtigungen konfiguriert
  • Grundlegende Kenntnisse der Kubernetes-Control-Plane-Komponenten
  • Für automatisierte Backups: Zugriff auf S3, GCS oder entsprechenden externen Speicher

Die Rolle von etcd in Kubernetes

Jedes Mal, wenn Sie kubectl apply ausführen, validiert der Kubernetes-API-Server die Anfrage und schreibt das resultierende Objekt in etcd. Alle Controller beobachten etcd über den Watch-Mechanismus des API-Servers und reconcilieren den Cluster entsprechend. etcd ist die einzige zustandsbehaftete Komponente in der Control Plane — alle anderen Komponenten sind zustandslos und können von Grund auf neu gestartet werden, solange etcd intakt ist.

Was in etcd gespeichert wird:

  • Alle API-Objektdefinitionen: Pods, Deployments, StatefulSets, DaemonSets, Services, Ingresses
  • Secrets und ConfigMaps
  • RBAC: Roles, ClusterRoles, RoleBindings, ClusterRoleBindings
  • Custom Resource Definitions und alle Custom-Resource-Instanzen
  • Namespace-Definitionen, ResourceQuotas, LimitRanges
  • ServiceAccounts und zugehörige Tokens
  • Node-Registrierungen und Lease-Objekte
  • Leader-Election-Einträge für kube-controller-manager und kube-scheduler

Was nicht in etcd gespeichert wird: die tatsächlichen Daten in PersistentVolumes. etcd speichert nur die PVC- und PV-API-Objekte (Metadaten und Bindung), nicht die Bytes auf der Festplatte.

etcd-Architektur: Raft, WAL und Snapshots

etcd verwendet den Raft-Konsensalgorithmus, um den Zustand über einen Cluster mit ungerader Anzahl von Mitgliedern (typischerweise 3 oder 5) zu replizieren. Raft wählt einen Leader, der alle Schreibvorgänge verarbeitet; Follower replizieren das Journal des Leaders. Der Cluster toleriert (n-1)/2 Memberausfälle — ein 3-Node-Cluster überlebt 1 Ausfall, ein 5-Node-Cluster überlebt 2.

Schreibvorgänge werden zunächst an das Write-Ahead Log (WAL) auf der Festplatte angehängt und dann auf einen B-Baum im Speicher (bbolt) angewendet. Periodisch erstellt etcd einen internen Snapshot des B-Baums auf der Festplatte und kürzt das WAL, um unbegrenztes Wachstum zu verhindern.

Der Befehl etcdctl snapshot save löst einen On-Demand-Snapshot des aktuellen B-Baum-Zustands aus. Dieser Snapshot ist ein vollständiges, eigenständiges Backup aller etcd-Daten zum Zeitpunkt seiner Erstellung.

Backup-Methoden

Methode 1: etcdctl snapshot save (Empfohlen)

Die kanonische Backup-Methode. In einem kubeadm-Cluster läuft etcd als statischer Pod mit TLS. Zertifikate befinden sich in /etc/kubernetes/pki/etcd/.

ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(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

Methode 2: Automatisierter CronJob

Stellen Sie einen Kubernetes-CronJob auf der Control Plane bereit, der die etcd-Zertifikate des Hosts einhängt und Snapshots in ein PVC oder Cloud-Speicher schreibt:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: etcd-backup
  namespace: kube-system
spec:
  schedule: "0 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          hostNetwork: true
          containers:
          - name: etcd-backup
            image: bitnami/etcd:3.5
            command:
            - /bin/sh
            - -c
            - |
              ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(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
            volumeMounts:
            - name: etcd-certs
              mountPath: /etc/kubernetes/pki/etcd
              readOnly: true
            - name: backup-dir
              mountPath: /backup
          volumes:
          - name: etcd-certs
            hostPath:
              path: /etc/kubernetes/pki/etcd
          - name: backup-dir
            persistentVolumeClaim:
              claimName: etcd-backup-pvc
          restartPolicy: OnFailure
          nodeSelector:
            node-role.kubernetes.io/control-plane: ""
          tolerations:
          - key: node-role.kubernetes.io/control-plane
            effect: NoSchedule

Vergleich der Backup-Tools

Tooletcd-ZustandPV-DatenWiederherstellungsgranularitätKomplexität
etcdctl snapshotJaNeinGesamter ClusterGering
Velero + etcd-PluginJaJaNamespace oder vollständigMittel
etcd-backup-operatorJaNeinGesamter ClusterMittel
kube-backupJaNeinGesamter ClusterGering
Manueller CronJobJaNeinGesamter ClusterGering

Snapshot-Verifizierung

Vertrauen Sie niemals einem Backup, das Sie nicht verifiziert haben. Nach jedem Snapshot:

ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-snapshot.db \
  --write-out=table

Wenn TOTAL KEYS 0 ist oder der Hash fehlerhaft ist, ist der Snapshot beschädigt. Integrieren Sie die Verifizierung in Ihren Backup-CronJob und konfigurieren Sie Alarme bei Fehlern.

Wiederherstellungsverfahren

Einknoteniger kubeadm-Cluster

Schritt 1: API-Server und etcd stoppen

mkdir -p /tmp/k8s-manifests-backup
mv /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/k8s-manifests-backup/
mv /etc/kubernetes/manifests/etcd.yaml /tmp/k8s-manifests-backup/
sleep 10
ps aux | grep etcd

Schritt 2: Vorhandenes Datenverzeichnis sichern

mv /var/lib/etcd /var/lib/etcd.bak

Schritt 3: Snapshot wiederherstellen

ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot.db \
  --data-dir=/var/lib/etcd \
  --initial-cluster=default=https://127.0.0.1:2380 \
  --initial-cluster-token=etcd-cluster-1 \
  --initial-advertise-peer-urls=https://127.0.0.1:2380

Schritt 4: Manifests wiederherstellen und verifizieren

mv /tmp/k8s-manifests-backup/etcd.yaml /etc/kubernetes/manifests/
mv /tmp/k8s-manifests-backup/kube-apiserver.yaml /etc/kubernetes/manifests/
sleep 30
kubectl get nodes

Mehrknotiger kubeadm-Cluster

Für einen 3-Node-Control-Plane-Cluster (HA) müssen Sie auf allen etcd-Membern gleichzeitig wiederherstellen, mit konsistenten Werten für --initial-cluster und --initial-cluster-token:

# Auf jedem Control-Plane-Node die Wiederherstellung mit DEMSELBEN Snapshot und Token ausführen
# aber mit dem korrekten --name und --initial-advertise-peer-urls für diesen Node

# Node 1
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot.db \
  --name=etcd-cp1 \
  --data-dir=/var/lib/etcd \
  --initial-cluster=etcd-cp1=https://10.0.0.1:2380,etcd-cp2=https://10.0.0.2:2380,etcd-cp3=https://10.0.0.3:2380 \
  --initial-cluster-token=etcd-restore-token-$(date +%s) \
  --initial-advertise-peer-urls=https://10.0.0.1:2380

Verwenden Sie ein eindeutiges --initial-cluster-token, das sich vom Original unterscheidet, um zu verhindern, dass der wiederhergestellte Cluster versehentlich dem alten (degradierten) Cluster beitritt.

Überlegungen zu verwaltetem Kubernetes

EKS, GKE, AKS — Der Cloud-Anbieter verwaltet etcd intern. Sie können nicht direkt auf etcd zugreifen. Verwenden Sie anbieternative Backup-Mechanismen:

  • EKS: Velero mit S3; AWS stellt etcd nicht direkt bereit
  • GKE: Velero; Google verwaltet etcd mit automatischen Backups auf Autopilot
  • AKS: Velero + Azure Blob; Microsoft verwaltet etcd für verwaltete Node Pools

etcd-Gesundheitsüberwachung

# Endpunkt-Gesundheit prüfen
ETCDCTL_API=3 etcdctl endpoint health \
  --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

# Leader- und Member-Status prüfen
ETCDCTL_API=3 etcdctl endpoint status --write-out=table \
  --endpoints=https://10.0.0.1:2379,https://10.0.0.2:2379,https://10.0.0.3:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

Empfohlene Prometheus-Alarme für etcd:

  • etcd_server_has_leader == 0 — kein Leader gewählt (kritisch)
  • etcd_disk_wal_fsync_duration_seconds{quantile="0.99"} > 0.01 — langsame WAL-Schreibvorgänge
  • etcd_server_proposals_failed_total > 0 — Konsensausfälle
  • etcd_mvcc_db_total_size_in_bytes > 8589934592 — DB nähert sich dem 8-GB-Limit

Komprimierung und Defragmentierung

etcd hält eine Historie aller Schlüsselrevisionen. Mit der Zeit verbraucht dies erheblichen Festplattenplatz. Aktivieren Sie die automatische Komprimierung:

--auto-compaction-mode=periodic
--auto-compaction-retention=1h

Führen Sie die Defragmentierung periodisch während Nebenzeiten durch:

ETCDCTL_API=3 etcdctl defrag \
  --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

Performance-Tuning

etcd ist extrem empfindlich gegenüber Festplattenlatenz. Empfehlungen:

  • Dedizierte SSD: Teilen Sie die etcd-Datenfestplatte niemals mit Anwendungsworkloads. Verwenden Sie eine dedizierte NVMe oder SSD mit über 2000 IOPS für zufällige Schreibvorgänge.
  • Heartbeat- und Election-Timeouts: Der Standard-heartbeat-interval ist 100ms und der election-timeout ist 1000ms. In latenzreichen Umgebungen erhöhen Sie auf 250ms / 1250ms.
  • DB-Quota: Der Standardwert ist 2 GB. Erhöhen Sie auf 8 GB für große Cluster: --quota-backend-bytes=8589934592

Produktions-Backup-Skript mit Alarmierung

#!/bin/bash
set -euo pipefail

BACKUP_DIR="/opt/etcd-backups"
RETENTION_COUNT=24
S3_BUCKET="s3://mein-cluster-etcd-backups"
SLACK_WEBHOOK="https://hooks.slack.com/services/xxx/yyy/zzz"
ETCD_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"

TIMESTAMP=$(date +%Y%m%d-%H%M%S)
SNAPSHOT_FILE="${BACKUP_DIR}/etcd-${TIMESTAMP}.db"

alarm() {
  local msg="$1"
  curl -s -X POST -H 'Content-type: application/json' \
    --data "{\"text\":\"[etcd-backup] ${msg}\"}" "${SLACK_WEBHOOK}" || true
}

mkdir -p "${BACKUP_DIR}"

if ! ETCDCTL_API=3 etcdctl snapshot save "${SNAPSHOT_FILE}" \
    --endpoints="${ETCD_ENDPOINTS}" \
    --cacert="${CACERT}" --cert="${CERT}" --key="${KEY}"; then
  alarm "KRITISCH: etcd snapshot save FEHLGESCHLAGEN auf $(hostname) um ${TIMESTAMP}"
  exit 1
fi

KEYS=$(ETCDCTL_API=3 etcdctl snapshot status "${SNAPSHOT_FILE}" \
  --write-out=json | python3 -c "import sys,json; print(json.load(sys.stdin)['totalKey'])")
if [ "${KEYS}" -lt 100 ]; then
  alarm "WARNUNG: Snapshot hat nur ${KEYS} Schlüssel — möglicherweise leerer oder beschädigter Snapshot"
  exit 1
fi

aws s3 cp "${SNAPSHOT_FILE}" "${S3_BUCKET}/$(basename ${SNAPSHOT_FILE})" \
  --storage-class STANDARD_IA

ls -t "${BACKUP_DIR}"/etcd-*.db | tail -n +$((RETENTION_COUNT + 1)) | xargs -r rm -f

echo "Backup abgeschlossen: ${SNAPSHOT_FILE} (${KEYS} Schlüssel)"

Disaster-Recovery-Szenarien

Szenario 1: Ausfall eines Members (Quorum intakt) — Der Cluster arbeitet weiter. Ersetzen Sie das ausgefallene Member mit etcdctl member remove + etcdctl member add ohne Wiederherstellung.

Szenario 2: Quorumverlust (Mehrheit der Member ausgefallen) — Der Cluster wird schreibgeschützt. Wenn die Daten intakt sind, stellen Sie die Konnektivität wieder her. Wenn Daten verloren gegangen sind, stellen Sie von einem Snapshot auf allen Membern wieder her.

Szenario 3: Vollständige Cluster-Wiederherstellung — Stoppen Sie alle Control-Plane-Komponenten, stellen Sie den Snapshot auf jedem Node mit konsistentem --initial-cluster-token wieder her, starten Sie in der Reihenfolge neu: zuerst etcd, dann kube-apiserver, dann kube-controller-manager und kube-scheduler.

Fallstricke und Randfälle

etcdctl-Versionskonflikt — Setzen Sie immer ETCDCTL_API=3. Überprüfen Sie, ob die Client-Version mit der Server-Version übereinstimmt. Konflikte verursachen stille Fehler oder beschädigte Wiederherstellungen.

Wiederherstellung überschreibt das Datenverzeichnisetcdctl snapshot restore schreibt in --data-dir. Wenn das Verzeichnis bereits existiert, schlägt die Wiederherstellung fehl. Verschieben Sie immer zuerst das vorhandene Verzeichnis.

Uhrabweichung zwischen Membern — etcd-Peer-TLS-Zertifikate sind zeitkritisch. Stellen Sie sicher, dass NTP auf allen Control-Plane-Nodes konfiguriert und synchronisiert ist.

Überraschungen bei verwalteten Clustern — Auf GKE oder EKS wird der Versuch, in den etcd-Pod zu wechseln, fehlschlagen oder blockiert werden. Verwenden Sie bei verwalteten Clustern sofort Velero.

Zusammenfassung

  • etcd speichert den gesamten Kubernetes-Cluster-Zustand; ihn ohne Backup zu verlieren bedeutet, von vorne anzufangen
  • Verwenden Sie etcdctl snapshot save mit TLS-Flags, die auf /etc/kubernetes/pki/etcd/ zeigen, für kubeadm-Cluster
  • Führen Sie immer etcdctl snapshot status aus, um Snapshots nach der Erstellung zu verifizieren
  • Die Wiederherstellung erfordert das Stoppen von API-Server und etcd, die Ausführung von etcdctl snapshot restore und den Neustart der Control Plane
  • Die Multi-Node-Wiederherstellung erfordert konsistentes --initial-cluster-token und korrekte --initial-advertise-peer-urls pro Node
  • Aktivieren Sie die automatische Komprimierung und führen Sie etcdctl defrag monatlich aus
  • Dedizieren Sie eine SSD mit geringer Latenz für etcd-Daten; überwachen Sie die WAL-fsync-Latenz mit Prometheus
  • Speichern Sie Snapshots extern (S3/GCS) mit mindestens 24 Stunden Aufbewahrungszeit; automatisieren Sie mit CronJob + Alarmierungsskript

Verwandte Artikel