Aller au contenu
Le modèle réseau de Kubernetes

Le modèle réseau de Kubernetes

200 Pratiquer ⏱ 1 h 10 kubernetesciliumiptables

À la fin, vous saurez

  • Énoncer les trois exigences du modèle réseau de Kubernetes et les vérifier sur un cluster
  • Distinguer la plage des pods, découpée par nœud, de la plage des Services
  • Expliquer ce que Kubernetes fait lui-même et ce qu'il délègue au plugin CNI
  • Décrire l'espace de noms réseau d'un pod et le rôle du conteneur pause
  • Comparer le modèle d'un pod à celui d'un conteneur Docker sur un pont avec NAT
  • Mesurer les conséquences de sécurité d'un réseau plat par défaut

Prérequis

Testé avec cilium 1.20.2 kubernetes 1.36 , vérifié le 5 octobre 2026

Pourquoi

Dans la leçon Services et DNS, les pods de Signalements obtenaient une adresse « par le plugin réseau du cluster », et un Service la traduisait vers eux. Ces deux phrases cachent presque tout : qui choisit l'adresse d'un pod, comment un paquet venu d'un pod du nœud A atteint un pod du nœud B, et pourquoi cela marche sans que vous ayez écrit une seule route.

Sans modèle clair, chaque panne réseau devient une devinette. Le pod signalements-7d9f n'arrive pas à joindre PostgreSQL : est-ce le nom, la route, le filtrage, la traduction d'adresses ? On ne peut poser la bonne question que si l'on sait ce que le cluster garantit et ce qu'il laisse au plugin réseau.

Kubernetes a fait un choix net, très différent de celui de Docker : il fixe des règles de résultat (ce que le réseau doit permettre) sans imposer de mécanisme (comment). Cette leçon pose les règles, les plages d'adresses qui en découlent, le partage de réseau à l'intérieur d'un pod, et les conséquences de sécurité d'un réseau où tout le monde joint tout le monde.

Les concepts

Les exigences du modèle

La documentation de Kubernetes décrit le réseau par quelques garanties. Reprises avec nos mots :

  1. Chaque pod a sa propre adresse IP, unique dans tout le cluster, pas seulement dans son nœud. Ce n'est pas l'adresse du nœud, ni une adresse partagée avec d'autres pods.
  2. Tous les pods se joignent entre eux, sur le même nœud ou sur des nœuds différents, directement, sans proxy et sans traduction d'adresses (NAT). L'adresse qu'un pod se connaît à lui-même est celle que les autres voient.
  3. Les agents d'un nœud (les démons système, le kubelet) joignent tous les pods de ce nœud.

La seconde garantie est la plus structurante. Elle a une conséquence que vous pouvez vérifier : si le pod a (10.244.1.5) appelle le pod b (10.244.2.7), b voit arriver une connexion dont la source est 10.244.1.5, et non l'adresse du nœud de a. Le journal d'accès de Signalements peut donc afficher l'adresse du pod appelant, et une règle de filtrage peut s'écrire sur cette adresse (ou, mieux, sur les étiquettes du pod, voir la leçon 8 du cours, à venir).

Un cas particulier : un pod déclaré avec hostNetwork: true partage le réseau du nœud au lieu d'avoir le sien. Il n'a pas d'adresse propre (il utilise celle du nœud), et la documentation signale que la garantie 2 ne s'applique pas à lui sous Windows. On réserve cette option aux composants d'infrastructure (le plugin réseau lui-même, un agent de supervision).

Note

Le modèle ne dit rien de l'extérieur du cluster. Un pod qui appelle Internet passe par une traduction d'adresses (leçon 3), et un client externe n'a aucune raison de joindre directement l'adresse d'un pod. Les garanties valent à l'intérieur du cluster.

Ce modèle est un choix de simplicité pour les applications. Le cours Docker décrit l'autre approche (Les réseaux de Docker) : chaque conteneur reçoit une adresse privée sur un pont de la machine, et pour être joint de l'extérieur, un port est publié sur la machine, avec traduction d'adresses. Avec cette approche, les applications doivent connaître leur adresse publique, les ports hôte se disputent, et deux conteneurs de deux machines ne se voient pas sans configuration. Kubernetes écarte ces difficultés : un pod est traité comme une petite machine virtuelle, avec son adresse, ses ports, son localhost.

