Späť na blog

etcd Watch Replay Búrky: Keď Obrovské ConfigMapy Zabíjajú Control Plane

|
| kubernetes, etcd, control-plane, debugging, configmap, performance

etcd je tichy, kym sa watch replay nezmeni na burku. “Kubernetes apiserver je náhodne pomalý.” Pridali sme viac CPU, viac pamäte—nič nepomohlo. Príčina: 500KB ConfigMap s rotujúcimi certifikátmi, aktualizovaný každú hodinu, spúšťajúci kaskádovú watch replay búrku naprieč všetkými kontrolérmi.

Prostredie: Kubernetes 1.27, 3-node etcd cluster, 150+ kontrolérov sledujúcich rôzne zdroje

Problém

Symptómy

Čo sme pozorovali:

Normálny deň:
  kubectl get pods        → 50ms
  API latency p99         → 100ms
  etcd latency p99        → 10ms

Počas "náhodných spomalení":
  kubectl get pods        → 5-30 sekúnd
  API latency p99         → 10+ sekúnd
  etcd latency p99        → 500ms+

Vzor:
- Stáva sa zhruba raz za hodinu
- Trvá 2-5 minút
- Žiadny zjavný trigger v aplikačnej vrstve
- Koreluje s... rotáciou certifikátov?

Prečo Štandardný Monitoring Toto Nezachytí

# CPU a pamäť vyzerajú dobre
kubectl top pods -n kube-system
# etcd: CPU 30%, Memory 40%
# apiserver: CPU 50%, Memory 60%

# etcd health hovorí že všetko je v poriadku
etcdctl endpoint health
# healthy: true

# Problém je skrytý v mechanizme watches
# a viditeľný len v špecifických metrikách

Príčina

Ako Watches Fungujú

Normálny watch flow:

Kontrolér: "Sleduj pody od revízie 12345"

apiserver:   Proxuje watch do etcd

etcd:        "Tu sú eventy od 12345:
              - Pod A vytvorený (rev 12346)
              - Pod B zmazaný (rev 12347)
              - ..."

Kontrolér:   Spracováva eventy jeden po druhom

Čo Sa Stane Pri Compaction

etcd compaction scenár:

Kontrolér: "Sleduj pody od revízie 12345"

etcd:        "Prepáč, revízia 12345 bola compactnutá!
              Najstaršia dostupná je 50000"

apiserver:   Vráti chybu kontroléru

Kontrolér:   "Musím RELISTOVAŤ všetko!"
              Listuje VŠETKY pody (môžu byť tisíce)
              Vytvára nový watch od aktuálnej revízie

Teraz si predstav že 150 kontrolérov narazí na toto naraz...

Problém Obrovského Objektu

Kaskáda:

1. Obrovský ConfigMap (500KB) aktualizovaný
   └─▶ Generuje veľkú etcd transakciu

2. Transakcia rýchlo zvyšuje revíziu
   └─▶ Staršie revízie sa compactujú rýchlejšie

3. Pomalý watcher zaostáva
   └─▶ Jeho sledovaná revízia sa compactuje
        └─▶ Kontrolér nútený relistovať

4. Relist tisícov objektov
   └─▶ Pridáva záťaž na apiserver
        └─▶ Ďalší watcheri zaostávajú
             └─▶ Viac compactions
                  └─▶ Viac relistov
                       └─▶ BÚRKA!

┌─────────────────────────────────────────────────┐
│                 Búrka                           │
│                                                 │
│    ConfigMap    Veľký       Rýchla              │
│      update  →  nárast   →  compaction          │
│                 revízie                         │
│         ↓                                       │
│    Watcher 1 zaostáva → Relist 10000 objektov   │
│    Watcher 2 zaostáva → Relist 5000 objektov    │
│    Watcher N zaostáva → Relist ...              │
│         ↓                                       │
│    API Server preťažený                         │
│    Viac watcherov zaostáva                      │
│    Opakuj...                                    │
└─────────────────────────────────────────────────┘

Diagnostika

Krok 1: Nájdi Veľké Objekty

# Skontroluj veľkosti objektov v etcd
ETCDCTL_API=3 etcdctl get "" --prefix --keys-only | while read key; do
  size=$(etcdctl get "$key" --print-value-only 2>/dev/null | wc -c)
  echo "$size $key"
done | sort -rn | head -20

# Alebo cez kubectl
kubectl get configmaps -A -o json | \
  jq -r '.items[] | "\(.metadata.namespace)/\(.metadata.name) \(.data | to_entries | map(.value | length) | add)"' | \
  sort -t' ' -k2 -rn | head -20

Krok 2: Skontroluj Compaction Rate

# etcd compaction metriky
curl -s http://localhost:2379/metrics | grep etcd_mvcc_db_compaction

# Vysoká compaction_pause_duration = problém
# etcd_mvcc_db_compaction_pause_duration_milliseconds_bucket

# Skontroluj aktuálnu revíziu vs compactnutú revíziu
etcdctl endpoint status --write-out=table
# Pozri na RAFT INDEX a porovnaj s predchádzajúcim

Krok 3: Watch Restart Metriky

# Skontroluj ako často sa watches reštartujú
curl -s http://localhost:8080/metrics | grep watch

# Hľadaj:
# apiserver_watch_events_total
# apiserver_watch_events_sizes
# apiserver_longrunning_requests (pre watch counts)

# Vysoká miera watch establishment = problém

Krok 4: Nájdi Trigger

# Skontroluj čo sa aktualizuje často
kubectl get events -A --sort-by='.lastTimestamp' | tail -50

