← 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_secondsP99 > 10ms на конкретном memberetcd_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 для небольших кластеров.