Les plages d'adresses

Pour donner à chaque pod une adresse unique, il faut une plage d'adresses réservée aux pods. Un cluster en manipule plusieurs, qu'il faut savoir distinguer.

PlageCe qu'elle contientQui l'attribueExemple (kind, par défaut)
Réseau des nœudsLes adresses des machinesLe fournisseur ou l'administrateurréseau Docker kind
Pod CIDR du clusterLes adresses de tous les podsChoisie à la création du cluster10.244.0.0/16
Pod CIDR du nœudLa part de la plage réservée à un nœudUn contrôleur, ou le plugin réseau10.244.1.0/24
Service CIDRLes adresses virtuelles des ServicesChoisie à la création10.96.0.0/16

La plage des pods est découpée par nœud. Dans l'organisation classique, un contrôleur du plan de contrôle (le node IPAM controller, dans le kube-controller-manager) attribue à chaque nœud, quand il rejoint le cluster, un sous-réseau, enregistré dans spec.podCIDR de l'objet Node. Pour de l'IPv4, la taille par défaut de ce sous-réseau est un /24, soit environ 250 pods par nœud. Quand le kubelet doit démarrer un pod, l'adresse est prise dans le sous-réseau du nœud.

Ce découpage a deux vertus. D'abord, l'unicité est garantie sans coordination : deux nœuds ne piochent jamais dans le même sous-réseau. Ensuite, le routage devient simple. Pour joindre une adresse de pod, il suffit de savoir quel nœud possède son sous-réseau, une seule route par nœud : « 10.244.2.0/24 passe par le nœud 2 ». C'est le principe de l'agrégation de routes vu dans la leçon Le routage du cours TCP/IP, appliqué au cluster.

La plage des Services est d'une autre nature : ses adresses sont virtuelles, portées par aucune interface, traduites par kube-proxy ou par le plugin réseau (voir la leçon kube-proxy et ses alternatives). Elle ne doit jamais chevaucher la plage des pods, ni celle des nœuds, ni les réseaux que vos pods doivent joindre (un réseau privé Scaleway, un VPN vers le client). Un chevauchement produit des pannes subtiles : le pod envoie un paquet vers un hôte réel, et la table de routage l'envoie dans le cluster.

Warning

Ces plages se choisissent à la création du cluster et se changent très difficilement ensuite. Une plage de pods trop petite plafonne le nombre de nœuds (avec des /24, un /16 ne fournit que 256 nœuds) ; une plage qui chevauche un réseau d'entreprise interdit plus tard de relier le cluster à ce réseau. Pensez au VPN et à l'interconnexion avant de créer le cluster.

Ce que Kubernetes ne fait pas

Kubernetes décrit le résultat attendu mais ne contient pas le code qui crée les interfaces, attribue les adresses et programme les routes. La documentation le dit : le réseau des pods est géré par une implémentation de réseau de pods, et, sous Linux, la plupart des moteurs de conteneurs la pilotent par l'interface standard CNI (Container Network Interface). Ces implémentations s'appellent des plugins CNI.

La répartition est la suivante :

TâcheQui s'en charge
Décider qu'un pod existe, sur quel nœudLe plan de contrôle (ordonnanceur)
Démarrer le pod, demander son réseauLe kubelet, via le moteur de conteneurs (containerd)
Créer l'interface du pod, attribuer l'adresse, installer les routesLe plugin CNI
Faire joindre un pod d'un autre nœudLe plugin CNI (route, tunnel...)
Traduire l'adresse d'un Service vers un podkube-proxy, ou le plugin CNI qui le remplace
Appliquer les NetworkPoliciesLe plugin CNI, ou rien du tout
Répondre aux requêtes DNS du clusterCoreDNS (un Deployment ordinaire)

