etcd ist der verteilte Key-Value-Store im Herzen jedes Kubernetes-Clusters und speichert den gesamten Clusterzustand von Pod-Definitionen bis hin zu Secrets. Wenn etcd ausfällt oder Daten verliert, hört die gesamte Control-Plane auf zu funktionieren. Dieser Leitfaden führt dich durch die Bereitstellung von etcd als eigenständigen Dienst und als Drei-Knoten-Cluster, die Absicherung mit gegenseitigem TLS, das Erstellen und Wiederherstellen von Snapshots sowie das Verständnis dafür, wie Kubernetes etcd nutzt — damit du es sicher in der Produktion betreiben kannst.

Voraussetzungen

  • Linux-Server mit Ubuntu 22.04 oder neuer (einer für Single-Node, drei für den Cluster)
  • Root- oder sudo-Zugriff
  • Grundkenntnisse in der Verwaltung von systemd-Diensten
  • curl und tar installiert
  • Für TLS: cfssl oder openssl verfügbar
  • Ports 2379 (Client) und 2380 (Peer) zwischen den etcd-Nodes geöffnet

Was ist etcd und wie funktioniert es?

etcd ist ein quelloffener, stark konsistenter verteilter Key-Value-Store, der ursprünglich von CoreOS entwickelt wurde und inzwischen ein abgeschlossenes Projekt der Cloud Native Computing Foundation (CNCF) ist. Es verwendet den Raft-Konsensalgorithmus, um sicherzustellen, dass alle Nodes sich auf den aktuellen Zustand einigen, selbst wenn Netzwerkpartitionen oder Node-Ausfälle auftreten.

Die wichtigsten Eigenschaften, die du kennen musst:

  • Starke Konsistenz: Jeder Lesevorgang gibt den zuletzt bestätigten Schreibvorgang zurück, niemals einen veralteten Wert
  • Watch-API: Clients abonnieren Schlüsseländerungen und erhalten Benachrichtigungen in Echtzeit
  • Atomare Transaktionen: Compare-and-Swap-Operationen ermöglichen den Aufbau verteilter Sperren
  • Leases: Schlüssel können automatisch ablaufen, was eine Heartbeat-basierte Leader-Wahl ermöglicht

Kubernetes verlässt sich auf etcd für jeden Teil des Clusterzustands. Der API-Server ist die einzige Komponente, die direkt in etcd liest und schreibt — alle anderen Komponenten (Scheduler, Controller-Manager, kubelet) kommunizieren über den API-Server.

MerkmaletcdRedisConsulZooKeeper
KonsensusRaftKeiner (eigenständig)RaftZAB
Starke KonsistenzJaNein (eventual)JaJa
Watch-APIJaNur Pub/SubJaJa
Kubernetes-nativJaNeinNeinNein
TLS integriertJaOptionalJaOptional
BetriebskomplexitätNiedrigSehr niedrigMittelHoch

etcd ist für Kubernetes optimal geeignet, weil es speziell für Control-Plane-Anwendungsfälle entwickelt wurde: kleine Werte, hohe Leserate, seltene Schreibvorgänge und Korrektheit vor rohem Durchsatz.

etcd installieren

Lade die neueste Version aus dem offiziellen GitHub-Repository herunter. Zum Zeitpunkt dieser Verfassung ist 3.5.x die stabile Serie, die für Kubernetes 1.29+ empfohlen wird.

ETCD_VER=v3.5.12
DOWNLOAD_URL=https://github.com/etcd-io/etcd/releases/download

curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz \
  -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz

tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/

sudo mv /tmp/etcd-${ETCD_VER}-linux-amd64/etcd /usr/local/bin/
sudo mv /tmp/etcd-${ETCD_VER}-linux-amd64/etcdctl /usr/local/bin/
sudo mv /tmp/etcd-${ETCD_VER}-linux-amd64/etcdutl /usr/local/bin/

etcd --version
etcdctl version

Erstelle das Datenverzeichnis und einen dedizierten Systembenutzer:

sudo groupadd --system etcd
sudo useradd -s /sbin/nologin --system -g etcd etcd
sudo mkdir -p /var/lib/etcd
sudo chown -R etcd:etcd /var/lib/etcd
sudo chmod 700 /var/lib/etcd

TLS-Zertifikate erstellen

Betreibe etcd niemals ohne TLS in einer anderen Umgebung als einem lokalen Laptop. etcd speichert Secrets und Zugangsdaten — jeder unverschlüsselte Listener ist ein unmittelbares Sicherheitsrisiko.

