PMTU Blackholes: Keď Iba Veľké Odpovede Visia
Toto bola cista networking legenda, kym nas to netrafilo. “API funguje pre malé odpovede ale visí pre veľké.” Strávili sme dni pridávaním timeoutov a retries, kým sme si uvedomili že problém je PMTU blackholing—ICMP správy sú filtrované, čo spôsobuje tiché zlyhanie Path MTU Discovery.
Prostredie: Kubernetes 1.28, Calico overlay (VXLAN), cloud provider s defaultnými security groups
Problém
Symptómy Ktoré Nedávajú Zmysel
Vzor ktorý sme pozorovali:
✓ GET /health → 200 OK (50 bytes) - funguje
✓ GET /api/user/1 → 200 OK (500 bytes) - funguje
✗ GET /api/users → visí navždy (15KB) - zlyháva
✗ POST /api/upload → visí (veľké telo) - zlyháva
Indície:
- Rovnaký endpoint, rôzne veľkosti payloadu
- Hranica okolo 1400-1500 bytes
- Cross-node traffic postihnutý viac
- V dev prostredí fungovalo
Prečo Je Toto Ťažké Debugovať
# Aplikačné logy neukazujú nič užitočné
# Len timeout po 30 sekundách
# tcpdump na odosielateľovi ukazuje pakety odchádzajúce
tcpdump -i eth0 host $DEST_IP
# 10:00:00 IP src > dst: TCP ... length 1460
# 10:00:00 IP src > dst: TCP ... length 1460
# Pakety sa posielajú... ale žiadna odpoveď
# Problém je neviditeľný na aplikačnej vrstve
# Pretože ICMP správy ktoré by signalizovali problém
# sú dropované firewallom niekde po ceste
Príčina
Path MTU Discovery 101
Normálne PMTU Discovery:
┌──────────┐ 1500B paket ┌──────────┐ Nemôže fragmentovať ┌──────────┐
│ Sender │──────────────────▶│ Router │────────────────────▶│ Drop │
└──────────┘ └──────────┘ └──────────┘
│
│ ICMP "Fragmentation Needed"
│ MTU = 1400
▼
┌──────────┐ 1400B pakety ┌──────────┐
│ Sender │──────────────────▶│ Router │──────────────────▶ Doručené!
└──────────┘ (po ICMP) └──────────┘
PMTU Blackhole (pokazené):
┌──────────┐ 1500B paket ┌──────────┐ Nemôže fragmentovať ┌──────────┐
│ Sender │──────────────────▶│ Router │────────────────────▶│ Drop │
└──────────┘ └──────────┘ └──────────┘
│
│ ICMP "Fragmentation Needed"
▼
┌──────────┐
│ Firewall │──▶ DROPPED (ICMP filtrované)
└──────────┘
Výsledok: Sender sa nikdy nedozvie o MTU probléme
Stále posiela 1500B pakety
Spojenie visí navždy
Overlay Sieť To Zhoršuje
Fyzické MTU: 1500 bytes
S VXLAN overlay:
┌─────────────────────────────────────────────────┐
│ Originálna IP hlavička (20B) + TCP (20B) + Data │
└─────────────────────────────────────────────────┘
│
│ VXLAN enkapsulácia pridáva:
│ - Vonkajšia IP hlavička: 20 bytes
│ - UDP hlavička: 8 bytes
│ - VXLAN hlavička: 8 bytes
│ - Vonkajší Ethernet: 14 bytes
▼
┌─────────────────────────────────────────────────┐
│ Vonkajšie hlavičky (50B) + Originálny paket (1450B) │
│ = 1500 bytes (akurát sa zmestí!) │
└─────────────────────────────────────────────────┘
Ale ak je originálny paket mierne väčší:
┌─────────────────────────────────────────────────┐
│ Vonkajšie hlavičky (50B) + Originál (1460B) = 1510B │
│ PREKRAČUJE MTU → potrebuje fragmentáciu alebo ICMP │
└─────────────────────────────────────────────────┘
Diagnostika
Krok 1: Identifikuj Hranicu
# Nájdi presnú veľkosť kde veci prestávajú fungovať
for size in 1000 1200 1400 1450 1480 1500; do
echo -n "Veľkosť $size: "
timeout 5 curl -s -o /dev/null -w "%{http_code}" \
"http://$SERVICE_IP/api/generate?size=$size" || echo "TIMEOUT"
done
# Výstup:
# Veľkosť 1000: 200
# Veľkosť 1200: 200
# Veľkosť 1400: 200
# Veľkosť 1450: TIMEOUT <-- Hranica nájdená!
# Veľkosť 1480: TIMEOUT
# Veľkosť 1500: TIMEOUT
Krok 2: Skontroluj ICMP Filtrovanie
# Z podu, skús či ICMP je dosiahnuteľné
kubectl exec -it $POD -- ping -c 3 -s 1472 -M do $DEST_IP
# Ak vidíš:
# ping: local error: message too long, mtu=1450
# To je dobré - PMTU funguje lokálne
# Ale ak pakety len miznú cez nody:
kubectl exec -it $POD -- tracepath $DEST_IP
# Hľadaj "asymm" alebo "no reply" záznamy
Krok 3: Zachyť Chýbajúce ICMP
# Na cieľovom node, zachytávaj ICMP
tcpdump -i any icmp
# Na zdrojovom node, pošli veľký ping
kubectl exec -it $POD -- ping -c 1 -s 1472 -M do $DEST_IP
# Ak sa žiadne ICMP neobjaví na zdroji, je filtrované niekde
Krok 4: Skontroluj MTU Po Ceste
#!/bin/bash
# pmtu-probe.sh - Nájdi skutočné MTU
TARGET_IP=$1
MAX_SIZE=1500
MIN_SIZE=1000
while [ $((MAX_SIZE - MIN_SIZE)) -gt 1 ]; do
MID=$(( (MAX_SIZE + MIN_SIZE) / 2 ))
# -M do = nefragmentuj, -s = veľkosť payloadu (mínus 28 pre IP+ICMP hlavičky)
if ping -c 1 -W 2 -M do -s $((MID - 28)) $TARGET_IP > /dev/null 2>&1; then
MIN_SIZE=$MID
echo "Veľkosť $MID: OK"
else
MAX_SIZE=$MID
echo "Veľkosť $MID: FAIL"
fi
done
echo "Skutočné MTU: $MIN_SIZE"
Riešenie
Možnosť 1: MSS Clamping na CNI
# Pre Calico - nakonfiguruj MSS clamping
apiVersion: crd.projectcalico.org/v1
kind: FelixConfiguration
metadata:
name: default
spec:
# Obmedz MSS aby sa predišlo priveľkým paketom
mtuIfacePattern: "^(eth|en).*"
# Nastav MTU explicitne pre overlay
ipipMTU: 1440
vxlanMTU: 1450
wireguardMTU: 1420
# Toto povie TCP session aby vyjednali menšie segmenty
# Žiadne ICMP nie je potrebné!
Možnosť 2: Oprav Security Group Pravidlá
# AWS Security Group - povol ICMP type 3 (Destination Unreachable)
aws ec2 authorize-security-group-ingress \
--group-id sg-xxx \
--protocol icmp \
--port 3 \
--cidr 10.0.0.0/8
# GCP Firewall - povol ICMP
gcloud compute firewall-rules create allow-icmp-pmtu \
--direction=INGRESS \
--priority=1000 \
--network=default \
--action=ALLOW \
--rules=icmp \
--source-ranges=10.0.0.0/8
Možnosť 3: Nastav MTU Rozhrania Explicitne
# DaemonSet na nastavenie MTU na všetkých nodoch
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: set-mtu
namespace: kube-system
spec:
selector:
matchLabels:
app: set-mtu
template:
metadata:
labels:
app: set-mtu
spec:
hostNetwork: true
initContainers:
- name: set-mtu
image: alpine
securityContext:
privileged: true
command:
- /bin/sh
- -c
- |
# Nájdi pod interface (zvyčajne vxlan.calico alebo podobné)
for iface in vxlan.calico flannel.1 cilium_vxlan; do
if ip link show $iface 2>/dev/null; then
ip link set $iface mtu 1450
echo "Nastavené $iface MTU na 1450"
fi
done
containers:
- name: pause
image: gcr.io/google_containers/pause:3.2
Možnosť 4: TCP MSS Prepisovanie cez iptables
# Na každom node, obmedz MSS pre všetku pod traffic
iptables -t mangle -A POSTROUTING \
-p tcp --tcp-flags SYN,RST SYN \
-o vxlan.calico \
-j TCPMSS --clamp-mss-to-pmtu
# Alebo nastav explicitnú hodnotu
iptables -t mangle -A POSTROUTING \
-p tcp --tcp-flags SYN,RST SYN \
-o vxlan.calico \
-j TCPMSS --set-mss 1360
Monitoring
Prometheus Pravidlá
groups:
- name: pmtu
rules:
# Alert na vysoké TCP retransmisie (symptóm PMTU problémov)
- alert: HighTCPRetransmissions
expr: |
rate(node_netstat_Tcp_RetransSegs[5m]) /
rate(node_netstat_Tcp_OutSegs[5m]) > 0.01
for: 10m
labels:
severity: warning
annotations:
summary: "Vysoké TCP retransmisie na {{ $labels.instance }}"
description: "Môže indikovať PMTU blackholing"
# Alert na ICMP unreachables (dobré - znamená že PMTU funguje)
- alert: ICMPUnreachableSpike
expr: |
rate(node_netstat_Icmp_InDestUnreachs[5m]) > 100
for: 5m
labels:
severity: info
annotations:
summary: "ICMP Destination Unreachable špička na {{ $labels.instance }}"
Checklist
## PMTU Blackhole Diagnostika
### Symptómy
- [ ] Veľké odpovede visia, malé fungujú
- [ ] Hranica okolo 1400-1500 bytes
- [ ] Cross-node traffic horší ako same-node
- [ ] Funguje v non-overlay prostrediach
### Diagnostika
- [ ] Nájdi presnú veľkostnú hranicu
- [ ] Skontroluj či ICMP type 3 je povolené
- [ ] Over MTU na overlay rozhraniach
- [ ] Skontroluj cloud security groups pre ICMP
### Riešenia
- [ ] Zapni MSS clamping na CNI úrovni
- [ ] Povol ICMP type 3 v security groups
- [ ] Nastav explicitné MTU na overlay rozhraniach
- [ ] Pridaj iptables MSS prepisovanie
### Verifikácia
- [ ] Testuj s veľkými payloadmi po oprave
- [ ] Monitoruj TCP retransmisie
- [ ] Over že ICMP správy prúdia
Záver
PMTU blackholes sú zákerné pretože:
- Malé requesty fungujú - dáva falošnú istotu
- Žiadne chyby sa neobjavia - len timeouty
- ICMP filtrovanie je neviditeľné - nevidíš čo je dropnuté
- Overlay enkapsulácia znižuje efektívne MTU - problém sa objaví až po deployi
Fix je jednoduchý (MSS clamping alebo povoliť ICMP), ale diagnostika vyžaduje pochopenie interakcie medzi overlay sieťami, PMTU discovery a firewall pravidlami.
Súvisiace články
- VXLAN Checksum Offload Straty Paketov - Ďalšia pasca overlay sietí
- Kubernetes DNS Caching - Ďalšie networking edge cases
Súvisiace články
VXLAN Náhodné Straty Paketov: Pasca Checksum Offload
gRPC volania medzi nodmi náhodne zlyhávajú ale lokálna komunikácia funguje. Vinník: TX checksum offload poškodzuje VXLAN hlavičky na špecifických NIC driveroch.
kube-proxy Mikro-Výpadky: Problém xtables Lock Contencie
Náhodné 1-3 sekundové výpadky spojení počas deploymentov. CPU vyzerá v poriadku, pamäť stabilná. Skrytá príčina: iptables-restore drží xtables lock počas endpoint churnu.
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.
Traffic Ide na Mŕtve Pody: Conntrack Zastaralé NAT Mapovanie
Deploy spôsobuje 503 presne 2 minúty. Problém: conntrack drží NAT mapovanie na staré pod IP aj po tom čo Kubernetes odstráni endpointy.
Citujte tento článok
Ak na článok odkazujete, pridajte pôvodnú URL a uveďte autora.