La dernière ligne qui concerne le plugin est celle qui surprend le plus : l'API des NetworkPolicies existe dans tous les clusters, mais c'est le plugin qui les applique. Avec un plugin qui ne les gère pas, vous pouvez créer une NetworkPolicy, l'API l'accepte, et rien n'est filtré. Nous y reviendrons dans la section Sécurité.

Quand aucun plugin CNI n'est installé, les nœuds restent NotReady, et les pods ne démarrent pas : le kubelet ne peut pas créer leur réseau. C'est le comportement documenté pour un cluster kind créé sans plugin par défaut, que nous exploitons à la leçon suivante.

L'espace de noms réseau d'un pod

Un pod est un groupe de conteneurs qui partagent des ressources, et d'abord leur réseau. Sous Linux, une pile réseau complète (interfaces, adresses, table de routage, règles de filtrage, table des ports) est isolée dans un espace de noms réseau (namespace Linux, à ne pas confondre avec un namespace Kubernetes). Les conteneurs du pod rejoignent tous le même espace de noms réseau. Conséquences, que la documentation énonce : les conteneurs d'un pod se parlent par localhost, et se partagent la table des ports, donc deux conteneurs d'un même pod ne peuvent pas écouter sur le même port.

Pour porter cet espace de noms, le moteur de conteneurs démarre d'abord un conteneur minuscule, le conteneur pause (le sandbox du pod, une image pause d'environ quelques centaines de kilo-octets, qui ne fait qu'attendre). Il crée les espaces de noms, puis le plugin CNI configure cet espace de noms (interface, adresse), et enfin les conteneurs de l'application (Signalements, son sidecar) le rejoignent. La raison d'être de pause : un conteneur d'application peut planter et redémarrer à tout moment ; l'espace de noms, et donc l'adresse IP du pod, doit survivre à ces redémarrages. Tant que le pod existe, pause tient le réseau.

    flowchart TB
  subgraph Pod["Pod signalements-7d9f (une adresse IP : 10.244.1.5)"]
    P["pause<br/>(porte l'espace de noms réseau)"]
    A["gunicorn<br/>écoute 0.0.0.0:8000"]
    S["sidecar<br/>joint localhost:8000"]
  end
  P --- A
  P --- S
  Pod --- V["interface veth<br/>vers le nœud"]
  

C'est pourquoi kubectl get pods -o wide affiche une adresse par pod, et pourquoi un kubectl delete pod suivi d'un remplacement donne une nouvelle adresse : le sandbox est détruit, un autre est créé, et le plugin CNI attribue une autre adresse. Redémarrer un conteneur garde l'adresse ; recréer le pod la change.

Tip

Les conteneurs d'un pod ne se parlent pas par le réseau « pour de vrai » : localhost ne traverse aucune interface physique ni aucune règle de pare-feu entre conteneurs du pod. C'est la raison pour laquelle un NetworkPolicy ne peut jamais isoler deux conteneurs d'un même pod l'un de l'autre.

En pratique

Les commandes ci-dessous s'exécutent sur le cluster kind formation (ou sur Kapsule) avec Signalements déployé. La leçon décrit ce que vous devez observer, sans reproduire de sortie.

Lire les plages et les adresses

$ kubectl get nodes -o custom-columns='NOEUD:.metadata.name,POD-CIDR:.spec.podCIDR'

-o custom-columns affiche les champs choisis. Vous obtenez une ligne par nœud, avec un sous-réseau /24 distinct pour chacun, tous pris dans la même plage de pods. Sur un cluster dont le plugin gère lui-même l'attribution (c'est possible, voir la leçon suivante), la colonne peut être vide : le plugin n'utilise pas le champ de l'objet Node.

$ kubectl get pods -n signalements -o wide

La colonne IP donne l'adresse de chaque pod, dans le sous-réseau du nœud indiqué dans la colonne NODE. Vérifiez la correspondance avec la commande précédente : un pod du nœud formation-worker a une adresse dans le podCIDR de ce nœud.

