Un pod du namespace shop appelle http://api et la requête expire. Le pod tourne, le Service existe et son EndpointSlice liste deux backends prêts. La panne peut venir du DNS, des règles que kube-proxy a écrites sur le nœud, de l'overlay entre les nœuds ou d'une NetworkPolicy appliquée la semaine dernière. Chacune est une couche distincte, gérée par un composant distinct.
Cet article parcourt ces couches à l'aide d'un schéma : le modèle réseau, le trafic de pod à pod, les plugins CNI, les Services, le DNS, NetworkPolicy, et le trafic entrant et sortant du cluster.
Le modèle réseau de Kubernetes
Le modèle réseau de Kubernetes repose sur trois règles. Chaque pod reçoit sa propre adresse IP à l'échelle du cluster, partagée par ses conteneurs. Chaque pod peut joindre tous les autres pods, sur n'importe quel nœud, sans proxy ni NAT. Et les agents de nœud, comme le kubelet, peuvent joindre tous les pods de leur nœud.
Kubernetes définit les API, et les composants que vous installez font le travail :
| Couche | Ce qu'elle apporte | Implémentée par |
|---|---|---|
| Réseau de pods | Une IP par pod, accessibilité de pod à pod | Un plugin CNI |
| Services | Une IP virtuelle stable et un nom pour un ensemble de pods | kube-proxy ou un remplaçant eBPF |
| DNS | Des noms comme api.shop.svc.cluster.local |
CoreDNS |
| NetworkPolicy | Des règles d'autorisation pour le trafic des pods | Le plugin CNI |
| Ingress, Gateway API | Le routage depuis l'extérieur du cluster | Un contrôleur que vous installez |
Ce découpage explique bien des surprises, comme une NetworkPolicy que le serveur d'API accepte mais que votre plugin ignore en silence.
De pod à pod sur le même nœud
Quand le runtime de conteneurs démarre un pod, il appelle le plugin CNI avec ADD. La plupart des plugins créent une paire veth, un câble virtuel avec eth0 dans le pod et l'autre extrémité sur l'hôte, et attribuent l'IP. Flannel branche l'extrémité côté hôte sur un bridge Linux, cni0 ; Calico se passe de bridge : chaque pod reçoit une route /32, et l'hôte joue le rôle de routeur. Dans les deux cas, le trafic sur un même nœud n'a besoin ni d'encapsulation ni de NAT.
De pod à pod entre nœuds : overlay ou routage natif
Chaque nœud possède généralement une tranche de la plage de pods. Avec la valeur par défaut de --node-cidr-mask-size du kube-controller-manager, soit 24, une plage 10.244.0.0/16 donne un /24 à chacun de 256 nœuds, soit 256 adresses pour les 110 pods par défaut du kubelet. Entre les nœuds, le plugin a deux options :
| Overlay (VXLAN, Geneve, IP-in-IP) | Routage natif (BGP, routes cloud, IP de VPC) | |
|---|---|---|
| Le réseau entre les nœuds voit | Uniquement les IP des nœuds | Les IP des pods |
| Nécessite | Une joignabilité IP entre les nœuds | Un réseau qui route les plages de pods, ou des adresses de VPC pour les pods |
| Surcoût par paquet | 50 octets pour VXLAN en IPv4, 20 pour IP-in-IP | Aucun |
| Exemples | Valeurs par défaut de Flannel et Cilium, Calico VXLAN | Calico avec BGP, AWS VPC CNI, Azure CNI |
Ce surcoût pose un problème de MTU : sur un réseau de 1 500 octets, les pods derrière du VXLAN en IPv4 ont besoin d'une MTU de 1 450, d'après le guide MTU de Calico. Si vous la réglez mal, les gros paquets disparaissent, ce qui ressemble à des blocages aléatoires.
Comparaison des plugins CNI
| Plugin | Trafic entre nœuds | NetworkPolicy | Remarques |
|---|---|---|---|
| Flannel | VXLAN par défaut (UDP 8472) ; host-gw sur un réseau de couche 2 partagé |
Non appliquée par Flannel ; ajoutez kube-network-policies ou Calico | Petit et simple |
| Calico | BGP, ou overlay VXLAN (UDP 4789) ou IP-in-IP | Complète, plus les politiques de Calico par namespace et globales | Plans de données iptables, nftables, eBPF, VPP et Windows |
| Cilium | VXLAN par défaut (UDP 8472), Geneve ou routage natif | Complète, plus des règles de couche 7 et basées sur le DNS | Chemin de données eBPF |
| AWS VPC CNI | Pas d'overlay ; les pods reçoivent des adresses de VPC | Depuis la v1.14, avec enableNetworkPolicy |
Pods par nœud limités par le type d'instance |
La limite d'AWS se fait sentir tôt : le maximum par défaut est ENI × (IP par ENI − 1) + 2, donc une m5.large avec 3 interfaces de 10 adresses exécute 3 × 9 + 2 = 29 pods. La délégation de préfixes l'augmente.
Services : une IP stable devant des pods qui changent
Les IP de pod changent chaque fois qu'un pod est remplacé. Un Service donne à un ensemble de pods une IP virtuelle stable, la ClusterIP, et un nom DNS ; les EndpointSlices suivent les pods qui se trouvent derrière.
| Type | Ce que vous obtenez |
|---|---|
| ClusterIP (par défaut) | Une IP virtuelle à l'intérieur du cluster |
| NodePort | En plus, un port sur chaque nœud, 30000–32767 par défaut |
| LoadBalancer | En plus, un load balancer du cloud ou d'un add-on |
| ExternalName | Un alias DNS (CNAME), sans proxy |
Headless (clusterIP: None) |
Pas d'IP virtuelle ; le DNS renvoie les IP des pods |
Aucune machine ne possède une ClusterIP. Sur chaque nœud, kube-proxy programme le noyau pour qu'un paquet à destination de 10.96.48.20:80 soit réécrit (NAT de destination) vers une adresse de pod comme 10.244.2.22:8080 avant de quitter le nœud du client. Le Service est une étape logique, pas un serveur. Les règles dépendent du mode de proxy :
| Mode | Statut dans Kubernetes 1.37 | Fonctionnement |
|---|---|---|
| iptables | Par défaut sous Linux | Règles par Service et par endpoint ; backend aléatoire |
| nftables | GA depuis la 1.33 ; futur mode par défaut prévu | Mises à jour plus rapides à grande échelle ; nécessite un noyau 5.13 ou plus récent |
| ipvs | Déprécié depuis la 1.35 ; désactivé par défaut en 1.40, supprimé en 1.43 | Tables IPVS du noyau, plus d'algorithmes d'équilibrage |
| eBPF (Cilium, Calico) | Remplace kube-proxy | Équilibrage de charge dans des programmes eBPF |
Définissez le mode explicitement pour qu'une mise à niveau ne puisse pas le changer, et prévoyez de quitter IPVS. En mode nftables, les NodePorts n'écoutent par défaut que sur les adresses principales du nœud.
DNS avec CoreDNS
CoreDNS est le DNS de cluster par défaut, et kubeadm l'exécute derrière un Service toujours nommé kube-dns. Chaque Service reçoit un nom, <service>.<namespace>.svc.cluster.local, qui se résout en sa ClusterIP, ou en IP de pods pour un Service headless. Le kubelet écrit le /etc/resolv.conf de chaque pod ; dans shop sur un cluster kubeadm, il contient typiquement :
nameserver 10.96.0.10
search shop.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
Le piège est ndots:5 : un nom de moins de cinq points, comme api.stripe.com, est d'abord essayé avec chaque domaine de recherche, si bien qu'une résolution externe peut coûter trois requêtes en échec. Ajoutez un point final aux noms très sollicités, baissez ndots dans le dnsConfig du pod, ou exécutez NodeLocal DNSCache. Les noms externes suivent ensuite le chemin décrit dans comment fonctionne le DNS.
NetworkPolicy : de l'autorisation par défaut au moindre privilège
Par défaut, chaque pod accepte le trafic de partout. Dès qu'une NetworkPolicy sélectionne un pod en ingress (ou en egress), seul ce qu'une politique autorise passe ; les réponses sont autorisées automatiquement. Les politiques n'ajoutent que des règles d'autorisation, donc l'ordre n'a jamais d'importance. Commencez chaque namespace par un refus par défaut :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: shop
spec:
podSelector: {}
policyTypes:
- Ingress
Ouvrez ensuite ce dont vous avez besoin, ici TCP 8080 de web vers api :
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-allow-web
namespace: shop
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: web
ports:
- protocol: TCP
port: 8080
Quatre détails piègent souvent :
- Le port est celui du pod, 8080, et non le port 80 du Service.
- Le refus par défaut isole aussi les pods web, donc le Gateway a besoin de sa propre règle pour les joindre.
- Un tiret change le sens. Un
namespaceSelectoret unpodSelectordans une même entréefromdoivent correspondre tous les deux ; en deux entrées, l'un ou l'autre suffit. - Le refus par défaut en egress bloque le DNS, donc autorisez d'abord le port 53 vers
kube-dns.
NetworkPolicy n'a pas de règles de refus, pas de portée à l'échelle du cluster et rien pour TLS ; pour du TLS mutuel entre workloads, voyez le schéma d'architecture de service mesh.
Trafic entrant et sortant : Ingress, Gateway API et egress
Ingress est stable mais figé, et le projet Kubernetes recommande plutôt la Gateway API. Le contrôleur communautaire Ingress NGINX a été retiré en mars 2026 et ne reçoit plus de correctifs de sécurité, pourtant les installations existantes continuent de tourner sans qu'on le remarque.
La Gateway API répartit le travail par rôle : les responsables de la plateforme gèrent le Gateway, avec ses listeners et ses certificats, et les équipes applicatives attachent des HTTPRoutes depuis leurs propres namespaces. Elle est passée en GA en octobre 2023, et les versions de 2026 ont aussi rendu TLSRoute, TCPRoute et UDPRoute standard. Le schéma d'ingress Kubernetes suit ce chemin saut par saut.
L'egress est la direction oubliée. Le trafic qui quitte le cluster est généralement traduit vers l'IP du nœud, comme le fait AWS VPC CNI pour les destinations hors du VPC. Limitez-le avec des règles d'egress, qui ne voient les destinations externes que comme des plages d'IP, avec des règles sensibles au DNS comme toFQDNs de Cilium, ou avec un egress gateway quand un partenaire a besoin d'une IP source fixe.
Le schéma réseau Kubernetes
Contenu du diagramme
- worker-1 · pods 10.244.1.0/24
- worker-2 · pods 10.244.2.0/24
- Users
- public-gw
- web · 10.244.1.12
- coredns · 10.244.1.5
- api · 10.244.2.21
- api · 10.244.2.22
- api · 10.96.48.20
- api-allow-web
- HTTPS 443
- HTTPRoute
- DNS: api.shop.svc.cluster.local via kube-dns 10.96.0.10
- TCP 10.96.48.20:80
- DNAT 10.244.2.21:8080
- DNAT 10.244.2.22:8080
- VXLAN overlay over UDP · node IP to node IP
Comment le lire :
- Deux nœuds worker, chacun étiqueté avec sa plage de pods /24.
- Le bleu, c'est le nord-sud : les utilisateurs atteignent
public-gwen HTTPS 443, et une HTTPRoute les envoie vers le pod web. - L'ambre, c'est le DNS : web interroge CoreDNS, via
kube-dnsà 10.96.0.10, pourapi.shop.svc.cluster.localet obtient 10.96.48.20. - Le turquoise, c'est le chemin du Service : web se connecte à 10.96.48.20:80, et les règles kube-proxy sur worker-1 le réécrivent vers un pod api sur le port 8080.
- Le gris, c'est l'overlay : le paquet passe vers worker-2 dans du VXLAN, entre les IP des nœuds.
- Le rouge, c'est la politique :
api-allow-webne laisse que les podsapp=webjoindre les pods api. - Le bloc Markdown liste les valeurs par défaut derrière les chiffres.
Dessiner clairement des schémas réseau Kubernetes
- Étiquetez les nœuds avec les plages de pods et les pods avec leurs IP, les détails que vous cherchez dans les logs.
- Dessinez le Service comme une étape logique et notez où se fait la réécriture.
- Étiquetez les liens avec l'adresse, le port et le protocole, en passant au port du pod après le Service.
- Colorez différemment le nord-sud et l'est-ouest, et dessinez l'overlay une seule fois, entre les nœuds.
- Rattachez chaque politique aux pods qu'elle sélectionne, avec la source autorisée.
- Omettez le kubelet, le serveur d'API et les réplicas supplémentaires ; le schéma d'architecture Kubernetes couvre le plan de contrôle.
- Erreurs fréquentes : kube-proxy dans le chemin des paquets (il écrit des règles, c'est le noyau qui transfère), pas de DNS, et une politique sur un plugin qui l'ignore.
Le construire dans Archboard
- Connectez-vous avec Google ou GitHub et créez un schéma. L'outil gratuit Kubernetes YAML vers schéma transforme des manifests existants en première ébauche.
- Ajoutez deux nœuds Cadre du pack Base pour worker-1 et worker-2, étiquetés avec leurs plages de pods.
- Depuis le pack Kubernetes, ajoutez quatre nœuds Pod avec leurs IP : web et coredns dans worker-1, deux pods api dans worker-2.
- Ajoutez un Service (ClusterIP, port 80 vers 8080) entre les cadres, avec des liens étiquetés depuis web et vers les deux pods api.
- Ajoutez une NetworkPolicy sélectionnant
app=api, avec des liens en pointillés vers les pods api. - Ajoutez un nœud Internet du pack Réseau et un Gateway avec un listener HTTPS 443, et chaînez-les au pod web.
- Tracez un lien DNS en tirets de web vers coredns et un lien VXLAN épais et bidirectionnel entre les cadres.
- Ajoutez un bloc Markdown du pack Base avec les valeurs par défaut, et de courtes notes Texte.
La page du cas d'usage Kubernetes liste d'autres objets. L'exemple utilise 11 nœuds de diagramme et reste dans les limites de l'offre Free.
FAQ
Comment les pods communiquent-ils entre nœuds dans Kubernetes ? Par le plugin CNI : un overlay encapsule les paquets de pods entre les IP des nœuds, ou le routage natif transporte directement les adresses de pods. Dans les deux cas, les pods voient les vraies IP les uns des autres.
Quelle est la différence entre une IP de pod et une ClusterIP ? Une IP de pod appartient à un seul pod et change quand le pod est remplacé. Une ClusterIP est l'IP virtuelle stable d'un Service, que kube-proxy ou un remplaçant eBPF réécrit vers une IP de pod actuelle.
Quel mode kube-proxy dois-je utiliser ? Dans Kubernetes 1.37, iptables est le mode par défaut, nftables est GA depuis la 1.33 et deviendra le mode par défaut, et IPVS est déprécié. Avec un noyau 5.13 ou plus récent, nftables est le meilleur choix à long terme.
Les NetworkPolicies fonctionnent-elles avec tous les plugins CNI ? Non. L'API les accepte partout, mais seuls les plugins qui implémentent NetworkPolicy les appliquent : Calico, Cilium et AWS VPC CNI avec la politique réseau activée le font ; Flannel seul, non.
Dois-je utiliser Ingress ou la Gateway API ? La Gateway API pour tout nouveau projet : Kubernetes la recommande, et Ingress est figé. Les ressources Ingress existantes continuent de fonctionner, mais prévoyez de quitter Ingress NGINX, qui ne reçoit plus de correctifs de sécurité.