# Skontroluj frekvenciu aktualizácie veľkých ConfigMaps
kubectl get configmap <podozriva-cm> -n <ns> -o json | \
  jq '.metadata.annotations["kubectl.kubernetes.io/last-applied-configuration"]'

Riešenie

Možnosť 1: Zmenši Veľké Objekty

# Pred: Obrovský ConfigMap so všetkými certifikátmi
apiVersion: v1
kind: ConfigMap
metadata:
  name: all-certificates
data:
  ca-bundle.crt: |
    -----BEGIN CERTIFICATE-----
    ... 500KB certifikátov ...
    -----END CERTIFICATE-----

# Po: Rozdeľ na viacero menších ConfigMaps
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ca-cert-1
data:
  ca.crt: |
    ... 50KB ...
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ca-cert-2
data:
  ca.crt: |
    ... 50KB ...

Možnosť 2: Zníž Frekvenciu Aktualizácie

# Ak rotujete certifikáty každú hodinu, zváž:
# 1. Rotuj menej často (každých 6 hodín)
# 2. Aktualizuj len keď sa obsah skutočne mení

# Skontroluj či aktualizácie skutočne menia obsah
kubectl get configmap cert-bundle -o jsonpath='{.data}' | md5sum
# Spusti znova po "aktualizácii" - ak rovnaký hash, update je zbytočný

Možnosť 3: Presuň Veľké Dáta Von z etcd

# Použi externé úložisko pre veľké dáta
apiVersion: v1
kind: Secret
metadata:
  name: ca-bundle-reference
type: Opaque
stringData:
  # Ulož URL alebo referenciu, nie skutočné dáta
  bundle-url: "https://internal-ca-server/bundle.pem"
  bundle-hash: "sha256:abc123..."

# Aplikácia sťahuje z URL, validuje hashom

Možnosť 4: Vylaď etcd Compaction

# etcd konfigurácia
# Zvýš compaction retention aby mali watcheri viac času
auto-compaction-retention: "8"  # hodín (default je 1)
auto-compaction-mode: "revision"  # alebo "periodic"

# Ale opatrne: viac retention = viac disk space
# Možno bude treba zvýšiť quota-backend-bytes
quota-backend-bytes: 8589934592  # 8GB

Možnosť 5: Použi Delta Updates

// Namiesto nahradenia celého ConfigMap
// Použi strategic merge patch na update len zmenených polí

patch := []byte(`{"data":{"new-cert.pem":"..."}}`)
_, err := clientset.CoreV1().ConfigMaps(namespace).Patch(
    context.TODO(),
    "ca-bundle",
    types.StrategicMergePatchType,
    patch,
    metav1.PatchOptions{},
)
// Menšia transakcia = menší dopad na watcherov

Monitoring

Kľúčové Metriky

groups:
  - name: etcd-watch
    rules:
      - alert: EtcdHighCompactionRate
        expr: |
          rate(etcd_mvcc_db_compaction_total_duration_milliseconds_count[5m]) > 10
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Vysoká etcd compaction rate"

      - alert: WatchCacheHitRate
        expr: |
          sum(rate(apiserver_cache_list_fetched_objects_total[5m])) /
          sum(rate(apiserver_cache_list_total[5m])) < 0.9
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Nízka watch cache hit rate - možné relist búrky"

      - alert: LargeEtcdObject
        expr: |
          etcd_object_size_bytes > 100000
        for: 5m
        labels:
          severity: info
        annotations:
          summary: "Veľký objekt v etcd: {{ $labels.key }}"

Checklist

## etcd Watch Replay Búrky

### Symptómy
- [ ] Náhodné spomalenia apiservera
- [ ] Vysoká list request rate
- [ ] Vzor koreluje s config updates
- [ ] Trvá 2-5 minút, potom sa zotaví

### Diagnostika
- [ ] Nájdi veľké objekty v etcd (>100KB)
- [ ] Skontroluj frekvenciu aktualizácie objektov
- [ ] Monitoruj etcd compaction rate
- [ ] Skontroluj watch restart metriky

### Riešenia
- [ ] Rozdeľ veľké ConfigMapy/Secrets
- [ ] Zníž frekvenciu aktualizácie
- [ ] Použi delta updates namiesto full replace
- [ ] Presuň veľké dáta von z etcd
- [ ] Vylaď compaction retention

### Prevencia
- [ ] Nastav object size limity v admission control
- [ ] Monitoruj veľké objekty proaktívne
- [ ] Použi externé úložisko pre veľké dáta

Záver

Tento failure mode je záludný pretože:

  1. Symptóm je “náhodná pomalosť” - žiadna zjavná príčina
  2. Štandardné zdroje vyzerajú dobre - CPU/pamäť nie sú problém
  3. Root cause je interakcia - medzi veľkosťou objektu, frekvenciou update a watch mechanikou
  4. Fix vyžaduje pochopenie etcd internals - nie len Kubernetes

Kľúčový insight: etcd nie je len key-value store—je to verzovaná, sledovaná databáza. Veľké, často aktualizované objekty môžu destabilizovať celú watch mašinériu.


Súvisiace články

Súvisiace články

Citujte tento článok

Ak na článok odkazujete, pridajte pôvodnú URL a uveďte autora.

Michal Drozd. "etcd Watch Replay Búrky: Keď Obrovské ConfigMapy Zabíjajú Control Plane". https://www.michal-drozd.com/sk/blog/etcd-watch-replay-burky/ (Publikované 5. decembra 2024).