kube-proxy Mikro-Výpadky: Problém xtables Lock Contencie
Najprv to vyzeralo ako packet loss, ale bol to iptables lock. “Deploymenty spôsobujú náhodné výpadky spojení ale všetko vyzerá zdravé.” Pridali sme viac replík aby sme zvládli záťaž—čo to zhoršilo. Skutočný vinník bol kube-proxy bojujúci o xtables lock počas endpoint churnu.
Prostredie: Kubernetes 1.27, kube-proxy iptables mode, 200+ služieb, častý HPA scaling
Problém
Symptómy
Vzor ktorý nás šialel:
1. Deploy novej verzie (alebo HPA škáluje)
2. 1-3 sekundy dropped connections
3. Žiadne reštarty podov, žiadny OOM, žiadne CPU špičky
4. Metriky neukazujú nič zlé
5. Stáva sa náhodne počas "busy" časov
Čo sme videli:
- Nové TCP spojenia zlyhajú s "connection refused"
- Existujúce spojenia sú v poriadku
- Trvá len 1-3 sekundy
- Viac replík = častejší výskyt
Prečo Štandardný Monitoring Toto Nezachytí
# Normálne metriky vyzerajú dobre
kubectl top nodes # CPU: 40%, Memory: 60% - vyzerá dobre
kubectl top pods # Všetky pody zdravé
# Ani kube-proxy metriky neukazujú problém jasne
curl localhost:10249/metrics | grep sync
# kubeproxy_sync_proxy_rules_duration_seconds - ukazuje priemer, nie špičky
# Lock kontencia sa deje na kernel úrovni, neviditeľná pre Kubernetes
Príčina
Ako Funguje iptables Mode
Normálny kube-proxy iptables sync:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Endpoints │────▶│ kube-proxy │────▶│ iptables │
│ zmena │ │ generuje │ │ -restore │
└─────────────┘ │ nové rules │ └─────────────┘
└─────────────┘ │
▼
┌─────────────────┐
│ xtables lock │
│ (kernel mutex) │
└─────────────────┘
│
Blokuje VŠETKY iptables
operácie počas restore
(môže trvať sekundy)
Problém Amplifikácie
Endpoint churn vytvára feedback loop:
1. Pod crashuje (CrashLoopBackOff)
└─▶ Endpoint odstránený
└─▶ kube-proxy syncuje rules (drží xtables lock)
2. HPA škáluje hore
└─▶ Nové endpointy pridané
└─▶ kube-proxy syncuje rules (drží xtables lock)
3. Rolling deployment
└─▶ Staré pody terminujú, nové štartujú
└─▶ Viaceré endpoint zmeny
└─▶ Viaceré rule syncy v queue
└─▶ Lock držaný dlhšie
Kontra-intuitívna časť:
VIAC REPLÍK = VIAC ENDPOINT ZMIEN = VIAC LOCK CONTENCIE
"Škáluj hore pre záťaž" môže problém zhoršiť!
Meranie Lock Contencie
# Na node, trasuj xtables lock akvizíciu
sudo perf trace -e 'lock:*' -p $(pgrep kube-proxy) 2>&1 | head -100
# Alebo použi bpftrace na meranie lock hold time
sudo bpftrace -e '
kprobe:xt_lock_table_lock { @start[tid] = nsecs; }
kretprobe:xt_lock_table_unlock /@start[tid]/ {
@lock_held_us = hist((nsecs - @start[tid]) / 1000);
delete(@start[tid]);
}
'
# Praktickejšie: time iptables-save počas syncu
time iptables-save > /dev/null
# Ak toto trvá >100ms počas "normálnych" časov, máš problém
Riešenie
Možnosť 1: Prepni na IPVS Mode
# kube-proxy ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: kube-proxy
namespace: kube-system
data:
config.conf: |
mode: "ipvs"
ipvs:
syncPeriod: "30s"
minSyncPeriod: "5s"
scheduler: "rr"
# IPVS používa iné kernel štruktúry, žiadny xtables lock
# Vyžaduje ipvs kernel moduly
# Over že IPVS moduly sú dostupné
lsmod | grep -E "ip_vs|nf_conntrack"
# Ak nie, načítaj ich
modprobe ip_vs
modprobe ip_vs_rr
modprobe ip_vs_wrr
modprobe ip_vs_sh
modprobe nf_conntrack
Možnosť 2: Vylaď iptables Mode
# kube-proxy ConfigMap - zníž sync frekvenciu
apiVersion: v1
kind: ConfigMap
metadata:
name: kube-proxy
namespace: kube-system
data:
config.conf: |
mode: "iptables"
iptables:
syncPeriod: "60s" # Zvýš z default 30s
minSyncPeriod: "10s" # Zvýš z default 1s
masqueradeAll: false
Možnosť 3: Zníž Endpoint Churn
# Spomaľ HPA reakcie
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app
spec:
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # 5 min okno
policies:
- type: Percent
value: 10 # Len 10% naraz
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 50 # 50% naraz
periodSeconds: 60
# Použi maxSurge/maxUnavailable na limitovanie deployment churnu
apiVersion: apps/v1
kind: Deployment
spec:
strategy:
rollingUpdate:
maxSurge: 1 # Len 1 nový pod naraz
maxUnavailable: 0 # Drž všetky staré pody kým nový nie je ready
Možnosť 4: nftables Mode (Kubernetes 1.29+)
# Ak bežíš K8s 1.29+ s kompatibilnými nodmi
apiVersion: v1
kind: ConfigMap
metadata:
name: kube-proxy
namespace: kube-system
data:
config.conf: |
mode: "nftables"
nftables:
syncPeriod: "30s"
minSyncPeriod: "1s"
# nftables používa atomickú výmenu pravidiel, oveľa menej lock contencie
Monitoring
Detekcia Lock Contencie
# Prometheus alert pre sync duration špičky
groups:
- name: kube-proxy
rules:
- alert: KubeProxySyncSlow
expr: |
histogram_quantile(0.99,
rate(kubeproxy_sync_proxy_rules_duration_seconds_bucket[5m])
) > 1
for: 5m
labels:
severity: warning
annotations:
summary: "kube-proxy rule sync trvá >1s na {{ $labels.instance }}"
- alert: KubeProxyEndpointChurn
expr: |
rate(kubeproxy_sync_proxy_rules_endpoint_changes_total[5m]) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "Vysoký endpoint churn na {{ $labels.instance }}"
Custom Metrika pre xtables Lock
#!/bin/bash
# /etc/node_exporter/scripts/xtables_lock.sh
# Spusti ako textfile collector
# Zmeraj ako dlho trvá iptables-save (proxy pre lock contenciu)
start=$(date +%s.%N)
iptables-save > /dev/null 2>&1
end=$(date +%s.%N)
duration=$(echo "$end - $start" | bc)
echo "# HELP xtables_lock_duration_seconds Čas na získanie xtables lock"
echo "# TYPE xtables_lock_duration_seconds gauge"
echo "xtables_lock_duration_seconds $duration"
# Spočítaj pravidlá (viac pravidiel = dlhší lock hold)
rule_count=$(iptables-save | wc -l)
echo "# HELP iptables_rule_count Celkový počet iptables pravidiel"
echo "# TYPE iptables_rule_count gauge"
echo "iptables_rule_count $rule_count"
Debugging Playbook
#!/bin/bash
# kube-proxy-debug.sh
echo "=== Krok 1: Skontroluj kube-proxy mode ==="
kubectl get cm kube-proxy -n kube-system -o jsonpath='{.data.config\.conf}' | grep mode
echo "=== Krok 2: Spočítaj iptables pravidlá ==="
iptables-save | wc -l
echo "=== Krok 3: Zmeraj iptables-save ==="
time iptables-save > /dev/null
echo "=== Krok 4: Skontroluj počet endpointov ==="
kubectl get endpoints -A | wc -l
echo "=== Krok 5: Sleduj sync eventy ==="
kubectl logs -n kube-system -l k8s-app=kube-proxy --tail=50 | grep -i sync
echo "=== Krok 6: Skontroluj crashlooping pody (zdroj churnu) ==="
kubectl get pods -A | grep -E "(CrashLoop|Error)"
echo "=== Krok 7: Skontroluj HPA aktivitu ==="
kubectl get hpa -A
Reálne Čísla
Cluster s 200 službami, iptables mode:
Pred ladením:
- iptables pravidiel: 15,000+
- iptables-save čas: 800ms priemer, 3s špičky
- Endpoint zmeny: 50/min počas business hours
- Výpadky spojení: 5-10/hodinu
Po prepnutí na IPVS:
- iptables-save čas: 50ms (len non-kube pravidlá)
- Endpoint zmeny: rovnaké, ale žiadna lock kontencia
- Výpadky spojení: 0
Alternatíva - vyladený iptables:
- minSyncPeriod: 10s (bolo 1s)
- Kontrolované HPA správanie
- Výpadky spojení: <1/hodinu
Checklist
## kube-proxy Lock Contention
### Symptómy
- [ ] Náhodné 1-3s výpadky spojení
- [ ] Koreluje s deploymentami/škálovaním
- [ ] CPU/memory vyzerajú normálne
- [ ] Viac replík to zhoršilo
### Diagnostika
- [ ] Skontroluj kube-proxy mode (iptables?)
- [ ] Spočítaj iptables pravidlá (>10k je znepokojujúce)
- [ ] Zmeraj iptables-save (>500ms je zlé)
- [ ] Skontroluj endpoint churn rate
- [ ] Hľadaj crashlooping pody
### Riešenia
- [ ] Zváž IPVS mode
- [ ] Zvýš minSyncPeriod
- [ ] Vylaď HPA stabilization windows
- [ ] Kontroluj deployment surge/unavailable
- [ ] Zváž nftables mode (K8s 1.29+)
Záver
Kontra-intuitívna lekcia: pridávanie viac replík na zvládnutie záťaže môže zvýšiť endpoint churn a zhoršiť výpadky spojení. xtables lock je skrytý bottleneck ktorý štandardný Kubernetes monitoring neodhalí.
Kľúčové poznatky:
- iptables mode má inherentnú lock contenciu pri škále
- Viac endpointov = dlhší lock hold time = viac výpadkov
- IPVS mode sa problému úplne vyhýba
- Ak si viazaný na iptables, znižuj churn nie kapacitu
Súvisiace články
- Kubernetes Conntrack Vyčerpanie - Connection tracking limity
- gRPC Load Balancing v Kubernetes - Connection management
Súvisiace články
Ghost Pod: Prečo váš Service stále posiela traffic na mŕtve endpointy
Náhodné ECONNRESET na niektorých nodoch. Endpointy vyzerajú správne. Vinník: conntrack NAT záznamy držia dlhodobé spojenia pripnuté k podom, ktoré už neexistujú.
PMTU Blackholes: Keď Iba Veľké Odpovede Visia
Malé API odpovede fungujú, veľké visia navždy. Príčina: ICMP 'Fragmentation Needed' správy filtrované firewallmi, rozbíjajú Path MTU Discovery v overlay sieťach.
Vyčerpanie Ephemeral Portov: Node Ktorý 'Pokazí'
Jeden Kubernetes node začne zlyhávať pripojenia k externým službám zatiaľ čo pody vyzerajú zdravé. Skrytá príčina: sidecar proxy vyčerpávajú ephemeral porty krátkodobými spojeniami.
TCP TIME_WAIT Vyčerpanie Portov: Keď Connection Pooling Nestačí
Služba sa nemôže pripojiť k databáze - 'cannot assign requested address'. Príčina: ephemeral porty vyčerpané tisíckami socketov v TIME_WAIT stave.
Citujte tento článok
Ak na článok odkazujete, pridajte pôvodnú URL a uveďte autora.