ingress-nginx reload búrky: prečo 502 špičky sedia s Ingress churnom
Symptómy sú nepríjemne periodické:
- 502/504 vyskočia na pár sekúnd… každých pár minút.
- gRPC a keep-alive heavy klienti reconnectujú a “healnú sa retry”.
- Backend je zdravý (readiness zelený).
- ingress-nginx pody necrashujú.
Keď vidím spiky 502 a backend je OK, položím si najprv jednu otázku:
Nereloadujeme NGINX príliš často?
ingress-nginx generuje NGINX config a reloaduje pri zmenách Kubernetes objektov. Pri churn-e (Ingress updaty, cert renewaly, ExternalDNS, canary flipy) sa reload prestane správať ako “konfigurácia” a začne byť “generátor mikro‑výpadkov”.
Testované na: Kubernetes 1.29–1.31, ingress-nginx 1.10–1.11, NGINX 1.25+, HTTP/1.1 + HTTP/2, cloud aj on‑prem LB pred ingressom.
Incident (anonymizovaný)
Mali sme 502 špičky, ktoré vždy zmizli po retry. Backend bol stabilný a p99 na aplikácii to nevysvetľovalo.
Clue bola synchronizácia: viacero nesúvisiacich služieb malo špičky v rovnakých timestampoch. To zvyčajne znamená spoločný edge komponent, nie individuálny backend.
Root cause:
- GitOps neustále reconciloval Ingress objekty.
- Reconciler robil “no-op” updaty (poradie anotácií, prepísané defaulty).
- ingress-nginx to bral ako zmenu configu a reloadoval pri každom update.
- Reload čas rástol, lebo rástol aj generovaný config.
Constraint: nemohli sme prestať deployovať. Potrebovali sme budget: najprv znížiť reload frekvenciu, potom spraviť reload menej disruptive.
Timeline
- T-0: 502 špičky, hlavne na keep-alive spojeniach a gRPC.
- T+10m: v logoch ingress-nginx vidím reload eventy presne v čase špičiek.
- T+20m: zmeriam reload rate (počas deploy okien viaceré reloady za minútu).
- T+30m: mitigácia: pauznúť non-essential churn a zvýšiť graceful shutdown budget.
- T+60m: 502 špičky výrazne klesnú.
- T+1d: fixy: stop no-op updateov, konsolidácia Ingressov, alert na reload rate.
Mechanizmus: prečo reload spraví 502 aj keď backend je zdravý
NGINX reload nie je no-op:
- master zvaliduje nový config
- naštartujú sa nové workery
- staré workery drainujú a potom skončia
Aj pri graceful reloade sa niektoré spojenia zavrú:
- idle keep-alive sa môžu dropnúť
- dlhé HTTP/2 streamy sa môžu resetnúť podľa timing-u
- retry to maskuje, kým nevyletí p99
Zhorší sa to, keď:
- príde ďalší reload skôr, než staré workery stihnú drain
- config je veľký (parsing/validácia)
- controller je CPU-throttlovaný a reload okno sa natiahne
Runbook: dokáž, že reload je príčina
1) Korelácia špičiek s reload logmi
Začni logmi. Rôzne verzie logujú trochu iné frázy, ale intent je vždy viditeľný.
kubectl -n ingress-nginx logs deploy/ingress-nginx-controller --since=60m | \
rg -n "Reloading|reloaded|Configuration changes detected|backend reload" | tail -n 50
Ak timestampy sedia so špičkami, máš silný signál.
2) Zmeraj reload rate (nehádaj)
Ak scrapuješ ingress-nginx metriky, najprv si nájdi reálne metriky v /metrics (nenašteluj sa na názvy naslepo):
kubectl -n ingress-nginx port-forward deploy/ingress-nginx-controller 10254:10254
curl -s http://127.0.0.1:10254/metrics | rg -n "reload|nginx.*reload" | head -n 50
Cieľ je budget: reloady za minútu v steady state majú byť takmer nulové.
3) Nájsť zdroj churnu
Typickí vinníci:
- GitOps patch loop
- cert-manager (TLS secret updaty)
- ExternalDNS (anotácie/DNS zmeny)
- canary tooling (časté anotácie)
V čase incidentu sa pozri, kto “touchoval” Ingress:
kubectl get events -A --sort-by=.lastTimestamp | tail -n 50
kubectl get ingress -A -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,GEN:.metadata.generation --sort-by=.metadata.generation | tail -n 20
Ak generácie rastú bez reálnej zmeny routingu, často ide o no-op churn bug.
4) Over, že backend je healthy (aby si nefixoval zlé miesto)
kubectl -n <app-ns> get pods -o wide
kubectl -n <app-ns> get endpoints <svc> -o wide
Ak backend drží a špičkuje iba edge, riešiš ingress správanie, nie appku.
Bezpečné mitigácie (v incidente)
1) Prestaň sa dotýkať configu
Pauzni to, čo robí churn:
- pauznúť GitOps sync pre Ingress resources
- neflipovať canary anotácie
- cert/DNS zmeny mimo peak trafficu
2) Viac drain budgetu pre reload
ingress-nginx exponuje NGINX knobs cez ConfigMap (over si presné kľúče pre tvoju verziu). Intent:
- dať workerom viac času na drain
- znížiť drop keep-alive počas tesných reload okien
Reprezentatívny príklad:
apiVersion: v1
kind: ConfigMap
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
data:
worker-shutdown-timeout: "30s"
keep-alive: "75"
keep-alive-requests: "10000"
A uisti sa, že controller pod má termination grace period, ktorá pokryje drain:
spec:
template:
spec:
terminationGracePeriodSeconds: 60
3) Odstráň CPU throttling z controlleru
CPU throttling predĺži reload a zväčší disruption okno. Daj controlleru CPU headroom a zváž horizontálne škálovanie.
Čo sme zmenili (konkrétne)
1) Stop no-op updatov pri zdroji
GitOps prepisoval anotácie aj keď sa reálny výsledok nezmenil. Fix znížil reloady o rád.
2) Konsolidácia a de-churn Ingressov
Stovky malých Ingress objektov spravia veľký generovaný config a veľa update eventov. Konsolidácia znížila:
- veľkosť configu
- reload time
- frekvenciu zmien
3) Reload budget a observabilita
Pridali sme:
- dashboard panel: reloady za minútu
- alert: reload rate nad budget
- alert: “reload start bez success” dlhšie než N sekúnd (log-based, ak treba)
Ako verifikovať
- 502 špičky už nesedia s reload logmi.
- Reload rate je nízky v steady state.
- Long-lived klienti (gRPC streamy, keep-alive heavy) prestanú periodicky reconnectovať.
Prevencia / guardrails
- Ingress updaty sú produkčná zmena; no-op updaty sú outage v prestrojení.
- Budget na reload rate (steady state má byť zriedkavý a vysvetliteľný).
- Ingress controller drž mimo CPU throttling.
- Cert/DNS churn koordinuj tak, aby nevznikali reload búrky počas peak trafficu.
Súvisiace čítanie
- HTTP Keep-Alive Connection Reset: Prečo Vaše Requesty Zlyhávajú s ‘Connection Reset by Peer’
- Kubernetes graceful shutdown ako kontrakt: nula 502 počas rolloutov (HTTP + gRPC)
- tcpdump vidí SYN, ale služba timeoutuje: pasca listen backlogu
- PMTU Blackholes: Keď Iba Veľké Odpovede Visia
- kube-proxy Mikro-Výpadky: Problém xtables Lock Contencie
- Structured Logging Performance: Keď Sa Logger Stane Bottleneckom
- Vyčerpanie Ephemeral Portov: Node Ktorý ‘Pokazí’
Súvisiace články
tcpdump vidí SYN, ale služba timeoutuje: pasca listen backlogu
Klienti timeoutujú, tcpdump ukazuje SYN (niekedy aj SYN-ACK), ale aplikácia nič neloguje. Častý vinník: Linux listen/accept fronty, ktoré sa pri load-e alebo CPU starvation preplnia.
Redis AOF fsync latency špičky: keď sa durabilita stane tvojím p99
Redis AOF vie spraviť z durability p99 špičky: fsync tlak a BGREWRITEAOF fork CoW. Runbook na dôkaz, bezpečné mitigácie a guardrails.
Kubernetes APF vyhladovanie: keď jeden controller zablokuje kubectl
APF vie vyhladovať Kubernetes API: kubectl visí, controllery timeoutujú a rastú 429. Runbook na izoláciu klienta, úpravu FlowSchema a verifikáciu.
Java Profilovanie v Hardened Kubernetes: Keď Security Blokuje Tvoj Debugger
Nemôžeš pripojiť profiler k produkčnej JVM. seccomp blokuje perf_event_open, container dropol CAP_SYS_PTRACE a PodSecurityPolicy bráni privileged mode. Tu je ako profilovať aj tak.
Citujte tento článok
Ak na článok odkazujete, pridajte pôvodnú URL a uveďte autora.