Pourquoi les pods GKE n’atteignent pas les hôtes locaux via le VPN
Le nœud atteint le site local, le pod non. Les exclusions de masquerade de GKE laissent les adresses de pod non traduites pour les destinations 10.x.
Le ping fonctionne depuis le nœud et échoue depuis le pod, et rien n’arrive sur le site local. Le tunnel et la route sont corrects ; l’adresse source sur le fil ne l’est pas. Ce qui distingue ces deux cas, c’est ce que le paquet prétend être lorsqu’il quitte le cluster, et GKE a un avis là-dessus. Le mécanisme est une liste d’exclusions de masquerade, et la lire ne demande qu’une commande.
Lisez la liste effective avant de changer quoi que ce soit
GKE fournit un agent qui décide, pour chaque plage de destination, si le trafic des pods est réécrit vers l’adresse du nœud en sortie. Sa configuration livrée nomme les trois blocs RFC1918, 10.0.0.0/8, 172.16.0.0/12 et 192.168.0.0/16, comme destinations exemptées. Tout ce que vous envoyez depuis un pod vers un hôte 10.x local quitte donc le nœud avec l’adresse propre du pod encore attachée. Le trafic du nœud lui-même n’est pas réécrit, et c’est exactement pourquoi son ping fonctionne.
Lisez la configuration prévue et les règles installées, car elles peuvent se contredire. kubectl -n kube-system get configmap ip-masq-agent -o yaml montre ce qui a été dit à l’agent, et kubectl -n kube-system get pods -l k8s-app=ip-masq-agent montre si quelque chose tourne pour l’appliquer. Sur un nœud, iptables-save | grep -i masq montre les règles qui existent réellement dans le noyau. Quand la ConfigMap dit une chose et les règles une autre, le suspect est l’agent, pas le réseau.
Confirmez l’adresse source par une capture
Faites une capture avant de modifier une liste. Un filtre sur la seule destination garde la sortie lisible : tcpdump -ni any host 10.20.30.40.
Comparez cela avec ce que rapporte l’autre côté. Une capture sur site qui montre l’adresse du pod et aucune réponse boucle le raisonnement : la liste d’exclusions explique l’asymétrie sans aucune panne du tunnel. Deux observations d’une même adresse source suffisent pour arrêter de spéculer sur le CNI.
Restreignez l’exclusion au CIDR des pods
La réparation prise en charge resserre l’exemption au lieu de la supprimer : gardez le CIDR des pods exempté et abandonnez le reste de l’espace 10.x. Cette liste vit dans la ConfigMap de l’agent sous nonMasqueradeCIDRs, et la modifier est une édition suivie d’un déploiement. Remplacez l’entrée large par la plage de pods réelle du cluster, conservez les autres blocs privés si le trafic interne au cluster en a encore besoin, et laissez resyncInterval tranquille sauf si vous avez une raison. Appliquez, confirmez que les pods de l’agent ont redémarré et confirmez que les règles du noyau ont changé.
C’est un changement à l’échelle du cluster avec un rayon d’impact réel. Une fois appliqué, le trafic qui conservait auparavant sa source de pod arrive désormais réécrit vers le nœud, si bien que tout ce qui était indexé sur ces adresses de pod voit un émetteur différent. Les victimes sont les journaux, les listes d’autorisation et les règles de pare-feu locales qui nomment des adresses de pod, et elles échouent silencieusement. Annoncez le changement comme un changement de comportement, pas comme une correction.
Sur un cluster comportant plusieurs pools de nœuds, vérifiez que l’agent est planifié sur les nœuds où les pods concernés s’exécutent réellement. Un pool dépourvu du DaemonSet conserve ses anciennes règles, et rien dans la ConfigMap ne le montrera.
L’alternative et son coût
L’autre option garde les adresses de pod intactes et apprend le chemin à leur sujet. Le CIDR des pods entre dans les sélecteurs de trafic de Cloud VPN, et le côté local a besoin d’une route de retour pour lui, afin que les réponses sachent où aller. Cela préserve l’identité du pod, que certains modèles de sécurité souhaitent, et cela élargit à la fois le périmètre de routage et le périmètre de pare-feu que l’autre côté doit accepter.
L’échange est la lisibilité contre l’étendue. La traduction fait voir au côté local une adresse par nœud, ce qui est facile à mettre dans une liste d’autorisation et masque quel pod a envoyé quoi. Sans traduction, l’adresse du pod est conservée de bout en bout, ce qui est meilleur pour l’attribution et pire pour chaque équipement du chemin qui doit apprendre une nouvelle plage. Aucune des deux options n’est un défaut de Docker ou du CNI ; les deux sont des décisions de routage avec une facture opérationnelle. Choisissez celle dont votre équipe peut payer la facture, et écrivez pourquoi.
Vérifiez et revenez en arrière
Refaites la même capture. Une capture au niveau du nœud qui affiche encore l’adresse du pod après votre modification signifie que les règles n’ont jamais changé, quoi qu’en dise la ConfigMap. Le fil est le fait ; tout le reste est inférence.
Vérifiez ensuite le sens inverse, car la moitié de ces changements ne sont vérifiés qu’en sortie. Confirmez que la réponse atteint le nœud ou le pod qui a envoyé la requête, et confirmez que l’application a terminé au lieu de simplement recevoir un SYN. Une capture montrant une requête sans réponse est un problème de routage de l’autre côté, pas un problème de masquerade de ce côté.
Le retour en arrière, c’est la ConfigMap précédente, appliquée de la même manière, avec la même confirmation que l’agent a redémarré et que les règles ont changé. Conservez l’adresse source avant et après pour une requête connue dans le journal des changements, car c’est cette seule ligne qui prouve que le changement a fait ce que vous avez dit. Le guide de l’agent de masquerade IP de GKE documente les valeurs par défaut et les champs de la ConfigMap. Si l’adresse source est inchangée après le déploiement, l’agent ne tourne pas sur ce nœud et aucune édition de YAML n’y remédiera.