← Back to notes

etcd: хранилище состояния
кластера Kubernetes


22: Controller Manager | 24: SLA/SLO/RPO/RTO


Роль etcd в кластере

etcd — единственный источник истины для всего состояния кластера. Каждый объект Kubernetes (Pod, Service, Deployment, Secret, ConfigMap) хранится в etcd. API server — единственный компонент, который напрямую читает и пишет в etcd. Все остальные компоненты общаются только через API server.

При деградации etcd API server может отвечать на GET (из watch cache), но write path, reconciliation и scheduling ломаются.

[source: kubernetes.io/docs/concepts/overview/components/#etcd]


Raft consensus protocol

etcd использует Raft для обеспечения consistency между members кластера. Все members видят одну и ту же последовательность операций.

[source: kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/]

Роли

Все writes идут через leader. Followers не принимают writes напрямую. Если leader недоступен — writes невозможны до завершения election (~1-3 секунды).


Полный write path

kubectl apply (write)
  
  
API server
    authn  authz  APF  admission  validation
  
  
etcd client (gRPC)
  
  
etcd leader
  
  ├── 1. Append to WAL (Write-Ahead Log)
  
  ├── 2. fsync WAL to disk
  
  ├── 3. Replicate entry to followers (Raft)
        
        
        Follower-1: append WAL  fsync  ack ──┐
        Follower-2: append WAL  fsync  ack ──┤
                                                
        ◄──── quorum acks received ─────────────┘
  
  ├── 4. Commit (entry считается committed)
  
  ├── 5. Apply to state machine (boltdb)
  
  └── 6. Response  API server  200 OK to client

Каждый write проходит через Raft consensus — гарантия, что данные не потеряются при отказе одного member.


Quorum arithmetic

Quorum = majority = (N/2) + 1 members должны подтвердить write.

Почему 4 members хуже 3

Кластер из 3:  quorum = 2, допустимые потери = 1
Кластер из 4:  quorum = 3, допустимые потери = 1

Та же fault tolerance, но:
  - каждый write требует ack от 3 вместо 2
  - больше latency на consensus
  - больше шансов, что slow member замедлит commit

Правило: всегда нечётное число members. Чётное количество не даёт выигрыша в fault tolerance, но увеличивает overhead.


Потеря quorum: каскад последствий

При потере quorum начинается каскад:

Quorum lost
  
  ├── Writes fail
       ├── Lease renewals fail
            ├── Leader election controller-manager ломается
            └── Leader election scheduler ломается
       ├── Node heartbeats не записываются
            └── Node controller считает nodes unreachable
       └── Новые Pod-ы не создаются
  
  └── Watch events останавливаются
        └── Controllers не видят изменений
              └── Reconciliation замирает

API server может продолжать отвечать на GET (из watch cache), создавая иллюзию работающего кластера.


Чувствительность к disk latency

Каждый Raft entry записывается в WAL и fsync-ается на диск до отправки ack. Это самый чувствительный участок.

fsync latency → состояние кластера

Почему HDD и network-attached storage опасны: нестабильный IOPS означает скачки fsync latency. Один spike до 100ms может вызвать пропущенный heartbeat и ненужный leader election.

Network RTT между members


Цепочка деградации: от диска до пользователя

Slow disk
  
  
Delayed fsync (WAL write медленный)
  
  
Delayed commit (ack от followers приходит позже)
  
  
Delayed watch event (API server получает notify позже)
  
  
Controller видит изменение позже  reconcile lag
  
  
Scheduler видит Pod позже  placement delay
  
  
API write latency растёт  user-facing degradation

Один медленный диск на одном etcd member может замедлить весь control plane.


Сценарии отказов

Scenario 1: Slow disk на одном member

Симптомы: один follower не успевает ack-нуть. Если quorum есть — writes проходят, но latency растёт. Если slow member — leader — деградация немедленная.

Обнаружение:

  • etcd_disk_wal_fsync_duration_seconds P99 > 10ms на конкретном member
  • etcd_server_slow_apply_total растёт
  • etcd_disk_backend_commit_duration_seconds растёт

Scenario 2: Leader churn

Симптомы: leader меняется каждые несколько секунд. Каждый election — пауза writes на 1-3s.

Причины: disk fsync spikes, network packet loss, CPU/memory contention на node с leader.

Обнаружение: etcd_server_leader_changes_seen_total > 0 за короткий период.

Scenario 3: Network partition

         ┌──── network partition ────┐
                                    
    member-1 (leader)          member-2
    member-3                         
                                    
    quorum = 2/3              alone = 1/3 
    writes работают            writes fail

API servers, подключённые к minority partition, отвечают на GET, но все writes fail-ятся.

Scenario 4: Полная потеря quorum

Симптомы: все writes fail. API server отдаёт 500 или timeout на mutating requests.

Последствия:

  • Новые Pod-ы не создаются
  • Lease renewals fail → leader election ломается
  • Node heartbeats не записываются → node controller считает все nodes unreachable
  • Кластер начинает "забывать" свои nodes

Maintenance операции

Compaction и defragmentation

# Compaction: удалить revisions старше текущего
ETCDCTL_API=3 etcdctl compact \
  $(ETCDCTL_API=3 etcdctl endpoint status --write-out="json" \
    --endpoints=https://etcd-1:2379 \
    --cacert=/etc/etcd/ca.crt \
    --cert=/etc/etcd/client.crt \
    --key=/etc/etcd/client.key \
    | jq '.[0].Status.header.revision')

# Defragmentation: вернуть место на диск (по одному member!)
ETCDCTL_API=3 etcdctl defrag \
  --endpoints=https://etcd-1:2379 \
  --cacert=/etc/etcd/ca.crt \
  --cert=/etc/etcd/client.crt \
  --key=/etc/etcd/client.key

ETCDCTL_API=3 etcdctl defrag \
  --endpoints=https://etcd-2:2379 \
  --cacert=/etc/etcd/ca.crt \
  --cert=/etc/etcd/client.crt \
  --key=/etc/etcd/client.key

API server с Kubernetes 1.26+ выполняет auto-compaction по умолчанию (каждые 5 минут). Defragmentation — ручная операция, требует последовательного выполнения (не одновременно на всех members).

Snapshot и restore

# Создать snapshot
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot-$(date +%Y%m%d-%H%M%S).db \
  --endpoints=https://etcd-1:2379 \
  --cacert=/etc/etcd/ca.crt \
  --cert=/etc/etcd/client.crt \
  --key=/etc/etcd/client.key

# Проверить snapshot
ETCDCTL_API=3 etcdctl snapshot status \
  /backup/etcd-snapshot.db \
  --write-out=table

# Restore (создаёт новый data directory)
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot.db \
  --data-dir=/var/lib/etcd-restored \
  --name=etcd-1 \
  --initial-cluster=etcd-1=https://etcd-1:2380,etcd-2=https://etcd-2:2380,etcd-3=https://etcd-3:2380 \
  --initial-cluster-token=etcd-cluster-new \
  --initial-advertise-peer-urls=https://etcd-1:2380

Restore создаёт новый кластер с данными из snapshot. Все данные, записанные после snapshot — потеряны. Выполнять restore нужно на всех members с одним snapshot файлом.

Quota alarm и разблокировка

# Проверить текущий размер и quota
ETCDCTL_API=3 etcdctl endpoint status --write-out=table \
  --endpoints=https://etcd-1:2379,https://etcd-2:2379,https://etcd-3:2379 \
  --cacert=/etc/etcd/ca.crt \
  --cert=/etc/etcd/client.crt \
  --key=/etc/etcd/client.key

# Снять alarm после compaction + defrag
ETCDCTL_API=3 etcdctl alarm disarm \
  --endpoints=https://etcd-1:2379 \
  --cacert=/etc/etcd/ca.crt \
  --cert=/etc/etcd/client.crt \
  --key=/etc/etcd/client.key

Quota alarm workflow:

etcd db size  приближается к quota (default 2GB)
  
  
Quota alarm triggered
  
  
etcd блокирует ВСЕ writes
  
  
API server: все mutating requests fail
  
  
Ручное вмешательство:
  1. etcdctl compact (удалить старые revisions)
  2. etcdctl defrag (вернуть место на диск)
  3. etcdctl alarm disarm (снять alarm)

Sizing recommendations

Критично: etcd на shared disk с другими workloads — главная причина нестабильности. Диск должен быть dedicated и SSD. NVMe предпочтительнее SATA SSD.

[source: kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/#hardware-recommendations]


Влияние на три пути control plane


Сигналы мониторинга

Disk и storage

Consensus и leadership

Network

Что мониторить в первую очередь:

# etcd жив и имеет leader?
etcd_server_is_leader == 1 (ровно на одном member)

# Диск справляется?
etcd_disk_wal_fsync_duration_seconds P99 < 10ms

# Leader стабилен?
rate(etcd_server_leader_changes_seen_total) == 0 за последние 10 минут

# База не переполнена?
etcd_mvcc_db_total_size_in_bytes / etcd_server_quota_backend_bytes < 0.8

Когда использовать

3-member etcd:

  • Dev/staging кластеры, production с небольшой нагрузкой.
  • Выживает потерю 1 member. Достаточно для большинства prod кластеров.

5-member etcd:

  • Критичные production кластеры, где важна устойчивость к потере 2 members.
  • Multi-AZ deployments: по одному member на AZ + 2 в основной AZ.
  • Больше overhead на каждый write, но higher fault tolerance.

Dedicated etcd nodes:

  • Всегда для production. etcd не должен делить диск с kubelet, containerd или другими workloads.
  • Taints + tolerations или dedicated node group.

Snapshot frequency:

  • Минимум — ежедневный automated snapshot. Лучше — каждый час.
  • Хранить off-cluster (S3, GCS). Snapshot на том же диске что и etcd бесполезен при disk failure.
  • Регулярно тестировать restore.

Типичные ошибки

1. etcd на shared SSD с другими workloads

Если kubelet или containerd создают интенсивный disk I/O, fsync latency etcd вырастет. Leader churn, нестабильный control plane. Решение: dedicated disk для etcd или dedicated nodes.

2. Чётное количество members (2 или 4)

2 members = quorum=2, допустимые потери=0. Хуже, чем 1 member (нет fault tolerance + write overhead). 4 members = quorum=3, та же fault tolerance что у 3-member кластера. Всегда нечётное количество.

3. Не тестировать restore

Snapshot создаётся, но restore никогда не тестировался. При реальной аварии оказывается, что snapshot corrupted или процедура restore незнакома команде. Регулярный drill restore — обязателен.

4. Игнорировать etcd_server_leader_changes_seen_total

Один leader change за сутки — нормально (плановые операции). Несколько за час — признак нестабильности (disk latency spikes, network issues). Без alert-а на этот counter проблема остаётся незамеченной.

5. Defrag на всех members одновременно

Defragmentation блокирует member на время выполнения. Одновременный defrag на 2 из 3 members уничтожает quorum. Всегда по одному, с паузой между операциями.

6. Не следить за размером базы

etcd растёт постепенно. Quota alarm срабатывает неожиданно, кластер уходит в read-only. Настройте alert на etcd_mvcc_db_total_size_in_bytes > 80% quota.


Альтернативы

etcd в production Kubernetes не заменяется — это требование. Контекст:

Managed etcd (EKS/GKE/AKS): провайдер управляет backup, upgrade, failover. Снимает operational overhead, ограничивает visibility.

k3s с SQLite/PostgreSQL: lightweight Kubernetes для edge/IoT с одним control plane node. Не для production HA.

kine: shim для работы API server с PostgreSQL/MySQL. Используется в k3s. Теряет часть etcd-гарантий (watch semantics), снижает operational complexity для небольших кластеров.


22: Controller Manager | 24: SLA/SLO/RPO/RTO

etcd: хранилище состояния кластера Kubernetes | Aleksandr Suprun