etcd — distributed key-value store: konfiguracja klastra
Opublikowano: 10 kwietnia 2026 · Kategoria: VPS / DevOps
etcd to rozproszony magazyn klucz-wartość napisany przez CoreOS (dziś w ramach CNCF), zaprojektowany z myślą o niezawodności i spójności danych w rozproszonych systemach. Jest fundamentem Kubernetes — przechowuje cały stan klastra. Ale etcd ma też zastosowania poza K8s: service discovery, distributed locks, feature flags, konfiguracja dynamiczna mikroserwisów. Algorytm Raft, którego używa, gwarantuje silną spójność danych nawet gdy część węzłów awarii. Ten artykuł przeprowadzi Cię przez budowę 3-węzłowego klastra etcd od instalacji po monitorowanie.
Instalacja etcd — binary i systemd
# Pobierz najnowsza wersje etcd
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.tar.gz
tar xzvf /tmp/etcd.tar.gz -C /usr/local/bin \
--strip-components=1 \
etcd-${ETCD_VER}-linux-amd64/etcd \
etcd-${ETCD_VER}-linux-amd64/etcdctl
# Weryfikacja
etcd --version
etcdctl version
# Katalogi danych
sudo mkdir -p /var/lib/etcd /etc/etcd
sudo useradd -r -s /sbin/nologin etcd
sudo chown etcd:etcd /var/lib/etcd Konfiguracja 3-węzłowego klastra
Poniżej konfiguracja dla 3 węzłów z IP: 10.0.0.1 (etcd-1),
10.0.0.2 (etcd-2), 10.0.0.3 (etcd-3). Na każdym węźle dostosuj ETCD_NAME i ETCD_INITIAL_ADVERTISE_PEER_URLS.
# /etc/etcd/etcd.conf (na wezle etcd-1, IP 10.0.0.1) ETCD_NAME="etcd-1" ETCD_DATA_DIR="/var/lib/etcd" ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379" ETCD_ADVERTISE_CLIENT_URLS="http://10.0.0.1:2379" ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380" ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.0.1:2380" # Inicjalny klaster - wszy wszystkie 3 wezly ETCD_INITIAL_CLUSTER="etcd-1=http://10.0.0.1:2380,etcd-2=http://10.0.0.2:2380,etcd-3=http://10.0.0.3:2380" ETCD_INITIAL_CLUSTER_STATE="new" ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-prod" # /etc/systemd/system/etcd.service # [Unit] # Description=etcd key-value store # After=network.target # # [Service] # User=etcd # EnvironmentFile=/etc/etcd/etcd.conf # ExecStart=/usr/local/bin/etcd # Restart=always # RestartSec=5 # LimitNOFILE=65536 # # [Install] # WantedBy=multi-user.target sudo systemctl daemon-reload sudo systemctl enable --now etcd # Sprawdz status klastra etcdctl --endpoints=http://10.0.0.1:2379,http://10.0.0.2:2379,http://10.0.0.3:2379 \ member list # Wynik: ID, status, nazwa, URL peera
etcdctl — podstawowe operacje
# Ustaw endpoint jako zmienna (wygoda)
export ETCDCTL_ENDPOINTS="http://10.0.0.1:2379,http://10.0.0.2:2379,http://10.0.0.3:2379"
export ETCDCTL_API=3
# Podstawowe operacje CRUD
etcdctl put /config/db/host "10.0.0.5"
etcdctl put /config/db/port "5432"
etcdctl put /config/app/env "production"
# Odczyt
etcdctl get /config/db/host
etcdctl get /config --prefix # Wszystkie klucze z prefiksem
etcdctl get /config --prefix --keys-only # Tylko klucze
# Wersjonowanie - historia zmian klucza
etcdctl put /config/db/host "10.0.0.6" # Zmien wartosc
etcdctl get /config/db/host --rev=1 # Poprzednia wartosc
# Watch - obserwowanie zmian w czasie rzeczywistym
etcdctl watch /config --prefix # Ctrl+C aby przerwac
# W innym terminalu: etcdctl put /config/new-key "new-val"
# Watch wyswietli zdarzenie CREATE
# Lease - klucze z TTL (distributed locks)
LEASE_ID=$(etcdctl lease grant 30 | awk '{print $2}') # 30 sekund TTL
etcdctl put --lease=${LEASE_ID} /locks/my-service "worker-1"
etcdctl lease timetolive ${LEASE_ID} # Ile zostalo
etcdctl lease keepalive ${LEASE_ID} # Odnow lease w tle
# Usuwanie
etcdctl del /config/db/host
etcdctl del /config --prefix # Usun wszystkie z prefiksem
# Status klastra
etcdctl endpoint health
etcdctl endpoint status --write-out=table TLS — szyfrowanie komunikacji klastra
# Wygeneruj CA i certyfikaty (cfssl lub openssl) # Przyklad z openssl: # CA openssl genrsa -out ca.key 4096 openssl req -new -x509 -days 3650 -key ca.key \ -subj "/CN=etcd-ca" -out ca.crt # Certyfikat dla etcd-1 openssl genrsa -out etcd-1.key 4096 openssl req -new -key etcd-1.key \ -subj "/CN=etcd-1" -out etcd-1.csr # SAN - Subject Alternative Names (IP wezla) cat > etcd-1-ext.cnf << 'EOF' [SAN] subjectAltName=IP:10.0.0.1,IP:127.0.0.1 EOF openssl x509 -req -days 365 -CA ca.crt -CAkey ca.key \ -CAcreateserial -in etcd-1.csr -out etcd-1.crt \ -extfile etcd-1-ext.cnf -extensions SAN # Aktualizuj /etc/etcd/etcd.conf - dodaj TLS: # ETCD_LISTEN_CLIENT_URLS="https://0.0.0.0:2379" # ETCD_CERT_FILE="/etc/etcd/tls/etcd-1.crt" # ETCD_KEY_FILE="/etc/etcd/tls/etcd-1.key" # ETCD_TRUSTED_CA_FILE="/etc/etcd/tls/ca.crt" # ETCD_CLIENT_CERT_AUTH="true" # etcdctl z TLS etcdctl --cacert=/etc/etcd/tls/ca.crt \ --cert=/etc/etcd/tls/etcd-1.crt \ --key=/etc/etcd/tls/etcd-1.key \ --endpoints=https://10.0.0.1:2379 \ endpoint health
Backup i restore — snapshot
# Backup (zawsze z jednego zdrowego wezla) etcdctl snapshot save /backup/etcd-$(date +%Y%m%d-%H%M%S).db \ --endpoints=http://10.0.0.1:2379 # Weryfikacja snapshotu etcdctl snapshot status /backup/etcd-20260410-120000.db --write-out=table # hash | revision | totalKey | totalSize # Restore (na NOWYM klastrze, NIE na istniejacym) # Zatrzymaj etcd na wszystkich wezlach: # sudo systemctl stop etcd # Na kazdym wezle wykonaj restore: etcdctl snapshot restore /backup/etcd-20260410-120000.db \ --name etcd-1 \ --initial-cluster "etcd-1=http://10.0.0.1:2380,etcd-2=http://10.0.0.2:2380,etcd-3=http://10.0.0.3:2380" \ --initial-advertise-peer-urls http://10.0.0.1:2380 \ --data-dir /var/lib/etcd-restored # Po restore na wszystkich wezlach: # sudo mv /var/lib/etcd /var/lib/etcd-old # sudo mv /var/lib/etcd-restored /var/lib/etcd # sudo systemctl start etcd # Cron - backup co 6 godzin # 0 */6 * * * etcdctl snapshot save /backup/etcd-$(date +\%Y\%m\%d-\%H).db # Retencja 7 dni: # 0 5 * * * find /backup -name "etcd-*.db" -mtime +7 -delete
Porównanie distributed stores
| Cecha | etcd | ZooKeeper | Consul |
|---|---|---|---|
| Konsensus | Raft | ZAB | Raft |
| Język | Go | Java | Go |
| API | gRPC / HTTP | Binarne / Curator | HTTP REST |
| Service discovery | Ograniczone | Brak (osobny) | Wbudowane |
| Watch API | Tak (gRPC stream) | Tak (watches) | Tak (blocking query) |
| Kubernetes | Natywny backend | Starsze wersje | Opcjonalny |