Le kernel Linux suit chaque connexion réseau active (TCP, UDP avec état, ICMP) dans une table en mémoire, conntrack, nécessaire au NAT et au firewalling avec état. Cette table a une taille maximale, nf_conntrack_max, et ce qui se passe une fois cette limite atteinte n’est presque jamais ce qu’on imagine : aucun ralentissement progressif, un rejet silencieux et immédiat des nouvelles connexions.
Ce que conntrack fait, et pourquoi Kubernetes en dépend
Chaque connexion qui traverse le NAT (le cas de la quasi-totalité du trafic Service Kubernetes) crée une entrée dans la table conntrack, qui associe la connexion d’origine à sa traduction NAT, nécessaire pour router correctement les paquets de retour. Un cluster avec un volume élevé de connexions courtes (beaucoup de petites requêtes HTTP, un service à fort débit) génère un volume d’entrées conntrack proportionnel, pas au nombre de connexions simultanées seulement, mais à leur taux de création.
# La limite actuelle et le nombre d'entrées suivies,
# la seule vérification qui révèle un problème imminent
cat /proc/sys/net/netfilter/nf_conntrack_max
cat /proc/sys/net/netfilter/nf_conntrack_count
Ce qui se passe réellement à la limite
Une table conntrack pleine ne ralentit pas les nouvelles connexions : le kernel les rejette immédiatement, une nouvelle tentative de connexion échouant avec un symptôme qui ressemble à un problème réseau distant, un firewall qui bloque, ou une application qui refuse la connexion, jamais explicitement à « la table conntrack de ce nœud est pleine ». Le symptôme se manifeste sur le nœud, pas sur l’application qui tourne dessus, ce qui égare souvent le diagnostic vers le mauvais composant.
# Le compteur qui révèle des rejets déjà en cours,
# la preuve concrète que la limite a été atteinte
cat /proc/sys/net/netfilter/nf_conntrack_max
dmesg | grep "nf_conntrack: table full"
Le piège spécifique à Kubernetes : le NAT systématique
Un cluster Kubernetes fait transiter une part disproportionnée de son trafic par le NAT, même pour des communications purement internes entre pods, selon la configuration du CNI et du mode kube-proxy. Ce volume de trafic NATé, invisible en fonctionnement normal, remplit la table conntrack plus vite qu’une infrastructure équivalente sans cette couche de virtualisation réseau, un facteur d’échelle souvent absent du dimensionnement initial d’un nœud.
Dimensionner et surveiller, pas seulement augmenter
Augmenter nf_conntrack_max repousse le problème sans jamais le résoudre si le volume de connexions continue de croître, et une valeur trop haute consomme une mémoire kernel non négligeable (chaque entrée occupe un espace fixe, multiplié par des millions d’entrées sur un nœud à fort trafic).
# Augmenter la limite, un correctif temporaire
# si le volume de connexions continue de croître
sysctl -w net.netfilter.nf_conntrack_max=524288
Surveiller le ratio nf_conntrack_count / nf_conntrack_max en continu (via Prometheus, l’exportateur node_exporter l’expose nativement) transforme un incident silencieux en alerte actionnable avant l’épuisement réel, plutôt que de découvrir la limite au moment où les connexions commencent déjà à échouer.
À retenir
Une table conntrack pleine ne dégrade rien progressivement : elle rejette immédiatement et silencieusement toute nouvelle connexion, un symptôme qui ressemble à un problème réseau ou applicatif distant, jamais explicitement à la vraie cause. Kubernetes aggrave ce risque par le volume de trafic systématiquement NATé, même en interne, un facteur d’échelle souvent oublié au dimensionnement initial. Surveiller le ratio d’occupation en continu, plutôt que d’augmenter la limite après coup, transforme un incident silencieux en signal exploitable avant l’épuisement, un des détails réseau bas niveau qui comptent dès qu’une migration Kubernetes fait tourner un trafic à fort volume de connexions.