etcd ist ein verteilter Key-Value Store für Konfigurationsdaten und Service Discovery. Es bildet das Rückgrat von Kubernetes und anderen verteilten Systemen.

Installation

# Binary herunterladen
ETCD_VER=v3.5.11
wget https://github.com/etcd-io/etcd/releases/download/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar xzf etcd-${ETCD_VER}-linux-amd64.tar.gz
mv etcd-${ETCD_VER}-linux-amd64/etcd* /usr/local/bin/

# Version prüfen
etcd --version
etcdctl version

Single-Node Setup

Starten

# Einfach starten
etcd

# Mit Konfiguration
etcd \
    --name node1 \
    --data-dir /var/lib/etcd \
    --listen-client-urls http://0.0.0.0:2379 \
    --advertise-client-urls http://192.168.1.10:2379

Systemd-Service

# /etc/systemd/system/etcd.service
[Unit]
Description=etcd key-value store
After=network.target

[Service]
Type=notify
ExecStart=/usr/local/bin/etcd \
    --name node1 \
    --data-dir /var/lib/etcd \
    --listen-client-urls http://0.0.0.0:2379 \
    --advertise-client-urls http://192.168.1.10:2379
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
systemctl enable etcd
systemctl start etcd

Cluster Setup

3-Node Cluster

# Node 1
etcd \
    --name node1 \
    --initial-advertise-peer-urls http://192.168.1.10:2380 \
    --listen-peer-urls http://192.168.1.10:2380 \
    --listen-client-urls http://192.168.1.10:2379,http://127.0.0.1:2379 \
    --advertise-client-urls http://192.168.1.10:2379 \
    --initial-cluster-token etcd-cluster \
    --initial-cluster node1=http://192.168.1.10:2380,node2=http://192.168.1.11:2380,node3=http://192.168.1.12:2380 \
    --initial-cluster-state new

# Node 2
etcd \
    --name node2 \
    --initial-advertise-peer-urls http://192.168.1.11:2380 \
    --listen-peer-urls http://192.168.1.11:2380 \
    --listen-client-urls http://192.168.1.11:2379,http://127.0.0.1:2379 \
    --advertise-client-urls http://192.168.1.11:2379 \
    --initial-cluster-token etcd-cluster \
    --initial-cluster node1=http://192.168.1.10:2380,node2=http://192.168.1.11:2380,node3=http://192.168.1.12:2380 \
    --initial-cluster-state new

# Node 3 analog

etcdctl Befehle

Schreiben und Lesen

# API-Version setzen
export ETCDCTL_API=3

# Key setzen
etcdctl put /config/database/host "db.example.de"
etcdctl put /config/database/port "5432"

# Key lesen
etcdctl get /config/database/host

# Mit Prefix
etcdctl get --prefix /config/database/

# Alle Keys
etcdctl get --prefix ""

Löschen

# Einzelner Key
etcdctl del /config/database/host

# Mit Prefix
etcdctl del --prefix /config/database/

Lease (TTL)

# Lease erstellen (60 Sekunden)
etcdctl lease grant 60
# lease 123456789 granted with TTL(60s)

# Key mit Lease
etcdctl put --lease=123456789 /services/web1 "192.168.1.10:8080"

# Lease erneuern
etcdctl lease keep-alive 123456789

# Lease widerrufen
etcdctl lease revoke 123456789

Watch

# Auf Änderungen warten
etcdctl watch /config/database/host

# Mit Prefix
etcdctl watch --prefix /config/

# In anderem Terminal: Änderung auslösen
etcdctl put /config/database/host "new-db.example.de"

TLS-Verschlüsselung

Zertifikate erstellen

# CA
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -subj "/CN=etcd-ca"

# Server-Zertifikat
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr -subj "/CN=etcd-server"
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365

TLS konfigurieren

etcd \
    --name node1 \
    --cert-file=/etc/etcd/ssl/server.crt \
    --key-file=/etc/etcd/ssl/server.key \
    --trusted-ca-file=/etc/etcd/ssl/ca.crt \
    --client-cert-auth \
    --peer-cert-file=/etc/etcd/ssl/server.crt \
    --peer-key-file=/etc/etcd/ssl/server.key \
    --peer-trusted-ca-file=/etc/etcd/ssl/ca.crt \
    --listen-client-urls https://192.168.1.10:2379 \
    --advertise-client-urls https://192.168.1.10:2379

