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
curlundtarinstalliert- Für TLS:
cfssloderopensslverfü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.
| Merkmal | etcd | Redis | Consul | ZooKeeper |
|---|---|---|---|---|
| Konsensus | Raft | Keiner (eigenständig) | Raft | ZAB |
| Starke Konsistenz | Ja | Nein (eventual) | Ja | Ja |
| Watch-API | Ja | Nur Pub/Sub | Ja | Ja |
| Kubernetes-nativ | Ja | Nein | Nein | Nein |
| TLS integriert | Ja | Optional | Ja | Optional |
| Betriebskomplexität | Niedrig | Sehr niedrig | Mittel | Hoch |
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.11etcd-2: 10.0.0.12etcd-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:
- Aktuelle Mitgliedschaft prüfen von einem gesunden Node:
etcdctl member list. Du siehst das ausgefallene Mitglied mit einer leeren URL. - Das tote Mitglied entfernen:
etcdctl member remove <MEMBER_ID> - Einen neuen Node bereitstellen mit demselben Hostnamen und derselben IP (oder DNS aktualisieren).
- Den Ersatz hinzufügen:
etcdctl member add etcd-1-new --peer-urls=https://10.0.0.11:2380 - etcd auf dem neuen Node starten mit
ETCD_INITIAL_CLUSTER_STATE=existingin der Konfiguration — verwende nichtnew. - Die Synchronisierung des neuen Mitglieds beobachten:
etcdctl endpoint statuszeigt 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 saveerstellen und mitsnapshot statusüberprüfen - Wiederherstellung durch Stoppen aller Mitglieder, Ausführen von
etcdutl snapshot restoreauf 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 addverwenden, um einen ausgefallenen Node ohne vollständige Wiederherstellung zu ersetzen