Installiere cfssl:

curl -Lo /usr/local/bin/cfssl \
  https://github.com/cloudflare/cfssl/releases/latest/download/cfssl_linux-amd64
curl -Lo /usr/local/bin/cfssljson \
  https://github.com/cloudflare/cfssl/releases/latest/download/cfssljson_linux-amd64
chmod +x /usr/local/bin/cfssl /usr/local/bin/cfssljson

Erstelle eine CA und ein Server-Zertifikat. Speichere folgendes als ca-config.json:

{
  "signing": {
    "default": { "expiry": "87600h" },
    "profiles": {
      "etcd": {
        "expiry": "87600h",
        "usages": ["signing","key encipherment","server auth","client auth"]
      }
    }
  }
}

Generiere die CA- und Server-Zertifikate:

# CA
cfssl gencert -initca ca-csr.json | cfssljson -bare ca

# Server + Peer-Zertifikat (alle Node-IPs/Hostnamen im CSR-hosts-Array hinzufügen)
cfssl gencert \
  -ca=ca.pem -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=etcd \
  etcd-csr.json | cfssljson -bare etcd

sudo mkdir -p /etc/etcd/pki
sudo cp ca.pem etcd.pem etcd-key.pem /etc/etcd/pki/
sudo chown -R etcd:etcd /etc/etcd/pki
sudo chmod 600 /etc/etcd/pki/*-key.pem

Einen Drei-Knoten-etcd-Cluster einrichten

Ein Produktions-etcd-Cluster benötigt drei oder fünf Mitglieder. Mit drei Mitgliedern toleriert er einen Ausfall und behält trotzdem das Quorum. Mit fünf Mitgliedern werden zwei gleichzeitige Ausfälle toleriert.

Angenommen, drei Nodes mit folgenden IPs:

  • etcd-1: 10.0.0.11
  • etcd-2: 10.0.0.12
  • etcd-3: 10.0.0.13

Erstelle /etc/etcd/etcd.conf.yml auf jedem Node und ersetze dabei die node-spezifischen Werte:

# /etc/etcd/etcd.conf.yml — Beispiel für etcd-1
name: etcd-1
data-dir: /var/lib/etcd

listen-peer-urls: https://10.0.0.11:2380
listen-client-urls: https://10.0.0.11:2379,https://127.0.0.1:2379

advertise-client-urls: https://10.0.0.11:2379
initial-advertise-peer-urls: https://10.0.0.11:2380

initial-cluster: >-
  etcd-1=https://10.0.0.11:2380,
  etcd-2=https://10.0.0.12:2380,
  etcd-3=https://10.0.0.13:2380
initial-cluster-token: etcd-cluster-prod-01
initial-cluster-state: new

client-transport-security:
  cert-file: /etc/etcd/pki/etcd.pem
  key-file: /etc/etcd/pki/etcd-key.pem
  trusted-ca-file: /etc/etcd/pki/ca.pem
  client-cert-auth: true

peer-transport-security:
  cert-file: /etc/etcd/pki/etcd.pem
  key-file: /etc/etcd/pki/etcd-key.pem
  trusted-ca-file: /etc/etcd/pki/ca.pem
  peer-client-cert-auth: true

Erstelle die systemd-Unit /etc/systemd/system/etcd.service auf allen Nodes:

[Unit]
Description=etcd distributed key-value store
Documentation=https://etcd.io
After=network.target

[Service]
User=etcd
Group=etcd
Type=notify
ExecStart=/usr/local/bin/etcd --config-file /etc/etcd/etcd.conf.yml
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Starte den Cluster — alle drei Nodes müssen innerhalb des Election-Timeouts (Standard 1 Sekunde) starten, damit der initiale Bootstrap gelingt:

# Auf allen drei Nodes schnell hintereinander ausführen
sudo systemctl daemon-reload
sudo systemctl enable --now etcd

Überprüfe, ob sich der Cluster korrekt gebildet hat:

export ETCDCTL_API=3
export ETCDCTL_ENDPOINTS=https://10.0.0.11:2379,https://10.0.0.12:2379,https://10.0.0.13:2379
export ETCDCTL_CACERT=/etc/etcd/pki/ca.pem
export ETCDCTL_CERT=/etc/etcd/pki/etcd.pem
export ETCDCTL_KEY=/etc/etcd/pki/etcd-key.pem

etcdctl endpoint health
etcdctl endpoint status --write-out=table
etcdctl member list --write-out=table

etcd-Backup und Snapshot-Wiederherstellung

Ein etcd-Backup ist in der Produktion unverzichtbar. Ein Snapshot erfasst den gesamten Key-Value-Store zu einem bestimmten Zeitpunkt. Erstelle immer ein Backup vor dem Upgrade von etcd oder Kubernetes.

Einen Snapshot erstellen

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/etcd/pki/ca.pem \
  --cert=/etc/etcd/pki/etcd.pem \
  --key=/etc/etcd/pki/etcd-key.pem

# Snapshot überprüfen
ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-snapshot-*.db --write-out=table

Automatisiere dies mit einem Cron-Job, der alte Snapshots rotiert:

# /etc/cron.d/etcd-backup
0 2 * * * etcd /usr/local/bin/etcdctl snapshot save \
  /backup/etcd-$(date +\%Y\%m\%d).db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/etcd/pki/ca.pem \
  --cert=/etc/etcd/pki/etcd.pem \
  --key=/etc/etcd/pki/etcd-key.pem && \
  find /backup/ -name "etcd-*.db" -mtime +7 -delete

Aus einem Snapshot wiederherstellen

Bei der Wiederherstellung wird das Datenverzeichnis ersetzt. Führe dies auf jedem Mitglied im Cluster durch:

# 1. etcd auf ALLEN Nodes zuerst stoppen
sudo systemctl stop etcd

# 2. Auf jedem Node wiederherstellen (eindeutigen --name und --initial-advertise-peer-urls pro Node verwenden)
ETCDCTL_API=3 etcdutl snapshot restore /backup/etcd-snapshot.db \
  --name etcd-1 \
  --initial-cluster "etcd-1=https://10.0.0.11:2380,etcd-2=https://10.0.0.12:2380,etcd-3=https://10.0.0.13:2380" \
  --initial-cluster-token etcd-cluster-prod-01 \
  --initial-advertise-peer-urls https://10.0.0.11:2380 \
  --data-dir /var/lib/etcd-restored

# 3. Datenverzeichnis tauschen
sudo mv /var/lib/etcd /var/lib/etcd-old
sudo mv /var/lib/etcd-restored /var/lib/etcd
sudo chown -R etcd:etcd /var/lib/etcd

# 4. etcd auf ALLEN Nodes starten
sudo systemctl start etcd

Praxisszenario: Wiederherstellung einer Kubernetes-Control-Plane

Du hast einen Drei-Knoten-Kubernetes-Cluster, bei dem ein Control-Plane-Node seine Festplatte verloren hat. Das etcd-Mitglied auf diesem Node ist nicht mehr vorhanden, und kubectl get nodes hängt nun, weil der API-Server kein Schreib-Quorum mehr erreichen kann.

Der Wiederherstellungspfad:

  1. Aktuelle Mitgliedschaft prüfen von einem gesunden Node: etcdctl member list. Du siehst das ausgefallene Mitglied mit einer leeren URL.
  2. Das tote Mitglied entfernen: etcdctl member remove <MEMBER_ID>
  3. Einen neuen Node bereitstellen mit demselben Hostnamen und derselben IP (oder DNS aktualisieren).
  4. Den Ersatz hinzufügen: etcdctl member add etcd-1-new --peer-urls=https://10.0.0.11:2380
  5. etcd auf dem neuen Node starten mit ETCD_INITIAL_CLUSTER_STATE=existing in der Konfiguration — verwende nicht new.
  6. Die Synchronisierung des neuen Mitglieds beobachten: etcdctl endpoint status zeigt in Echtzeit, wie die Revisionsnummer aufholt.

Der gesamte Prozess dauert typischerweise fünf bis zehn Minuten für einen Cluster mit weniger als 1 GB etcd-Daten. Während der Entfernung und bevor das neue Mitglied das Quorum erreicht, bedient Kubernetes weiterhin Leseanfragen, blockiert aber Schreibvorgänge.

Fallstricke und Sonderfälle

Betreibe niemals eine gerade Anzahl von etcd-Mitgliedern. Ein Zwei-Mitglieder-Cluster bietet keine Fehlertoleranz — der Verlust eines Mitglieds führt sofort zum Verlust des Quorums. Ein Vier-Mitglieder-Cluster toleriert nur einen Ausfall, genauso wie ein Drei-Mitglieder-Cluster, benötigt aber einen zusätzlichen Node. Bleibe bei 3 oder 5.

Festplatten-I/O ist der primäre etcd-Engpass. etcd ruft bei jedem Schreibvorgang fdatasync auf. Wenn deine Festplattenlatenz dauerhaft 10 ms überschreitet, wirst du Leader-Wahlen und request timeout-Fehler in Kubernetes sehen. Verwende SSDs oder NVMe-Speicher. Prüfe die Festplattenlatenz mit: fio --rw=write --ioengine=sync --fdatasync=1 --directory=/var/lib/etcd --size=22m --bs=2300 --name=etcd-bench.

etcd ist keine Allzweck-Datenbank. Das Standard-Speicherkontingent beträgt 2 GB. Kubernetes-Cluster mit vielen Objekten oder intensiver Nutzung von Custom Resources können dieses Limit erreichen. Überwache etcd_mvcc_db_total_size_in_bytes in Prometheus und komprimiere/defragmentiere regelmäßig:

# Alte Revisionen komprimieren (letzte 1000 behalten)
rev=$(etcdctl endpoint status --write-out=json | jq '.[0].Status.header.revision')
etcdctl compact $((rev - 1000))
etcdctl defrag --cluster

Uhrzeitsabweichung verursacht Leader-Wahlen. etcd verwendet die Wanduhrzeit für den Ablauf von Leases. Wenn Nodes um mehr als einige hundert Millisekunden abweichen, wirst du unbeabsichtigte Leader-Wahlen sehen. Führe NTP (chrony oder systemd-timesyncd) auf allen etcd-Nodes aus und überprüfe es mit chronyc tracking.

Snapshot-Wiederherstellung löscht die Cluster-Mitgliedschaft. Nach der Wiederherstellung werden alle Mitglieder als brandneuer Cluster mit der im Snapshot codierten Mitgliedschaft behandelt. Stelle niemals einen Snapshot auf einem laufenden Cluster wieder her, ohne zuerst alle Mitglieder zu stoppen — du wirst eine Split-Brain-Situation erzeugen.

Fehlerbehebung

etcdserver: request timed out — Normalerweise Festplattenlatenz. Prüfe iostat -x 1 auf etcd-Nodes. Überprüfe auch die Peer-Verbindung: etcdctl endpoint health von jedem Node einzeln.

etcdserver: mvcc: database space exceeded — Das 2-GB-Speicherkontingent wurde erreicht. Führe Komprimierung und Defragmentierung wie oben beschrieben durch, oder erhöhe das Kontingent mit --quota-backend-bytes=4294967296 (4 GB) in der etcd-Konfiguration.

raft: failed to send message — Firewall blockiert Port 2380 zwischen Peers, oder ein CN-Fehler im Peer-Zertifikat. Überprüfe mit openssl s_client -connect 10.0.0.12:2380 von einem anderen etcd-Node.

certificate has expired — etcd-Peer- und Client-Zertifikate müssen vor dem Ablauf rotiert werden. Kubernetes-kubeadm-Cluster rotieren diese automatisch im Zeitraum von 90 Tagen bis 1 Jahr, manuell verwaltete Cluster jedoch nicht. Ablaufdatum prüfen: openssl x509 -in /etc/etcd/pki/etcd.pem -noout -dates.

etcd verbraucht zu viel Arbeitsspeicher — etcd hält den Arbeitssatz im Speicher. Bei Clustern mit vielen Objekten kann der RSS-Wert 8 GB überschreiten. Das ist normal. Setze --snapshot-count=5000 (Standard 100000), um häufigere Snapshots auszulösen und die Raft-Log-Größe im Speicher zu reduzieren.

Zusammenfassung

  • etcd speichert den gesamten Kubernetes-Clusterzustand; es ist der kritischste Dienst in der Control-Plane
  • Immer drei oder fünf Mitglieder für die Produktion einsetzen — nur ungerade Zahlen
  • Gegenseitiges TLS auf Client- und Peer-Ports aktivieren; etcd niemals ohne Authentifizierung exponieren
  • Täglich Snapshots mit etcdctl snapshot save erstellen und mit snapshot status überprüfen
  • Wiederherstellung durch Stoppen aller Mitglieder, Ausführen von etcdutl snapshot restore auf jedem mit eindeutigen Node-Parametern, Tauschen des Datenverzeichnisses und anschließendem Neustart
  • Festplattenlatenz überwachen (unter 10 ms halten), Datenbankgröße (komprimieren wenn 2 GB erreicht werden) und Leader-Stabilität
  • etcdctl member remove + member add verwenden, um einen ausgefallenen Node ohne vollständige Wiederherstellung zu ersetzen

Verwandte Artikel