Späť na blog

Kubernetes conntrack Vyčerpanie: Tichý Zabijak Paketov

Conntrack vycerpanie je klasika, ktora aj tak prekvapi timy vo velkom scale. “Naše DNS lookupy náhodne zlyhávajú.” “Služby timeout-ujú ale pody sú healthy.” “Funguje lokálne ale padá v K8s.” Tieto symptómy často ukazujú na jedného vinníka: vyčerpanie conntrack tabuľky.

Testované na: EKS 1.28, GKE 1.27, Linux kernel 5.15, Calico CNI

Čo je conntrack?

Základy Connection Tracking

Linux connection tracking (conntrack) mapuje:
  Source IP:Port ←→ Destination IP:Port ←→ State

Účel: Umožniť NAT, firewally a stateful filtrovanie paketov

Každé spojenie cez kube-proxy používa conntrack záznam:

Pod A (10.1.1.5:45678) → Service (10.96.0.10:80) → Pod B (10.1.2.3:8080)

           conntrack záznam sleduje toto mapovanie

Prečo Kubernetes je Conntrack-Heavy

Jeden HTTP request v Kubernetes:

1. DNS lookup do CoreDNS
   Pod → kube-dns Service → CoreDNS Pod (conntrack záznam #1)

2. Service volanie
   Pod → Service ClusterIP → Backend Pod (conntrack záznam #2)

3. Ak backend volá databázu
   Backend → DB Service → DB Pod (conntrack záznam #3)

4. Externé API volanie (cez NAT Gateway)
   Pod → NAT → External IP (conntrack záznam #4)

Výsledok: Jeden user request = 4+ conntrack záznamy
Pri 10,000 RPS: 40,000+ záznamy konštantne rotujúce

Problém

Default Limity

# Skontroluj aktuálne conntrack nastavenia
cat /proc/sys/net/netfilter/nf_conntrack_max
# Default: 131072 (128K záznamy)

cat /proc/sys/net/netfilter/nf_conntrack_count
# Aktuálne záznamy v použití

# Keď count sa blíži k max:
# - Nové spojenia sa ticho zahadzujú
# - DNS lookupy timeout-ujú (UDP)
# - TCP spojenia visia

Symptómy

Symptóm 1: DNS timeouty
  - DNS je väčšinou UDP; aj \"connectionless\" traffic vytvára conntrack stav (kvôli kube-proxy NAT)
  - Vysoký UDP QPS rýchlo rotuje záznamy
  - DNS zlyhania kaskádujú do všetkých služieb

Symptóm 2: Náhodné zlyhania spojení
  - Niektoré requesty uspejú, niektoré zlyhajú
  - Žiaden vzor v logoch
  - Pody hlásia healthy

Symptóm 3: Vysoké latency spiky
  - Setup spojenia trvá dlhšie
  - Existujúce spojenia ovplyvnené GC

Kernel log (dmesg):
  nf_conntrack: table full, dropping packet

Súvisiaci failure mode: kube-proxy conntrack cleanup stormy (vysoke RSS/CPU)

Conntrack vycerpanie je o zahadzovani paketov, ked je tabulka plna. Ale existuje aj iny conntrack-typ vypadku, ktory vyzera uplne inak:

  • kube-proxy RSS zrazu vystreli na viac GB
  • kube-proxy CPU skoci hore
  • casto to koreluje s update-mi Podov/Services, ktore maju UDP port (CoreDNS byva klasicky trigger)
  • conntrack tabulka nemusi byt “plna” - je len dost velka na to, aby “scan celej tabulky” bol brutalne drahy

Toto sa pekne ukazalo v Kubernetes issue #129982 (kube-proxy v1.32): zmeny Podov/Services s UDP portom spustali full conntrack cleanup, ktory prechadzal celu tabulku a palil pamat/CPU.

Co robim v praxi:

  1. Potvrd, ze to je kube-proxy (nie workload)

    kubectl -n kube-system top pods -l k8s-app=kube-proxy
  2. Skontroluj conntrack pressure na node

    cat /proc/sys/net/netfilter/nf_conntrack_{count,max}
  3. Upgradni na release, kde su fixy

    V tomto type incidentu su relevantne najma tieto mergnute fixy:

    • Kubernetes PR #130032: “Conntrack memory leak fix”
    • Kubernetes PR #130484: “conntrack reconciler must check the dst port”

    Fix bol backportnuty do Kubernetes 1.32 patch vetvy a klasicka rada plati stale: bud na najnovsom patch release pre svoju branch. Toto by som netunil okolo sysctl-ami, ak vies upgradovat/backportnut - failure mode je algoritmicky.

    Ak si zaseknuty na provider builde, ktory laguje za upstreamom, v issue sa spominal aj workaround: zvysit --iptables-min-sync-period, aby sa sync path nespustal tak casto. Nefixne to root cause, ale vie to znizit blast radius, kym sa dostanes na verziu s fixom.

Ak trafis toto, zvysok clanku (limity, timeouts, NodeLocal DNSCache) stale pomoze, lebo mensia/stabilnejsia conntrack tabulka znamena mensiu cenu. Ale realny fix je upgrade kube-proxy/Kubernetes na verziu s opravami v reconcileri.

Diagnostika

Skontroluj Stav Node

# SSH na node alebo použi kubectl debug
kubectl debug node/my-node -it --image=busybox

# Vnútri debug kontajnera:
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max

# Skontroluj dropy
dmesg | grep conntrack
# Hľadaj: "table full, dropping packet"

# Rozdelenie spojení podľa stavu
cat /proc/net/nf_conntrack | awk '{print $4}' | sort | uniq -c | sort -rn
#  45000 TIME_WAIT
#  38000 ESTABLISHED
#  12000 SYN_SENT
#   5000 FIN_WAIT

Prometheus Metriky

# Node exporter poskytuje tieto:

# Aktuálne conntrack záznamy
node_nf_conntrack_entries

# Maximum povolené
node_nf_conntrack_entries_limit

# Percentuálne využitie (kritická metrika)
node_nf_conntrack_entries / node_nf_conntrack_entries_limit

# Rýchlosť nových spojení
rate(node_nf_conntrack_entries[5m])

Analýza High-Traffic Služieb

# Nájdi služby generujúce najviac spojení
kubectl get endpoints -A -o json | jq '
  .items[] |
  select(.subsets != null) |
  {
    namespace: .metadata.namespace,
    name: .metadata.name,
    endpoints: [.subsets[].addresses // [] | length] | add
  }' | sort -k3 -rn

# Skontroluj krátkodobé spojenia (HTTP bez keepalive)
# Tieto rotujú conntrack záznamy najrýchlejšie

Riešenia

1. Zvýš Conntrack Limity

# DaemonSet na tuning sysctl na všetkých nodoch
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: sysctl-tuner
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: sysctl-tuner
  template:
    metadata:
      labels:
        app: sysctl-tuner
    spec:
      hostPID: true
      hostNetwork: true
      initContainers:
        - name: sysctl
          image: busybox
          securityContext:
            privileged: true
          command:
            - sh
            - -c
            - |
              sysctl -w net.netfilter.nf_conntrack_max=1048576
              sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=86400
              sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
              sysctl -w net.core.somaxconn=65535
      containers:
        - name: pause
          image: k8s.gcr.io/pause:3.9

Cloud-Špecifická Konfigurácia

# EKS: Použi launch template s user data
#!/bin/bash
echo "net.netfilter.nf_conntrack_max=1048576" >> /etc/sysctl.conf
echo "net.netfilter.nf_conntrack_tcp_timeout_time_wait=30" >> /etc/sysctl.conf
sysctl -p

# GKE: Použi node pool config
gcloud container node-pools create high-conntrack \
  --cluster=my-cluster \
  --node-config='linuxNodeConfig:
    sysctls:
      net.netfilter.nf_conntrack_max: "1048576"'

# AKS: Použi custom node config
az aks nodepool add \
  --cluster-name my-cluster \
  --name highconn \
  --linux-os-config linuxOsConfig.json

# linuxOsConfig.json:
{
  "sysctls": {
    "netNetfilterNfConntrackMax": 1048576
  }
}

2. Zníž Conntrack Využitie

# Použi headless služby kde možné
# Žiadny conntrack potrebný pre priame pod-to-pod
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  clusterIP: None  # Headless - žiadny NAT, žiadny conntrack
  selector:
    app: my-app
---
# Povoľ HTTP keepalive pre zníženie churn spojení
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
data:
  nginx.conf: |
    upstream backend {
      server backend:8080;
      keepalive 100;  # Znovupoužitie spojení
    }

    server {
      location / {
        proxy_http_version 1.1;
        proxy_set_header Connection "";  # Povoľ keepalive
        proxy_pass http://backend;
      }
    }

3. Tuning Timeout Hodnôt

# Default timeouty sú príliš dlhé pre efemérny traffic
# Zníž TIME_WAIT záznamy:

# Pred: TIME_WAIT spojenia držané 120 sekúnd
# Po: Uvoľnené za 30 sekúnd
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30

# Uzavri mŕtve spojenia rýchlejšie
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close_wait=15

# Plný timeout tuning pre vysoký traffic:
net.netfilter.nf_conntrack_tcp_timeout_syn_sent=30
net.netfilter.nf_conntrack_tcp_timeout_syn_recv=30
net.netfilter.nf_conntrack_tcp_timeout_established=86400
net.netfilter.nf_conntrack_tcp_timeout_fin_wait=15
net.netfilter.nf_conntrack_tcp_timeout_close_wait=15
net.netfilter.nf_conntrack_tcp_timeout_last_ack=15
net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
net.netfilter.nf_conntrack_tcp_timeout_close=10
net.netfilter.nf_conntrack_udp_timeout=30
net.netfilter.nf_conntrack_udp_timeout_stream=60

4. IPVS Mód (Alternatíva k iptables)

# IPVS používa menej conntrack pre služby
# ConfigMap pre kube-proxy
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-proxy
  namespace: kube-system
data:
  config.conf: |
    mode: "ipvs"
    ipvs:
      scheduler: "rr"
      strictARP: true

# IPVS výhody:
# - Lepší výkon v škále (O(1) vs O(n) pre iptables)
# - Efektívnejšie využitie conntrack
# - Vstavané algoritmy load balancingu

Monitoring

Alert Rules

groups:
- name: conntrack
  rules:
  - alert: ConntrackTabulkaSkoro Plna
    expr: |
      node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.75
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "Conntrack tabuľka na {{ $value | humanizePercentage }}"
      description: "Node {{ $labels.instance }} conntrack využitie vysoké"

  - alert: ConntrackTabulkaKriticka
    expr: |
      node_nf_conntrack_entries / node_nf_conntrack_entries_limit > 0.9
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "Conntrack tabuľka na {{ $value | humanizePercentage }}"
      description: "Packet dropy hrozia na {{ $labels.instance }}"

  - alert: ConntrackZaznamyRastuRychlo
    expr: |
      rate(node_nf_conntrack_entries[5m]) > 1000
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "Conntrack rastie rýchlosťou {{ $value }}/sec"
      description: "Možný connection leak alebo traffic spike"

Grafana Dashboard

# Panel 1: Conntrack využitie per node
node_nf_conntrack_entries / node_nf_conntrack_entries_limit

# Panel 2: Záznamy v čase
node_nf_conntrack_entries

# Panel 3: Rýchlosť zmeny
rate(node_nf_conntrack_entries[1m])

# Panel 4: Rezerva
node_nf_conntrack_entries_limit - node_nf_conntrack_entries

DNS-Špecifické Problémy

NodeLocal DNS Cache

# NodeLocal DNSCache znižuje conntrack tlak
# DNS queries zostávajú na node, žiadny conntrack potrebný

# Nainštaluj NodeLocal DNSCache
kubectl apply -f https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/dns/nodelocaldns/nodelocaldns.yaml

# Výhody:
# - DNS queries neprechádzajú sieťou
# - Žiadne conntrack záznamy pre DNS
# - Znížená záťaž na CoreDNS

CoreDNS Conntrack Bypass

# CoreDNS môže použiť TCP pre zníženie UDP conntrack problémov
# ConfigMap pre CoreDNS
apiVersion: v1
kind: ConfigMap
metadata:
  name: coredns
  namespace: kube-system
data:
  Corefile: |
    .:53 {
        forward . /etc/resolv.conf {
            prefer_udp
            max_concurrent 1000
        }
        cache 30
    }

Checklist

## Conntrack Vyčerpanie Prevencia

### Monitoring
- [ ] Alert na conntrack využitie > 75%
- [ ] Dashboard ukazujúci conntrack záznamy per node
- [ ] Monitoruj rýchlosť spojení (záznamy/sec)

### Tuning
- [ ] Zvýš nf_conntrack_max (1M+ pre vysoký traffic)
- [ ] Zníž TIME_WAIT timeout (30s)
- [ ] Zváž IPVS mód pre kube-proxy

### Architektúra
- [ ] Použi headless služby kde možné
- [ ] Povoľ HTTP keepalive medzi službami
- [ ] Deploy NodeLocal DNS Cache
- [ ] Použi connection pools v aplikáciách

### Investigácia
- [ ] Skontroluj dmesg pre "table full" správy
- [ ] Analyzuj distribúciu conntrack stavov
- [ ] Identifikuj high-connection služby

Záver

Conntrack vyčerpanie je tichý zabijak v Kubernetes:

  1. Default 128K limit je príliš nízky pre produkciu
  2. DNS a krátkodobé spojenia plnia tabuľku rýchlo
  3. Monitoruj nf_conntrack_entries skôr než nastanú problémy
  4. Zvýš limity + zníž timeouty pre okamžitú úľavu

Skontroluj svoje nody teraz - dropy možno už prebiehajú.


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. "Kubernetes conntrack Vyčerpanie: Tichý Zabijak Paketov". https://www.michal-drozd.com/sk/blog/kubernetes-conntrack-vycerpanie/ (Publikované 3. júna 2025).