Pour l'adresse des Services, le Service CIDR ne se lit pas dans un objet Node. Un moyen indirect consiste à observer l'adresse du Service kubernetes du namespace default, qui est la première adresse de la plage :

$ kubectl get service kubernetes -n default

Sur un cluster kind par défaut, l'adresse est de la forme 10.96.0.1 : la plage des Services est 10.96.0.0/16. Sur un autre fournisseur, l'adresse diffère, mais la logique est la même. Les paramètres exacts se lisent dans la configuration du serveur d'API (--service-cluster-ip-range), que les offres managées affichent dans leur console.

Vérifier les exigences

Exigence 1 et 2 : pod à pod sans NAT. Lancez deux pods de diagnostic sur deux nœuds différents. Le plus simple est de s'appuyer sur les pods de Signalements, qui sont répartis, et d'un pod de diagnostic :

$ kubectl run diag --rm -it --restart=Never --image=nicolaka/netshoot -n signalements -- bash

Dans le pod, appelez directement l'adresse d'un pod de Signalements (relevée à l'étape précédente), pas le Service :

bash-5.2# curl -s http://10.244.2.7:8000/sante

Remplacez l'adresse par celle de votre pod. La réponse vient du pod, directement. Pour voir l'adresse source telle que le pod la reçoit, il faut consulter son journal d'accès : gunicorn, configuré pour journaliser, y inscrit l'adresse du client. Elle doit être l'adresse du pod diag (visible par kubectl get pod diag -o wide), et pas celle d'un nœud. Si vous voyez l'adresse d'un nœud, c'est qu'une traduction d'adresses s'est glissée sur le chemin : voir les pièges.

Exigence 3 : le nœud joint ses pods. Sur kind, les nœuds sont des conteneurs Docker. Depuis le nœud, un curl direct sur l'adresse d'un pod du même nœud doit répondre :

$ docker exec formation-worker curl -s http://10.244.1.5:8000/sante

C'est exactement ce que fait le kubelet quand il sonde la disponibilité d'un pod : il joint l'adresse du pod depuis le nœud, par la garantie 3.

Regarder le réseau du pod de l'intérieur

bash-5.2# ip addr
bash-5.2# ip route

ip addr montre deux interfaces : lo (le localhost du pod) et eth0, qui porte l'adresse du pod. ip route montre une route par défaut qui passe par une adresse de passerelle sur eth0. Le nom eth0 est trompeur : ce n'est pas une carte réseau, mais une extrémité d'une paire veth (La couche liaison, et le terme au glossaire). L'autre extrémité vit dans l'espace de noms du nœud. Le plugin CNI a créé ce câble virtuel quand le pod a démarré.

Voir les conteneurs pause

Sur un nœud kind, si le moteur est containerd, la commande crictl liste les sandboxes :

$ docker exec formation-worker crictl pods
$ docker exec formation-worker crictl ps

crictl pods liste les sandboxes (un par pod, c'est l'espace de noms réseau), crictl ps liste les conteneurs applicatifs (pas les pause). Le nombre de sandboxes correspond au nombre de pods du nœud, y compris ceux de kube-system.

Sous le capot

Créer le réseau d'un pod. Quand le kubelet doit démarrer un pod, il demande au moteur de conteneurs (containerd) de créer le sandbox. Le moteur crée les espaces de noms Linux et exécute le plugin CNI configuré, en lui passant le chemin de l'espace de noms réseau du sandbox. Selon la spécification CNI 1.1.0, le plugin reçoit sa configuration en JSON sur l'entrée standard et des paramètres dans des variables d'environnement (CNI_COMMAND=ADD, CNI_CONTAINERID, CNI_NETNS, CNI_IFNAME...), et renvoie en JSON l'adresse attribuée et les routes. Le détail est l'objet de la leçon suivante. Retenez que le kubelet n'a aucune idée de ce que fait le plugin : il attend seulement une adresse.

L'adresse du pod est publiée par le kubelet. Une fois le sandbox prêt, l'adresse est écrite dans status.podIP du Pod ; c'est ce champ que le contrôleur d'EndpointSlices recopie pour construire la liste des points d'accès d'un Service. Cette adresse vit exactement le temps du pod : aucun mécanisme ne la conserve, ce qui est la raison d'être des Services.

Une route par nœud, ou un tunnel. Dans le modèle le plus simple, chaque nœud connaît une route par sous-réseau de pod de chaque autre nœud, avec pour passerelle l'adresse du nœud propriétaire. Un paquet du pod a vers le pod b sort par la veth de a, est routé sur le nœud 1, traverse le réseau des nœuds jusqu'au nœud 2, puis descend dans la veth de b. Si le réseau des nœuds ne transporte pas des adresses de pods (par exemple parce qu'il filtre les paquets dont la source n'est pas l'adresse d'un nœud), le plugin encapsule : il enveloppe le paquet du pod dans un paquet entre nœuds. Le choix entre ces deux familles est le sujet central de la leçon 2.

Pourquoi pas de NAT entre pods. Le NAT casse l'identité : le pod destinataire ne saurait plus qui l'appelle, et les protocoles qui transportent des adresses dans leurs données (une adresse de rappel, un enregistrement de pair) cesseraient de fonctionner. Il masque aussi la source dans les journaux, au moment même où l'on en a besoin pour diagnostiquer. En supprimant le NAT interne, Kubernetes réserve la traduction aux frontières : Service (DNAT vers un pod) et sortie vers l'extérieur (masquerade). Ces deux frontières sont le sujet de la leçon 3.

Pièges courants

Un chevauchement de plages. Le pod ne joint pas un serveur du réseau d'entreprise du client, alors que le nœud le joint. La plage des pods (ou celle des Services) recouvre le réseau cible : le noyau du pod route ces adresses vers le cluster. Diagnostic : comparer l'adresse cible à spec.podCIDR des nœuds et au Service CIDR ; ip route get <adresse> depuis le pod montre la route choisie.

Un NAT inattendu entre pods. Les journaux de Signalements affichent l'adresse d'un nœud au lieu de celle du pod appelant. Causes fréquentes : l'appel passe par un Service avec externalTrafficPolicy: Cluster depuis l'extérieur (leçon 3), un plugin ou un mode qui masque le trafic entre nœuds, ou un pod hostNetwork. Le cas « pod à pod direct » ne doit jamais afficher l'adresse d'un nœud.

Des pods bloqués en ContainerCreating. Message typique dans kubectl describe pod : failed to set up sandbox container ... network plugin ... suivi d'un détail du plugin (plus d'adresses disponibles dans la plage du nœud, plugin qui ne répond pas). Le pod existe, mais son réseau n'a pas pu être créé. Les événements (kubectl get events -n signalements --sort-by=.lastTimestamp) donnent le motif. Une plage de nœud épuisée (/24 plein) en est une cause classique sur les nœuds qui hébergent beaucoup de petits pods.