Client mit TLS

etcdctl --cacert=/etc/etcd/ssl/ca.crt \
    --cert=/etc/etcd/ssl/client.crt \
    --key=/etc/etcd/ssl/client.key \
    --endpoints=https://192.168.1.10:2379 \
    get /config/key

Authentifizierung

Auth aktivieren

# Root-User erstellen
etcdctl user add root

# Auth aktivieren
etcdctl auth enable

User und Rollen

# Rolle erstellen
etcdctl role add app-role
etcdctl role grant-permission app-role readwrite /app/

# User erstellen
etcdctl user add app-user
etcdctl user grant-role app-user app-role

# Mit Auth nutzen
etcdctl --user=app-user:password get --prefix /app/

Backup und Restore

Snapshot erstellen

# Snapshot
etcdctl snapshot save /backup/etcd-$(date +%Y%m%d).db

# Status prüfen
etcdctl snapshot status /backup/etcd-20240126.db

Restore

# Restore (neuer Datenordner!)
etcdctl snapshot restore /backup/etcd-20240126.db \
    --name node1 \
    --initial-cluster node1=http://192.168.1.10:2380 \
    --initial-advertise-peer-urls http://192.168.1.10:2380 \
    --data-dir /var/lib/etcd-restored

Cluster-Management

Status prüfen

# Cluster-Health
etcdctl endpoint health

# Member-Liste
etcdctl member list

# Status
etcdctl endpoint status --cluster

Member hinzufügen

# Neuen Member ankündigen
etcdctl member add node4 --peer-urls=http://192.168.1.13:2380

# Dann node4 mit --initial-cluster-state=existing starten

Member entfernen

# Member-ID ermitteln
etcdctl member list

# Entfernen
etcdctl member remove MEMBER_ID

Defragmentierung

# Speicher freigeben
etcdctl defrag --endpoints=http://192.168.1.10:2379

# Auf allen Nodes
etcdctl defrag --cluster

Metriken

# Prometheus-Metriken
curl http://localhost:2379/metrics

# In Prometheus-Konfiguration
- job_name: 'etcd'
  static_configs:
    - targets: ['192.168.1.10:2379', '192.168.1.11:2379', '192.168.1.12:2379']

Praktisches Beispiel

Service Discovery

# Service registrieren (mit Lease)
LEASE=$(etcdctl lease grant 30 | awk '{print $2}')
etcdctl put --lease=$LEASE /services/web/192.168.1.10 '{"port":8080,"healthy":true}'

# Services auflisten
etcdctl get --prefix /services/web/

# Heartbeat (in Schleife)
while true; do
    etcdctl lease keep-alive $LEASE
    sleep 10
done

Konfiguration

# App-Konfiguration speichern
etcdctl put /config/myapp/database '{"host":"db.local","port":5432}'
etcdctl put /config/myapp/cache '{"host":"redis.local","port":6379}'

# App liest Konfiguration
etcdctl get --prefix /config/myapp/

Zusammenfassung

| Befehl | Funktion | |--------|----------| | etcdctl put | Key setzen | | etcdctl get | Key lesen | | etcdctl del | Key löschen | | etcdctl watch | Auf Änderungen warten | | etcdctl lease | TTL verwalten | | etcdctl snapshot | Backup | | etcdctl member | Cluster-Member |

| Port | Verwendung | |------|------------| | 2379 | Client-Kommunikation | | 2380 | Peer-Kommunikation |

| Option | Beschreibung | |--------|--------------| | --prefix | Alle mit Prefix | | --lease | Mit TTL | | --endpoints | Server-Liste |

Fazit

etcd ist essentiell für verteilte Systeme und Kubernetes. Der Raft-Konsens garantiert Konsistenz. Watches ermöglichen reaktive Konfiguration. TLS und Auth sind für Produktion zwingend. Regelmäßige Backups sind wichtig, da etcd kritische Daten enthält.