Croire qu'une adresse de pod est stable. Mettre l'adresse d'un pod dans une configuration, une liste de pare-feu, une règle de base de données. Elle change à chaque recréation du pod. On filtre par étiquettes (NetworkPolicy) ou par nom de Service.

Deux conteneurs d'un pod sur le même port. Le second échoue avec Address already in use : ils partagent la table des ports. Chaque conteneur d'un pod doit avoir son port.

Confondre le Service CIDR et le Pod CIDR. Une adresse du Service CIDR ne répond jamais au ping et n'apparaît dans aucun ip addr ; une adresse du Pod CIDR est portée par une vraie interface.

Sécurité

Le modèle réseau de Kubernetes est plat et ouvert par défaut : tout pod joint tout pod, de tous les namespaces. C'est le prix de la simplicité, et il faut le payer en connaissance de cause.

  • Le namespace n'est pas une frontière réseau. Un pod du namespace test peut appeler PostgreSQL du namespace signalements : il lui suffit de connaître l'adresse ou le nom. Un conteneur compromis (une dépendance piégée, une faille dans l'application) peut donc balayer le cluster : tester les adresses du Pod CIDR, énumérer les Services par DNS, atteindre les bases et les API internes. La parade est la NetworkPolicy (leçon 8, à venir), qui passe en refus par défaut, puis autorise le strict nécessaire.
  • Une NetworkPolicy sans plugin compatible est un faux sentiment de sécurité. L'API accepte l'objet sans erreur, même si le plugin ne l'applique pas. Vérifiez que votre plugin gère les NetworkPolicies, et testez qu'un trafic interdit l'est réellement. Cilium et Calico les appliquent ; pour un plugin plus simple (kindnet, le plugin par défaut de kind), consultez sa documentation pour la version utilisée, au lieu de le supposer.
  • Les agents joignent tous les pods de leur nœud. C'est la garantie 3, et elle a un revers : un processus compromis sur le nœud (ou un pod hostNetwork) joint les pods du nœud. Les NetworkPolicies ne filtrent généralement pas le trafic venu du nœud lui-même, par conception, pour que les sondes du kubelet fonctionnent.
  • Les points d'accès sensibles du nœud. Depuis un pod, l'adresse de métadonnées du fournisseur et l'API du kubelet (port 10250) sont atteignables si rien ne les filtre. Sur un cloud, les métadonnées donnent parfois des identifiants : à bloquer par une politique de sortie.
  • Le trafic entre pods n'est pas chiffré par défaut. Un attaquant qui capture le réseau des nœuds lit le trafic des pods. Le chiffrement (WireGuard ou IPsec chez certains plugins, TLS mutuel dans un maillage) est un choix explicite, vu à la leçon 9 du cours (à venir).

En production

  • Dimensionnez les plages dès le départ. Prévoyez large pour les pods (par exemple un /16 pour quelques dizaines de nœuds, davantage au-delà), évitez les plages courantes des réseaux d'entreprise (10.0.0.0/8 entier, 192.168.0.0/16), et réservez la plage de chaque cluster dans votre plan d'adressage, comme pour un réseau ordinaire. Si vous voulez interconnecter plusieurs clusters, ils doivent avoir des plages disjointes.
  • Le nombre de pods par nœud dépend de la taille du sous-réseau du nœud et d'une limite du kubelet (maxPods, 110 par défaut). Un /24 suffit pour 110 pods, avec de la marge pour le renouvellement ; un sous-réseau plus petit gaspillerait moins d'adresses mais plafonnerait plus tôt.
  • Sur Kapsule, le cluster est livré avec son plugin (Cilium par défaut chez Scaleway, voir la leçon 2) et ses plages ; elles se choisissent à la création et sont à noter dans votre documentation d'architecture. Si le cluster doit joindre un réseau privé Scaleway, vérifiez l'absence de chevauchement avant la création.
  • Documentez le modèle pour votre équipe : pods en réseau plat, namespaces non étanches, NetworkPolicies obligatoires pour les applications qui manipulent des données personnelles. C'est une exigence que les audits (RGPD, SecNumCloud) demandent de pouvoir démontrer.
  • Sachez ce que le fournisseur gère. Sur un service managé, le plugin CNI et ses réglages font partie du périmètre du fournisseur ; sur un cluster auto-hébergé, ce sont les vôtres : mise à jour, supervision, et choix du mode (leçon 2).

Exercices

1. Compter les nœuds (niveau 100). Un cluster est créé avec un Pod CIDR 10.244.0.0/16 et des sous-réseaux de nœud en /24. Combien de nœuds au maximum ? Combien d'adresses de pod utilisables par nœud ? Que se passe-t-il si on veut 400 nœuds ?

Solution

Un /16 contient 256 sous-réseaux /24 : 256 nœuds au maximum. Chaque /24 offre 254 adresses utilisables (256 moins l'adresse de réseau et celle de diffusion), ce qui couvre largement les 110 pods par défaut du kubelet. Pour 400 nœuds, il faut agrandir la plage (un /15 donne 512 sous-réseaux /24), ou réduire la taille des sous-réseaux de nœud (des /25 donneraient 512 nœuds de 126 adresses). Comme la plage se change difficilement, il vaut mieux la prévoir large dès la création.

2. Deux conteneurs, un port (niveau 200). Un pod contient gunicorn (port 8000) et un sidecar de métriques qui, par défaut, écoute aussi sur 8000. Le sidecar plante en boucle avec Address already in use. Expliquez, et proposez deux corrections.

Solution

Les conteneurs d'un pod partagent un seul espace de noms réseau, donc une seule table de ports : deux processus ne peuvent écouter sur le même port d'une même adresse. Correction 1 : changer le port du sidecar (par exemple 9102) par sa configuration, et déclarer ce port dans containerPort. Correction 2 : déplacer le sidecar dans un pod séparé, si son couplage au pod n'est pas indispensable. Ce partage est l'inverse de ce qui se passe entre deux pods, qui ont chacun leur table de ports.

3. Le NAT invisible (niveau 200). Les journaux d'accès de Signalements affichent, pour un appel venant d'un autre pod du namespace, l'adresse du nœud de ce pod. Le modèle réseau garantit l'inverse. Donnez trois hypothèses, dans l'ordre où vous les vérifiez, et la commande qui permet de les départager.

Solution
  1. L'appel ne vise pas directement l'adresse du pod mais un Service, avec un mode qui masque la source : vérifiez que l'appelant vise l'adresse du pod (test direct) et comparez. 2. Le pod appelant est en hostNetwork: true : kubectl get pod <nom> -o jsonpath='{.spec.hostNetwork}'. Son adresse est celle du nœud. 3. Le plugin ou son mode masque le trafic entre nœuds (option de masquerade activée pour des destinations qui devraient être exclues) : consulter la configuration du plugin et les règles de traduction du nœud (iptables -t nat -S POSTROUTING, ou l'équivalent du plugin). La première étape consiste toujours à reproduire avec un appel direct pod à pod, qui isole le Service du reste.

4. Plages en conflit (niveau 200). Lyneko doit relier un cluster (Pod CIDR 10.244.0.0/16, Service CIDR 10.96.0.0/16) au réseau d'un client dont une base est en 10.244.50.0/24. Que se passe-t-il quand un pod appelle cette base, et que faire ?

Solution

Le Pod CIDR du cluster contient 10.244.50.0/24. Une adresse de cette plage est considérée comme un pod du cluster : le routage la dirige vers un nœud (ou vers le sous-réseau d'un nœud), jamais vers le VPN. L'appel échoue ou atteint un mauvais pod, alors que le nœud lui-même (qui n'a pas cette route) joint peut-être la base. Pas de contournement propre : il faut changer la plage du cluster (recréer le cluster avec une autre plage) ou demander une traduction d'adresses côté client. D'où la règle : valider les plages avant de créer le cluster.

Récapitulatif

  • Le modèle réseau de Kubernetes tient en trois garanties : une adresse par pod, pods joignables sans NAT, agents du nœud joignant ses pods.
  • Les pods tirent leur adresse d'un Pod CIDR découpé par nœud (souvent un /24 par nœud) ; les Services utilisent une plage virtuelle distincte, le Service CIDR. Aucune ne doit chevaucher un réseau à joindre.
  • Kubernetes décrit le résultat ; le plugin CNI le réalise (interfaces, adresses, routes, parfois Services et NetworkPolicies).
  • Un pod est un espace de noms réseau partagé par ses conteneurs, tenu par le conteneur pause ; recréer le pod change l'adresse, redémarrer un conteneur non.
  • Le réseau est plat et ouvert par défaut, entre namespaces compris : le cloisonnement vient des NetworkPolicies, appliquées seulement si le plugin le permet.

Pour aller plus loin

  • La page Cluster Networking de la documentation de Kubernetes, qui énonce le modèle et ses exigences.
  • La spécification CNI 1.1.0, courte, pour voir ce que le moteur de conteneurs demande vraiment au plugin.
  • La leçon suivante, Les plugins CNI, qui explique comment un plugin tient ces promesses et laquelle choisir.
  • Le cours Le modèle TCP/IP, notamment les leçons sur le routage et le NAT.
Voir ma constellation →

Sources