Le modèle réseau de Kubernetes repose sur plusieurs éléments :
Chaque pod d'un cluster reçoit sa propre
adresse IP, unique dans tout le cluster.
Un pod a son propre namespace réseau privé, partagé par
tous les conteneurs du pod. Les processus qui s'exécutent dans
différents conteneurs d'un même pod peuvent communiquer entre eux
via localhost.
Le réseau des pods (aussi appelé réseau du cluster) gère la communication
entre les pods. Il garantit que (sauf segmentation réseau volontaire) :
Tous les pods peuvent communiquer avec tous les autres pods, qu'ils soient
sur le même nœud ou sur
des nœuds différents. Les pods peuvent communiquer entre eux
directement, sans proxy ni traduction d'adresses (NAT).
Sous Windows, cette règle ne s'applique pas aux pods qui utilisent le réseau de l'hôte.
Les agents d'un nœud (comme les démons système ou le kubelet) peuvent
communiquer avec tous les pods de ce nœud.
L'API Service
vous permet de fournir une adresse IP ou un nom d'hôte stable (durable) pour un service mis en œuvre
par un ou plusieurs pods backend, alors que les pods qui composent
ce service peuvent changer au fil du temps.
Kubernetes gère automatiquement des objets
EndpointSlice
qui donnent des informations sur les pods qui servent actuellement de backends à un Service.
Une implémentation de proxy de service surveille l'ensemble des objets Service et
EndpointSlice, et programme le plan de données pour acheminer
le trafic des services vers leurs backends, en utilisant les API du système d'exploitation ou
du fournisseur cloud pour intercepter ou réécrire les paquets.
L'API Gateway
(ou son prédécesseur, Ingress)
vous permet de rendre des Services accessibles à des clients extérieurs au cluster.
Un mécanisme plus simple, mais moins configurable, pour faire entrer le trafic
dans le cluster est proposé par le
type: LoadBalancer de l'API Service,
si vous utilisez un fournisseur de cloud compatible.
NetworkPolicy est une API
intégrée à Kubernetes qui vous permet de contrôler le trafic entre les pods, ou entre les pods et
le monde extérieur.
Dans les anciens systèmes de conteneurs, il n'existait pas de connectivité automatique
entre les conteneurs de différents hôtes. Il fallait donc souvent
créer explicitement des liens entre les conteneurs, ou faire correspondre les ports des conteneurs
à des ports de l'hôte pour que les conteneurs d'autres hôtes puissent les joindre.
Ce n'est pas nécessaire dans Kubernetes : dans son modèle,
les pods peuvent être traités presque comme des VM ou des hôtes physiques du point de vue
de l'allocation des ports, du nommage, de la découverte de services, de l'équilibrage
de charge, de la configuration des applications et de la migration.
Seules quelques parties de ce modèle sont mises en œuvre par Kubernetes lui-même.
Pour les autres, Kubernetes définit les API, mais la
fonctionnalité correspondante est fournie par des composants externes, dont certains
sont facultatifs :
La mise en place du namespace réseau des pods est assurée par un logiciel système qui implémente
la Container Runtime Interface.
Le réseau des pods lui-même est géré par une
implémentation du réseau des pods.
Sous Linux, la plupart des environnements d'exécution de conteneurs utilisent la
Container Networking Interface (CNI)
pour dialoguer avec l'implémentation du réseau des pods. C'est pourquoi ces
implémentations sont souvent appelées plugins CNI.
Kubernetes fournit une implémentation par défaut du proxy de service,
appelée kube-proxy, mais certaines implémentations
du réseau des pods utilisent plutôt leur propre proxy de service,
plus étroitement intégré au reste de leur implémentation.
Les NetworkPolicies sont en général aussi mises en œuvre par l'implémentation du réseau
des pods. (Certaines implémentations plus simples du réseau des pods ne
prennent pas en charge les NetworkPolicies, ou un administrateur peut choisir de
configurer le réseau des pods sans elles. Dans
ces cas, l'API reste présente, mais elle n'a aucun effet.)
Il existe de nombreuses implémentations de Gateway API,
certaines propres à des environnements cloud particuliers, d'autres plutôt
orientées vers les environnements « bare metal », et d'autres plus génériques.
Une manière abstraite d'exposer une application s'exécutant sur un ensemble de Pods en tant que service réseau.
Avec Kubernetes, vous n'avez pas besoin de modifier votre application pour utiliser un mécanisme de découverte de services inconnu.
Kubernetes donne aux pods leurs propres adresses IP et un nom DNS unique pour un ensemble de pods, et peut équilibrer la charge entre eux.
Motivation
Les Pods Kubernetes sont mortels.
Ils naissent et lorsqu'ils meurent, ils ne ressuscitent pas.
Si vous utilisez un Déploiement pour exécuter votre application, il peut créer et détruire dynamiquement des pods.
Chaque pod obtient sa propre adresse IP, mais dans un déploiement, l'ensemble de pods s'exécutant en un instant peut être différent de l'ensemble de pods exécutant cette application un instant plus tard.
Cela conduit à un problème: si un ensemble de pods (appelez-les «backends») fournit des fonctionnalités à d'autres pods (appelez-les «frontends») à l'intérieur de votre cluster, comment les frontends peuvent-ils trouver et suivre l'adresse IP à laquelle se connecter, afin que le frontend puisse utiliser la partie backend de la charge de travail?
C'est là où les Services rentrent en jeu.
La ressource Service
Dans Kubernetes, un service est une abstraction qui définit un ensemble logique de pods et une politique permettant d'y accéder (parfois ce modèle est appelé un micro-service).
L'ensemble des pods ciblés par un service est généralement déterminé par un selector (voir ci-dessous pourquoi vous voudrez peut-être un service sans un sélecteur).
Par exemple, considérons un backend de traitement d'image sans état qui s'exécute avec 3 replicas.
Ces réplicas sont fongibles et les frontends ne se soucient pas du backend qu'ils utilisent.
Bien que les pods réels qui composent l'ensemble backend puissent changer, les clients frontends ne devraient pas avoir besoin de le savoir, pas plus qu'ils ne doivent suivre eux-mêmes l'ensemble des backends.
L'abstraction du service permet ce découplage.
Découverte de services native du cloud
Si vous pouvez utiliser les API Kubernetes pour la découverte de services dans votre application, vous pouvez interroger l'API server pour les Endpoints, qui sont mis à jour chaque fois que l'ensemble des pods d'un service change.
Pour les applications non natives, Kubernetes propose des moyens de placer un port réseau ou un load balancer entre votre application et les modules backend.
Définition d'un service
Un service dans Kubernetes est un objet REST, semblable à un pod.
Comme tous les objets REST, vous pouvez effectuer un POST d'une définition de service sur le serveur API pour créer une nouvelle instance.
Par exemple, supposons que vous ayez un ensemble de pods qui écoutent chacun sur le port TCP 9376 et portent une étiquette app.kubernetes.io/name=MyApp:
Cette spécification crée un nouvel objet Service nommé «my-service», qui cible le port TCP 9376 sur n'importe quel pod avec l'étiquette «app.kubernetes.io/name=MyApp».
Kubernetes attribue à ce service une adresse IP (parfois appelé l'"IP cluster"), qui est utilisé par les proxies Service (voir IP virtuelles et proxy de service).
Le contrôleur de service recherche en continu les pods qui correspondent à son sélecteur, puis POST toutes les mises à jour d'un objet Endpoint également appelé "my-service".
Note:
Un service peut mapper n'importe quelport entrant vers un targetPort.
Par défaut et pour plus de commodité, le targetPort a la même valeur que le champ port.
Les définitions de port dans les pods ont des noms, et vous pouvez référencer ces noms dans l'attribut targetPort d'un service.
Cela fonctionne même s'il existe un mélange de pods dans le service utilisant un seul nom configuré, avec le même protocole réseau disponible via différents numéros de port.
Cela offre beaucoup de flexibilité pour déployer et faire évoluer vos services.
Par exemple, vous pouvez modifier les numéros de port que les pods exposent dans la prochaine version de votre logiciel principal, sans casser les clients.
Le protocole par défaut pour les services est TCP; vous pouvez également utiliser tout autre protocole pris en charge.
Comme de nombreux services doivent exposer plus d'un port, Kubernetes prend en charge plusieurs définitions de port sur un objet Service.
Chaque définition de port peut avoir le même protocole, ou un autre.
Services sans sélecteurs
Les services abritent le plus souvent l'accès aux pods Kubernetes, mais ils peuvent également abstraire d'autres types de backends.
Par exemple:
Vous voulez avoir un cluster de base de données externe en production, mais dans votre environnement de test, vous utilisez vos propres bases de données.
Vous souhaitez pointer votre service vers un service dans un autre Namespace ou sur un autre cluster.
Vous migrez une charge de travail vers Kubernetes.
Lors de l'évaluation de l'approche, vous exécutez uniquement une partie de vos backends dans Kubernetes.
Dans n'importe lequel de ces scénarios, vous pouvez définir un service sans un sélecteur de pod.
Par exemple:
Étant donné que ce service n'a pas de sélecteur, l'objet Endpoint correspondant n'est pas créé automatiquement.
Vous pouvez mapper manuellement le service à l'adresse réseau et au port où il s'exécute, en ajoutant manuellement un objet Endpoint:
Les IP de noeud final ne doivent pas être: loopback (127.0.0.0/8 pour IPv4, ::1/128 pour IPv6), ou link-local (169.254.0.0/16 et 224.0.0.0/24 pour IPv4, fe80::/64 pour IPv6).
Les adresses IP de noeud final ne peuvent pas être les adresses IP de cluster d'autres services Kubernetes, car kube-proxy ne prend pas en charge les adresses IP virtuelles en tant que destination.
L'accès à un service sans sélecteur fonctionne de la même manière que s'il avait un sélecteur.
Dans l'exemple ci-dessus, le trafic est routé vers le Endpoint unique défini dans le YAML: 192.0.2.42:9376 (TCP).
Un service ExternalName est un cas spécial de service qui n'a pas de sélecteurs et utilise des noms DNS à la place.
Pour plus d'informations, consultez la section ExternalName plus loin dans ce document.
Endpoint Slices
Feature state:Beta since Kubernetes v1.17
Un Endpoint Slices est une ressource API qui peut fournir une alternative plus évolutive au Endpoints.
Bien que conceptuellement assez similaire aux Endpoints, les Endpoint Slices permettent la distribution des endpoints réseau sur plusieurs ressources.
Par défaut, un Endpoint Slice est considéré comme "plein" une fois qu'il atteint 100 endpoints, au delà, des Endpoint Slices addtionnels seront crées pour stocker tout autre endpoints.
Les Endpoint Slices fournissent des attributs et des fonctionnalités supplémentaires qui sont décrits en détail dans Endpoint Slices.
IP virtuelles et proxy de service
Chaque nœud d'un cluster Kubernetes exécute un kube-proxy.
kube-proxy est responsable de l'implémentation d'une forme d'IP virtuelle pour les Services qui ne sont pas de type ExternalName.
Pourquoi ne pas utiliser le DNS round-robin ?
Une question qui apparaît de temps en temps est pourquoi Kubernetes s'appuie sur le proxy pour transférer le trafic entrant vers les backends.
Et les autres approches?
Par exemple, serait-il possible de configurer des enregistrements DNS qui ont plusieurs valeurs A (ou AAAA pour IPv6), et de s'appuyer sur la résolution de nom à tour de rôle (round-robin)?
Il existe plusieurs raisons d'utiliser le proxy pour les services:
Il existe une longue histoire d'implémentations DNS ne respectant pas les TTL d'enregistrement et mettant en cache les résultats des recherches de noms après leur expiration.
Certaines applications n'effectuent des recherches DNS qu'une seule fois et mettent en cache les résultats indéfiniment.
Même si les applications et les bibliothèques ont fait une bonne résolution, les TTL faibles ou nuls sur les enregistrements DNS pourraient imposer une charge élevée sur DNS qui devient alors difficile à gérer.
User space proxy mode
Dans ce mode, kube-proxy surveille le maître Kubernetes pour l'ajout et la suppression d'objets Service et Endpoint.
Pour chaque service, il ouvre un port (choisi au hasard) sur le nœud local.
Toutes les connexions à ce "port proxy" sont transmises par proxy à l'un des modules backend du service (comme indiqué via les Endpoints).
kube-proxy prend en compte le paramètre SessionAffinity du service pour décider quel pod backend utiliser.
Enfin, le proxy de l'espace utilisateur installe des règles iptables qui capturent le trafic vers le service clusterIP (qui est virtuel) et port.
Les règles redirigent ce trafic vers le port proxy qui fait office de proxy pour le Pod de backend.
Par défaut, kube-proxy en mode espace utilisateur choisit un backend via un algorithme round-robin.
iptables proxy mode
Dans ce mode, kube-proxy surveille le plan de contrôle Kubernetes pour l'ajout et la suppression d'objets Service et Endpoint.
Pour chaque service, il installe des règles iptables, qui capturent le trafic vers le «clusterIP» et le «port» du service, et redirigent ce trafic vers l'un des ensembles principaux du service.
Pour chaque objet Endpoint, il installe des règles iptables qui sélectionnent un Pod de backend.
Par défaut, kube-proxy en mode iptables choisit un backend au hasard.
L'utilisation d'iptables pour gérer le trafic a un coût système inférieur, car le trafic est géré par Linux netfilter sans avoir besoin de basculer entre l'espace utilisateur et l'espace noyau.
Cette approche est également susceptible d'être plus fiable.
Si kube-proxy s'exécute en mode iptables et que le premier pod sélectionné ne répond pas, la connexion échoue.
C'est différent du mode espace utilisateur: dans ce scénario, kube-proxy détecterait que la connexion au premier pod avait échoué et réessayerait automatiquement avec un pod backend différent.
Vous pouvez utiliser les readiness probes d'un Pod pour vérifier que les pods backend fonctionnent correctement, de sorte que kube-proxy en mode iptables ne voit que les backends testés comme sains.
Cela signifie que vous évitez d'envoyer du trafic via kube-proxy vers un pod connu pour avoir échoué.
IPVS proxy mode
Feature state:Stable since Kubernetes v1.11
En mode ipvs, kube-proxy surveille les Services et Endpoints Kubernetes. kube-proxy appelle l'interface netlink pour créer les règles IPVS en conséquence et synchronise périodiquement les règles IPVS avec les Services et Endpoints Kubernetes.
Cette boucle de contrôle garantit que l'état IPVS correspond à l'état souhaité.
Lors de l'accès à un service, IPVS dirige le trafic vers l'un des pods backend.
Le mode proxy IPVS est basé sur des fonctions hooks de netfilter qui est similaire au mode iptables, mais utilise la table de hachage comme structure de données sous-jacente et fonctionne dans l'espace du noyau.
Cela signifie que kube-proxy en mode IPVS redirige le trafic avec une latence plus faible que kube-proxy en mode iptables, avec de bien meilleures performances lors de la synchronisation des règles de proxy.
Par rapport aux autres modes proxy, le mode IPVS prend également en charge un débit plus élevé de trafic réseau.
IPVS offre plus d'options pour équilibrer le trafic vers les pods d'arrière-plan; ceux-ci sont:
rr: round-robin
lc: least connection (plus petit nombre de connexions ouvertes)
dh: destination hashing
sh: source hashing
sed: shortest expected delay
nq: never queue
Note:
Pour exécuter kube-proxy en mode IPVS, vous devez rendre IPVS Linux disponible sur le nœud avant de démarrer kube-proxy.
Lorsque kube-proxy démarre en mode proxy IPVS, il vérifie si les modules du noyau IPVS sont disponibles.
Si les modules du noyau IPVS ne sont pas détectés, alors kube-proxy revient à fonctionner en mode proxy iptables.
Dans ces modèles de proxy, le trafic lié à l'IP: Port du service est dirigé vers un backend approprié sans que les clients ne sachent quoi que ce soit sur Kubernetes, les services ou les pods.
Si vous souhaitez vous assurer que les connexions d'un client particulier sont transmises à chaque fois au même pod, vous pouvez sélectionner l'affinité de session en fonction des adresses IP du client en définissant service.spec.sessionAffinity sur" ClientIP "(la valeur par défaut est" None").
Vous pouvez également définir la durée maximale de session persistante en définissant service.spec.sessionAffinityConfig.clientIP.timeoutSeconds de manière appropriée (la valeur par défaut est 10800, ce qui correspond à 3 heures).
Services multi-ports
Pour certains services, vous devez exposer plusieurs ports.
Kubernetes vous permet de configurer plusieurs définitions de port sur un objet Service.
Lorsque vous utilisez plusieurs ports pour un service, vous devez donner tous vos noms de ports afin qu'ils ne soient pas ambigus.
Par exemple:
Comme pour tous les names Kubernetes en général, les noms de ports ne doivent contenir que des caractères alphanumériques en minuscules et -.
Les noms de port doivent également commencer et se terminer par un caractère alphanumérique.
Par exemple, les noms 123-abc et web sont valides, mais 123_abc et -web ne le sont pas.
Choisir sa propre adresse IP
Vous pouvez spécifier votre propre adresse IP de cluster dans le cadre d'une demande de création de Service.
Pour ce faire, définissez le champ .spec.clusterIP.
Par exemple, si vous avez déjà une entrée DNS existante que vous souhaitez réutiliser, ou des systèmes existants qui sont configurés pour une adresse IP spécifique et difficiles à reconfigurer.
L'adresse IP que vous choisissez doit être une adresse IPv4 ou IPv6 valide dans la plage CIDR service-cluster-ip-range configurée pour le serveur API.
Si vous essayez de créer un service avec une valeur d'adresse de clusterIP non valide, le serveur API retournera un code d'état HTTP 422 pour indiquer qu'il y a un problème.
Découvrir les services
Kubernetes prend en charge 2 modes principaux de recherche d'un service: les variables d'environnement et DNS.
Variables d'environnement
Lorsqu'un pod est exécuté sur un nœud, le kubelet ajoute un ensemble de variables d'environnement pour chaque service actif.
Il prend en charge à la fois les variables Docker links (voir makeLinkVariables) et plus simplement les variables {SVCNAME}_SERVICE_HOST et {SVCNAME}_SERVICE_PORT, où le nom du service est en majuscules et les tirets sont convertis en underscore.
Par exemple, le service redis-master qui expose le port TCP 6379 et a reçu l'adresse IP de cluster 10.0.0.11, produit les variables d'environnement suivantes:
Lorsque vous avez un pod qui doit accéder à un service et que vous utilisez la méthode des variables d'environnement pour publier le port et l'IP du cluster sur les pods clients, vous devez créer le service avant que les pods clients n'existent.
Sinon, ces pods clients n'auront pas leurs variables d'environnement remplies.
Si vous utilisez uniquement DNS pour découvrir l'IP du cluster pour un service, vous n'avez pas à vous soucier de ce problème de commande.
DNS
Vous pouvez (et devriez presque toujours) configurer un service DNS pour votre cluster Kubernetes à l'aide d'un add-on.
Un serveur DNS prenant en charge les clusters, tel que CoreDNS, surveille l'API Kubernetes pour les nouveaux services et crée un ensemble d'enregistrements DNS pour chacun.
Si le DNS a été activé dans votre cluster, tous les pods devraient automatiquement être en mesure de résoudre les services par leur nom DNS.
Par exemple, si vous avez un service appelé "my-service" dans un namespace Kubernetes "my-ns", le plan de contrôle et le service DNS agissant ensemble et créent un enregistrement DNS pour "my-service.my-ns".
Les Pods dans le Namespace "my-ns" devrait être en mesure de le trouver en faisant simplement une recherche de nom pour my-service ("my-service.my-ns" fonctionnerait également).
Les pods dans d'autres namespaces doivent utiliser le nom de my-service.my-ns.
Ces noms seront résolus en IP de cluster attribuée pour le service.
Kubernetes prend également en charge les enregistrements DNS SRV (Service) pour les ports nommés.
Si le service "my-service.my-ns" a un port nommé http avec un protocole défini sur TCP, vous pouvez effectuer une requête DNS SRV pour _http._tcp.my-service.my-ns pour découvrir le numéro de port de http, ainsi que l'adresse IP.
Le serveur DNS Kubernetes est le seul moyen d'accéder aux services ExternalName.
Vous pouvez trouver plus d'informations sur la résolution de ExternalName dans DNS Pods et Services.
Headless Services
Parfois, vous n'avez pas besoin de load-balancing et d'une seule IP de Service.
Dans ce cas, vous pouvez créer ce que l'on appelle des services "headless", en spécifiant explicitement "None" pour l'IP du cluster (.spec.clusterIP).
Vous pouvez utiliser un service headless pour interfacer avec d'autres mécanismes de découverte de service, sans être lié à l'implémentation de Kubernetes.
Pour les services headless, une IP de cluster n'est pas allouée, kube-proxy ne gère pas ces services et aucun load-balancing ou proxy n'est effectué par la plateforme pour eux.
La configuration automatique de DNS dépend de la définition ou non de sélecteurs par le service:
Avec sélecteurs
Pour les services headless qui définissent des sélecteurs, le controlleur des Endpoints crée des enregistrements Endpoints dans l'API, et modifie la configuration DNS pour renvoyer des enregistrements (adresses) qui pointent directement vers les Pods visés par le Service.
Sans sélecteurs
Pour les services headless qui ne définissent pas de sélecteurs, le contrôleur des Endpoints ne crée pas d'enregistrements Endpoints.
Cependant, le système DNS recherche et configure soit:
Enregistrements CNAME pour les services de type ExternalName.
Un enregistrement pour tous les «Endpoints» qui partagent un nom avec le Service, pour tous les autres types.
Services de publication (ServiceTypes)
Pour certaines parties de votre application (par exemple, les frontaux), vous souhaiterez peut-être exposer un service sur une adresse IP externe, qui est en dehors de votre cluster.
Les «ServiceTypes» de Kubernetes vous permettent de spécifier le type de service que vous souhaitez.
La valeur par défaut est «ClusterIP».
Les valeurs de Type et leurs comportements sont:
ClusterIP: Expose le service sur une IP interne au cluster.
Le choix de cette valeur rend le service uniquement accessible à partir du cluster.
Il s'agit du ServiceType par défaut.
NodePort: Expose le service sur l'IP de chaque nœud sur un port statique (le NodePort).
Un service ClusterIP, vers lequel le service NodePort est automatiquement créé.
Vous pourrez contacter le service NodePort, depuis l'extérieur du cluster, en demandant <NodeIP>: <NodePort>.
LoadBalancer: Expose le service en externe à l'aide de l'équilibreur de charge d'un fournisseur de cloud.
Les services NodePort et ClusterIP, vers lesquels les itinéraires de l'équilibreur de charge externe, sont automatiquement créés.
ExternalName: Mappe le service au contenu du champ externalName (par exemple foo.bar.example.com), en renvoyant un enregistrement CNAME avec sa valeur.
Aucun proxy d'aucune sorte n'est mis en place.
Note:
Vous avez besoin de CoreDNS version 1.7 ou supérieure pour utiliser le type `ExternalName`.
Vous pouvez également utiliser Ingress pour exposer votre service.
Ingress n'est pas un type de service, mais il sert de point d'entrée pour votre cluster.
Il vous permet de consolider vos règles de routage en une seule ressource car il peut exposer plusieurs services sous la même adresse IP.
Type NodePort
Si vous définissez le champ type sur NodePort, le plan de contrôle Kubernetes alloue un port à partir d'une plage spécifiée par l'indicateur --service-node-port-range (par défaut: 30000-32767).
Chaque nœud assure le proxy de ce port (le même numéro de port sur chaque nœud) vers votre service.
Votre service signale le port alloué dans son champ .spec.ports[*].nodePort.
Si vous souhaitez spécifier une ou des adresses IP particulières pour proxyfier le port, vous pouvez définir l'indicateur --nodeport-addresses dans kube-proxy sur des blocs IP particuliers; cela est pris en charge depuis Kubernetes v1.10.
Cet indicateur prend une liste délimitée par des virgules de blocs IP (par exemple 10.0.0.0/8, 192.0.2.0/25) pour spécifier les plages d'adresses IP que kube-proxy doit considérer comme locales pour ce nœud.
Par exemple, si vous démarrez kube-proxy avec l'indicateur --nodeport-addresses=127.0.0.0/8, kube-proxy sélectionne uniquement l'interface de boucle locale pour les services NodePort.
La valeur par défaut pour --nodeport-addresses est une liste vide.
Cela signifie que kube-proxy doit prendre en compte toutes les interfaces réseau disponibles pour NodePort (qui est également compatible avec les versions antérieures de Kubernetes).
Si vous voulez un numéro de port spécifique, vous pouvez spécifier une valeur dans le champ nodePort.
Le plan de contrôle vous attribuera ce port ou signalera l'échec de la transaction API.
Cela signifie que vous devez vous occuper vous-même des éventuelles collisions de ports.
Vous devez également utiliser un numéro de port valide, celui qui se trouve dans la plage configurée pour l'utilisation de NodePort.
L'utilisation d'un NodePort vous donne la liberté de configurer votre propre solution d'équilibrage de charge, de configurer des environnements qui ne sont pas entièrement pris en charge par Kubernetes, ou même d'exposer directement les adresses IP d'un ou plusieurs nœuds.
Notez que ce service est visible en tant que <NodeIP>: spec.ports[*].nodePort et .spec.clusterIP: spec.ports[*].Port.
(Si l'indicateur --nodeport-addresses dans kube-proxy est défini, serait filtré NodeIP(s).)
Type LoadBalancer
Sur les fournisseurs de cloud qui prennent en charge les load balancers externes, la définition du champ type sur LoadBalancer provisionne un load balancer pour votre service.
La création réelle du load balancer se produit de manière asynchrone et les informations sur le load balancer provisionné sont publiées dans le champ .status.loadBalancer.
Par exemple:
Le trafic provenant du load balancer externe est dirigé vers les Pods backend.
Le fournisseur de cloud décide de la répartition de la charge.
Certains fournisseurs de cloud vous permettent de spécifier le loadBalancerIP.
Dans ces cas, le load balancer est créé avec le loadBalancerIP spécifié par l'utilisateur.
Si le champ loadBalancerIP n'est pas spécifié, le loadBalancer est configuré avec une adresse IP éphémère.
Si vous spécifiez un loadBalancerIP mais que votre fournisseur de cloud ne prend pas en charge la fonctionnalité, le champ loadBalancerIP que vous définissez est ignoré.
Note:
Si vous utilisez SCTP, voir le caveat ci-dessous sur le type de service LoadBalancer.
Note:
Sur Azure, si vous souhaitez utiliser un type public spécifié par l'utilisateur loadBalancerIP, vous devez d'abord créer une ressource d'adresse IP publique de type statique.
Cette ressource d'adresse IP publique doit se trouver dans le même groupe de ressources que les autres ressources créées automatiquement du cluster.
Par exemple, MC_myResourceGroup_myAKSCluster_eastus.
Dans un environnement mixte, il est parfois nécessaire d'acheminer le trafic des services à l'intérieur du même bloc d'adresse réseau (virtuel).
Dans un environnement DNS à horizon divisé, vous auriez besoin de deux services pour pouvoir acheminer le trafic externe et interne vers vos endpoints.
Vous pouvez y parvenir en ajoutant une des annotations suivantes à un service.
L'annotation à ajouter dépend du fournisseur de services cloud que vous utilisez.
Le premier spécifie l'ARN du certificat à utiliser.
Il peut s'agir soit d'un certificat d'un émetteur tiers qui a été téléchargé sur IAM, soit d'un certificat créé dans AWS Certificate Manager.
La deuxième annotation spécifie le protocole utilisé par un pod.
Pour HTTPS et SSL, l'ELB s'attend à ce que le pod s'authentifie sur la connexion chiffrée, à l'aide d'un certificat.
HTTP et HTTPS sélectionnent le proxy de couche 7: l'ELB met fin à la connexion avec l'utilisateur, analyse les en-têtes et injecte l'en-tête X-Forwarded-For avec l'adresse IP de l'utilisateur (les pods ne voient que l'adresse IP de l'ELB à l'autre extrémité de sa connexion) lors du transfert des demandes.
TCP et SSL sélectionnent le proxy de couche 4: l'ELB transfère le trafic sans modifier les en-têtes.
Dans un environnement à usage mixte où certains ports sont sécurisés et d'autres non chiffrés, vous pouvez utiliser les annotations suivantes:
Dans l'exemple ci-dessus, si le service contenait trois ports, «80», «443» et «8443», alors «443» et «8443» utiliseraient le certificat SSL, mais «80» serait simplement un proxy HTTP.
A partir de Kubernetes v1.9, vous pouvez utiliser des stratégies SSL AWS prédéfinies avec des écouteurs HTTPS ou SSL pour vos services.
Pour voir quelles politiques sont disponibles, vous pouvez utiliser l'outil de ligne de commande aws:
Vous pouvez ensuite spécifier l'une de ces stratégies à l'aide de l'annotation "service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy"; par exemple:
Depuis la version 1.3.0, l'utilisation de cette annotation s'applique à tous les ports mandatés par l'ELB et ne peut pas être configurée autrement.
Journaux d'accès ELB sur AWS
Il existe plusieurs annotations pour gérer les journaux d'accès aux services ELB sur AWS.
L'annotation service.beta.kubernetes.io/aws-load-balancer-access-log-enabled contrôle si les journaux d'accès sont activés.
L'annotation service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval contrôle l'intervalle en minutes pour la publication des journaux d'accès.
Vous pouvez spécifier un intervalle de 5 ou 60 minutes.
L'annotation service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name contrôle le nom du bucket Amazon S3 où les journaux d'accès au load balancer sont stockés.
L'annotation service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix spécifie la hiérarchie logique que vous avez créée pour votre bucket Amazon S3.
metadata:name:my-serviceannotations:service.beta.kubernetes.io/aws-load-balancer-access-log-enabled:"true"# Spécifie si les journaux d'accès sont activés pour le load balancerservice.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval:"60"# L'intervalle de publication des journaux d'accès.# Vous pouvez spécifier un intervalle de 5 ou 60 (minutes).service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name:"my-bucket"# Le nom du bucket Amazon S3 où les journaux d'accès sont stockésservice.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix:"my-bucket-prefix/prod"# La hiérarchie logique que vous avez créée pour votre bucket Amazon S3, par exemple `my-bucket-prefix/prod`
Drainage de connexion sur AWS
Le drainage des connexions pour les ELB classiques peut être géré avec l'annotation service.beta.kubernetes.io / aws-load-balancer-connection-draining-enabled définie sur la valeur true.
L'annotation service.beta.kubernetes.io / aws-load-balancer-connection-draining-timeout peut également être utilisée pour définir la durée maximale, en secondes, pour garder les connexions existantes ouvertes avant de désenregistrer les instances.
Il existe d'autres annotations pour gérer les Elastic Load Balancers décrits ci-dessous.
metadata:name:my-serviceannotations:service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout:"60"# Délai, en secondes, pendant lequel la connexion peut être inactive (aucune donnée n'a été envoyée via la connexion) avant d'être fermée par le load balancerservice.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled:"true"# Spécifie si le load balancing inter-zones est activé pour le load balancerservice.beta.kubernetes.io/aws-load-balancer-additional-resource-tags:"environment=prod,owner=devops"# Une liste de paires clé-valeur séparées par des virgules qui seront enregistrées en tant que balises supplémentaires dans l'ELB.service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold:""# Nombre de contrôles de santé successifs réussis requis pour qu'un backend soit considéré comme sain pour le trafic.# La valeur par défaut est 2, doit être comprise entre 2 et 10service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold:"3"# Nombre de contrôles de santé infructueux requis pour qu'un backend soit considéré comme inapte pour le trafic.# La valeur par défaut est 6, doit être comprise entre 2 et 10service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval:"20"# Intervalle approximatif, en secondes, entre les contrôles d'intégrité d'une instance individuelle.# La valeur par défaut est 10, doit être comprise entre 5 et 300service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout:"5"# Durée, en secondes, pendant laquelle aucune réponse ne signifie l'échec d'un contrôle de santé.# Cette valeur doit être inférieure à la valeur service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval.# La valeur par défaut est 5, doit être comprise entre 2 et 60service.beta.kubernetes.io/aws-load-balancer-extra-security-groups:"sg-53fae93f,sg-42efd82e"# Une liste de groupes de sécurité supplémentaires à ajouter à l'ELB
Prise en charge du load balancer réseau sur AWS
Feature state:Beta since Kubernetes v1.15
Pour utiliser un load balancer réseau sur AWS, utilisez l'annotation service.beta.kubernetes.io/aws-load-balancer-type avec la valeur définie sur nlb.
NLB ne fonctionne qu'avec certaines classes d'instance; voir la documentation AWS sur Elastic Load Balancing pour une liste des types d'instances pris en charge.
Contrairement aux équilibreurs de charge élastiques classiques, les équilibreurs de charge réseau (NLB) transfèrent l'adresse IP du client jusqu'au nœud.
Si un service est .spec.externalTrafficPolicy est réglé sur Cluster, l'adresse IP du client n'est pas propagée aux pods finaux.
En définissant .spec.externalTrafficPolicy à Local, les adresses IP des clients sont propagées aux pods finaux, mais cela peut entraîner une répartition inégale du trafic.
Les nœuds sans pods pour un service LoadBalancer particulier échoueront au contrôle de santé du groupe cible NLB sur le .spec.healthCheckNodePort attribué automatiquement et ne recevront aucun trafic.
Pour obtenir un trafic uniforme, utilisez un DaemonSet ou spécifiez un pod anti-affinity pour ne pas localiser sur le même noeud.
Vous pouvez également utiliser les services NLB avec l'annotation load balancer internal.
Pour que le trafic client atteigne des instances derrière un NLB, les groupes de sécurité du nœud sont modifiés avec les règles IP suivantes:
Rule
Protocol
Port(s)
IpRange(s)
IpRange Description
Health Check
TCP
NodePort(s) (.spec.healthCheckNodePort for .spec.externalTrafficPolicy = Local)
VPC CIDR
kubernetes.io/rule/nlb/health=<loadBalancerName>
Client Traffic
TCP
NodePort(s)
.spec.loadBalancerSourceRanges (defaults to 0.0.0.0/0)
kubernetes.io/rule/nlb/client=<loadBalancerName>
MTU Discovery
ICMP
3,4
.spec.loadBalancerSourceRanges (defaults to 0.0.0.0/0)
kubernetes.io/rule/nlb/mtu=<loadBalancerName>
Afin de limiter les IP clientes pouvant accéder à l'équilibreur de charge réseau, spécifiez loadBalancerSourceRanges.
spec:loadBalancerSourceRanges:- "143.231.0.0/16"
Note:
Si .spec.loadBalancerSourceRanges n'est pas défini, Kubernetes autorise le trafic de 0.0.0.0/0 vers les groupes de sécurité des nœuds.
Si les nœuds ont des adresses IP publiques, sachez que le trafic non NLB peut également atteindre toutes les instances de ces groupes de sécurité modifiés.
Autres annotations CLB sur Tencent Kubernetes Engine (TKE)
Il existe d'autres annotations pour la gestion des équilibreurs de charge cloud sur TKE, comme indiqué ci-dessous.
metadata:name:my-serviceannotations:# Lier des load balancers avec des nœuds spécifiquesservice.kubernetes.io/qcloud-loadbalancer-backends-label:key in (value1, value2)# ID d'un load balancer existantservice.kubernetes.io/tke-existed-lbid:lb-6swtxxxx# Paramètres personnalisés pour le load balancer (LB), ne prend pas encore en charge la modification du type LBservice.kubernetes.io/service.extensiveParameters:""# Paramètres personnalisés pour le listener LBservice.kubernetes.io/service.listenerParameters:""# Spécifie le type de Load balancer;# valeurs valides: classic (Classic Cloud Load Balancer) ou application (Application Cloud Load Balancer)service.kubernetes.io/loadbalance-type:xxxxx# Spécifie la méthode de facturation de la bande passante du réseau public;# valid values: TRAFFIC_POSTPAID_BY_HOUR(bill-by-traffic) and BANDWIDTH_POSTPAID_BY_HOUR (bill-by-bandwidth).service.kubernetes.io/qcloud-loadbalancer-internet-charge-type:xxxxxx# Spécifie la valeur de bande passante (plage de valeurs: [1,2000] Mbps).service.kubernetes.io/qcloud-loadbalancer-internet-max-bandwidth-out:"10"# Lorsque cette annotation est définie, les équilibreurs de charge n'enregistrent que les nœuds sur lesquels le pod s'exécute, sinon tous les nœuds seront enregistrés.service.kubernetes.io/local-svc-only-bind-node-with-pod:true
Type ExternalName
Les services de type ExternalName mappent un service à un nom DNS, et non à un sélecteur standard tel que my-service ou cassandra.
Vous spécifiez ces services avec le paramètre spec.externalName.
Cette définition de service, par exemple, mappe le service my-service dans l'espace de noms prod à my.database.example.com:
ExternalName accepte une chaîne d'adresse IPv4, mais en tant que noms DNS composés de chiffres, et non en tant qu'adresse IP.
Les noms externes qui ressemblent aux adresses IPv4 ne sont pas résolus par CoreDNS ou ingress-nginx car ExternalName est destiné à spécifier un nom DNS canonique.
Pour coder en dur une adresse IP, pensez à utiliser des Services headless.
Lors de la recherche de l'hôte my-service.prod.svc.cluster.local, le service DNS du cluster renvoie un enregistrement CNAME avec la valeur my.database.example.com.
L'accès à «mon-service» fonctionne de la même manière que les autres services, mais avec la différence cruciale que la redirection se produit au niveau DNS plutôt que via un proxy ou un transfert.
Si vous décidez ultérieurement de déplacer votre base de données dans votre cluster, vous pouvez démarrer ses pods, ajouter des sélecteurs ou des Endpoints appropriés et modifier le type du service.
Attention:
Vous pouvez rencontrer des difficultés à utiliser ExternalName pour certains protocoles courants, notamment HTTP et HTTPS.
Si vous utilisez ExternalName, le nom d'hôte utilisé par les clients à l'intérieur de votre cluster est différent du nom référencé par ExternalName.
Pour les protocoles qui utilisent des noms d'hôtes, cette différence peut entraîner des erreurs ou des réponses inattendues.
Les requêtes HTTP auront un en-tête Host: que le serveur d'origine ne reconnaît pas; Les serveurs TLS ne pourront pas fournir de certificat correspondant au nom d'hôte auquel le client s'est connecté.
S'il existe des adresses IP externes qui acheminent vers un ou plusieurs nœuds de cluster, les services Kubernetes peuvent être exposés sur ces "IP externes".
Le trafic qui pénètre dans le cluster avec l'IP externe (en tant qu'IP de destination), sur le port de service, sera routé vers l'un des Endpoints de service.
Les externalIPs ne sont pas gérées par Kubernetes et relèvent de la responsabilité de l'administrateur du cluster.
Dans la spécification de service, «externalIPs» peut être spécifié avec n'importe lequel des «ServiceTypes».
Dans l'exemple ci-dessous, "my-service" peut être consulté par les clients sur "198.51.100.32:80" (externalIP:port)
Le proxy fonctionnant dans l'espace utilisateur pour les VIP peut fonctionner à petite ou moyenne échelle, mais montrera ses limites dans de très grands clusters avec des milliers de services.
La proposition de conception originale pour les portails a plus de détails à ce sujet.
L'utilisation du proxy de l'espace utilisateur masque l'adresse IP source d'un paquet accédant à un service.
Cela rend certains types de filtrage réseau (pare-feu) impossibles.
Le mode proxy iptables n'obscurcit pas les adresses IP source dans le cluster, mais il affecte toujours les clients passant par un LoadBalancer ou un NodePort.
Le champ Type est conçu comme une fonctionnalité imbriquée - chaque niveau s'ajoute au précédent.
Cela n'est pas strictement requis sur tous les fournisseurs de cloud (par exemple, Google Compute Engine n'a pas besoin d'allouer un NodePort pour faire fonctionner LoadBalancer, mais AWS le fait) mais l'API actuelle le requiert.
Implémentation IP virtuelle
Les informations précédentes devraient être suffisantes pour de nombreuses personnes qui souhaitent simplement utiliser les Services.
Cependant, il se passe beaucoup de choses dans les coulisses qui méritent d'être comprises.
Éviter les collisions
L'une des principales philosophies de Kubernetes est que vous ne devez pas être exposé à des situations qui pourraient entraîner l'échec de vos actions sans aucune faute de votre part.
Pour la conception de la ressource Service, cela signifie de ne pas vous faire choisir votre propre numéro de port si ce choix pourrait entrer en collision avec le choix de quelqu'un d'autre.
C'est un échec d'isolement.
Afin de vous permettre de choisir un numéro de port pour vos Services, nous devons nous assurer qu'aucun deux Services ne peuvent entrer en collision.
Kubernetes le fait en attribuant à chaque service sa propre adresse IP.
Pour garantir que chaque service reçoit une adresse IP unique, un allocateur interne met à jour atomiquement une carte d'allocation globale dans etcd avant de créer chaque service.
L'objet de mappage doit exister dans le registre pour que les services obtiennent des affectations d'adresse IP, sinon les créations échoueront avec un message indiquant qu'une adresse IP n'a pas pu être allouée.
Dans le plan de contrôle, un contrôleur d'arrière-plan est responsable de la création de cette carte (nécessaire pour prendre en charge la migration à partir d'anciennes versions de Kubernetes qui utilisaient le verrouillage en mémoire).
Kubernetes utilise également des contrôleurs pour vérifier les affectations non valides (par exemple en raison d'une intervention de l'administrateur) et pour nettoyer les adresses IP allouées qui ne sont plus utilisées par aucun service.
Service IP addresses
Contrairement aux adresses IP des pods, qui acheminent réellement vers une destination fixe, les adresses IP des services ne sont pas réellement répondues par un seul hôte.
Au lieu de cela, kube-proxy utilise iptables (logique de traitement des paquets sous Linux) pour définir les adresses IP virtual qui sont redirigées de manière transparente selon les besoins.
Lorsque les clients se connectent au VIP, leur trafic est automatiquement transporté vers un Endpoint approprié.
Les variables d'environnement et DNS pour les services sont en fait remplis en termes d'adresse IP virtuelle (et de port) du service.
kube-proxy prend en charge trois modes proxy — espace utilisateur, iptables et IPVS — qui fonctionnent chacun légèrement différemment.
Userspace
À titre d'exemple, considérons l'application de traitement d'image décrite ci-dessus.
Lorsque le service backend est créé, le maître Kubernetes attribue une adresse IP virtuelle, par exemple 10.0.0.1.
En supposant que le port de service est 1234, le service est observé par toutes les instances kube-proxy dans le cluster.
Lorsqu'un proxy voit un nouveau service, il ouvre un nouveau port aléatoire, établit une redirection iptables de l'adresse IP virtuelle vers ce nouveau port et commence à accepter les connexions sur celui-ci.
Lorsqu'un client se connecte à l'adresse IP virtuelle du service, la règle iptables entre en jeu et redirige les paquets vers le propre port du proxy.
Le “Service proxy” choisit un backend, et commence le proxy du trafic du client vers le backend.
Cela signifie que les propriétaires de services peuvent choisir le port de leur choix sans risque de collision.
Les clients peuvent simplement se connecter à une adresse IP et à un port, sans savoir à quels pods ils accèdent réellement.
iptables
Considérons à nouveau l'application de traitement d'image décrite ci-dessus.
Lorsque le service backend est créé, le plan de contrôle Kubernetes attribue une adresse IP virtuelle, par exemple 10.0.0.1.
En supposant que le port de service est 1234, le service est observé par toutes les instances de kube-proxy dans le cluster.
Lorsqu'un proxy voit un nouveau service, il installe une série de règles iptables qui redirigent de l'adresse IP virtuelle vers des règles par service.
Les règles par service sont liées aux règles des Endpoints qui redirigent le trafic (à l'aide du NAT de destination) vers les backends.
Lorsqu'un client se connecte à l'adresse IP virtuelle du service, la règle iptables entre en jeu.
Un backend est choisi (soit en fonction de l'affinité de la session, soit au hasard) et les paquets sont redirigés vers le backend.
Contrairement au proxy de l'espace utilisateur, les paquets ne sont jamais copiés dans l'espace utilisateur, le proxy de kube n'a pas besoin d'être exécuté pour que l'adresse IP virtuelle fonctionne et les nœuds voient le trafic provenant de l'adresse IP du client non modifiée.
Ce même flux de base s'exécute lorsque le trafic arrive via un port de nœud ou via un load balancer, bien que dans ces cas, l'adresse IP du client soit modifiée.
IPVS
Les opérations iptables ralentissent considérablement dans un cluster à grande échelle, par exemple 10000 services.
IPVS est conçu pour l'équilibrage de charge et basé sur des tables de hachage dans le noyau.
Ainsi, vous pouvez obtenir une cohérence des performances dans un grand nombre de services à partir d'un kube-proxy basé sur IPVS.
De plus, kube-proxy basé sur IPVS a des algorithmes d'équilibrage de charge plus sophistiqués (le moins de connexions, localité, pondéré, persistance).
Objet API
Le service est une ressource de niveau supérieur dans l'API REST Kubernetes.
Vous pouvez trouver plus de détails sur l'objet API sur: Service API object.
Protocoles pris en charge
TCP
Feature state:Stable since Kubernetes v1.0
Vous pouvez utiliser TCP pour tout type de service, et c'est le protocole réseau par défaut.
UDP
Feature state:Stable since Kubernetes v1.0
Vous pouvez utiliser UDP pour la plupart des services.
Pour Services de type LoadBalancer, la prise en charge UDP dépend du fournisseur de cloud offrant cette fonctionnalité.
HTTP
Feature state:Stable since Kubernetes v1.1
Si votre fournisseur de cloud le prend en charge, vous pouvez utiliser un service dans le mode LoadBalancer pour configurer le proxy inverse HTTP / HTTPS externe, transmis au Endpoints du Service.
Note:
Vous pouvez aussi utiliser Ingress à la place du service pour exposer les services HTTP/HTTPS.
Protocole PROXY
Feature state:Stable since Kubernetes v1.1
Si votre fournisseur de cloud le prend en charge(eg, AWS), vous pouvez utiliser un service en mode LoadBalancer pour configurer un load balancer en dehors de Kubernetes lui-même, qui transmettra les connexions préfixées par PROXY protocol.
Le load balancer enverra une première série d'octets décrivant la connexion entrante, similaire à cet exemple
PROXY TCP4 192.0.2.202 10.0.42.7 12345 7\r\n
suivi des données du client.
SCTP
Feature state:Alpha since Kubernetes v1.12
Kubernetes prend en charge SCTP en tant que valeur de «protocole» dans les définitions de Service, Endpoint, NetworkPolicy et Pod en tant que fonctionnalité alpha.
Pour activer cette fonction, l'administrateur du cluster doit activer le flag SCTPSupport sur l'apiserver, par exemple, --feature-gates=SCTPSupport=true,….
When the feature gate is enabled, you can set the protocol field of a Service, Endpoint, NetworkPolicy or Pod to SCTP.
Kubernetes sets up the network accordingly for the SCTP associations, just like it does for TCP connections.
Avertissements
Prise en charge des associations SCTP multi-hôtes
Attention:
La prise en charge des associations SCTP multi-hôtes nécessite que le plug-in CNI puisse prendre en charge l'attribution de plusieurs interfaces et adresses IP à un pod.
Le NAT pour les associations SCTP multi-hôtes nécessite une logique spéciale dans les modules de noyau correspondants.
Service avec type=LoadBalancer
Attention:
Vous ne pouvez créer un service de type LoadBalancer avec SCTP que si le fournisseur de load balancer supporte SCTP comme protocole.
Sinon, la demande de création de service est rejetée.
L'ensemble actuel de fournisseurs de load balancer cloud (Azure, AWS, CloudStack, GCE, OpenStack) ne prennent pas en charge SCTP.
Windows
Attention:
SCTP n'est pas pris en charge sur les nœuds Windows.
Userspace kube-proxy
Attention:
Le kube-proxy ne prend pas en charge la gestion des associations SCTP lorsqu'il est en mode userspace.
Futurs développements
À l'avenir, la stratégie de proxy pour les services peut devenir plus nuancée que le simple équilibrage alterné, par exemple master-elected ou sharded.
Nous prévoyons également que certains services auront des load balancer «réels», auquel cas l'adresse IP virtuelle y transportera simplement les paquets.
Le projet Kubernetes vise à améliorer la prise en charge des services L7 (HTTP).
Le projet Kubernetes prévoit d'avoir des modes d'entrée plus flexibles pour les services, qui englobent les modes ClusterIP, NodePort et LoadBalancer actuels et plus encore.
Rendez votre service réseau HTTP (ou HTTPS) accessible grâce à un mécanisme de configuration sensible au protocole et comprend les concepts du web comme les URI, les noms d'hôte, les chemins, etc. Le concept d'Ingress vous permet d'acheminer le trafic vers différents backends selon des règles que vous définissez via l'API Kubernetes.
Feature state:Stable since Kubernetes v1.19
Un objet API qui gère l'accès externe aux services d'un cluster, typiquement HTTP.
L'Ingress peut fournir un équilibrage de charge, une terminaison SSL ainsi qu'un hébergement virtuel basé sur un nom.
Note:
Le projet Kubernetes recommande d'utiliser Gateway plutôt
qu'Ingress.
L'API Ingress est figée.
Cela signifie que :
L'API Ingress est en disponibilité générale (GA) et soumise aux garanties de stabilité prévues pour les API GA.
Le projet Kubernetes n'a pas l'intention de retirer Ingress de Kubernetes.
L'API Ingress n'est plus développée et ne recevra plus aucune modification
ni mise à jour.
Terminologie
Par souci de clarté, ce guide définit les termes suivants :
Nœud (Node) : une machine de travail de Kubernetes, qui fait partie d'un cluster.
Cluster : un ensemble de nœuds qui exécutent des applications conteneurisées gérées par Kubernetes.
Dans cet exemple, comme dans la plupart des déploiements Kubernetes courants, les nœuds du cluster
ne sont pas exposés sur l'Internet public.
Routeur de bordure (edge router) : un routeur qui applique la politique de pare-feu de votre cluster.
Il peut s'agir d'une passerelle gérée par un fournisseur de cloud ou d'un équipement physique.
Réseau du cluster : un ensemble de liens, logiques ou physiques, qui permettent la communication
au sein d'un cluster selon le modèle réseau de Kubernetes.
Service : un Service Kubernetes qui identifie
un ensemble de Pods à l'aide de sélecteurs de labels.
Sauf mention contraire, on suppose que les Services ont des adresses IP virtuelles routables uniquement dans le réseau du cluster.
Qu'est-ce qu'un Ingress ?
Un Ingress
expose des routes HTTP et HTTPS depuis l'extérieur du cluster vers des
services du cluster.
Le routage du trafic est contrôlé par des règles définies sur la ressource Ingress.
Voici un exemple simple dans lequel un Ingress envoie tout son trafic vers un seul Service :
Figure. Ingress
Un Ingress peut être configuré pour donner aux Services des URL accessibles de l'extérieur,
équilibrer la charge du trafic, assurer la terminaison SSL / TLS et proposer un hébergement virtuel basé sur le nom.
Un contrôleur d'Ingress
est chargé de mettre en œuvre l'Ingress, généralement avec un équilibreur de charge (load balancer),
mais il peut aussi configurer votre routeur de bordure ou des frontaux supplémentaires pour aider à gérer le trafic.
Un Ingress n'expose pas de ports ni de protocoles arbitraires. Pour exposer à Internet des services autres que HTTP et HTTPS,
on utilise généralement un Service de type Service.Type=NodePort ou
Service.Type=LoadBalancer.
Prérequis
Vous devez disposer d'un contrôleur d'Ingress
pour qu'un Ingress soit pris en compte. La simple création d'une ressource Ingress n'a aucun effet.
Idéalement, tous les contrôleurs d'Ingress devraient respecter la spécification de référence. En pratique,
les différents contrôleurs d'Ingress fonctionnent de manière légèrement différente.
Note:
Consultez bien la documentation de votre contrôleur d'Ingress pour connaître les limites à prendre en compte avant de le choisir.
Un Ingress a besoin des champs apiVersion, kind, metadata et spec.
Le nom d'un objet Ingress doit être un
nom de sous-domaine DNS valide.
Pour des informations générales sur l'utilisation des fichiers de configuration, consultez
déployer des applications,
configurer des conteneurs et
gérer des ressources.
Les contrôleurs d'Ingress utilisent souvent des annotations pour configurer leur comportement.
Consultez la documentation du contrôleur d'Ingress que vous avez choisi pour savoir quelles annotations sont attendues ou prises en charge.
La spec de l'Ingress
contient toutes les informations nécessaires pour configurer un équilibreur de charge ou un serveur proxy. Elle contient
surtout une liste de règles comparées à toutes les requêtes entrantes. La ressource Ingress ne prend en charge
que des règles pour diriger du trafic HTTP(S).
Certains contrôleurs d'Ingress fonctionnent même sans définition
d'une IngressClass par défaut. Même si vous utilisez un contrôleur d'Ingress capable
de fonctionner sans IngressClass, le projet Kubernetes recommande tout de même
de définir une IngressClass par défaut.
Règles d'Ingress
Chaque règle HTTP contient les informations suivantes :
Un hôte facultatif. Dans cet exemple, aucun hôte n'est indiqué : la règle s'applique donc à tout
le trafic HTTP entrant par l'adresse IP indiquée. Si un hôte est fourni (par exemple
foo.bar.com), les règles s'appliquent à cet hôte.
Une liste de chemins (par exemple /testpath), chacun associé à un
backend défini par un service.name et un service.port.name ou un
service.port.number. L'hôte et le chemin doivent tous deux correspondre au contenu
d'une requête entrante pour que l'équilibreur de charge dirige le trafic vers le
Service référencé.
Un backend est une combinaison d'un nom de Service et d'un port, comme décrit dans la
documentation des Services, ou un backend de ressource personnalisée
défini au moyen d'une CRD. Les requêtes HTTP (et HTTPS) adressées à
l'Ingress qui correspondent à l'hôte et au chemin de la règle sont envoyées au backend indiqué.
Un defaultBackend est souvent configuré dans un contrôleur d'Ingress pour traiter toutes les requêtes
qui ne correspondent à aucun chemin de la spec.
DefaultBackend
Un Ingress sans règles envoie tout le trafic vers un unique backend par défaut, et .spec.defaultBackend
est le backend qui doit traiter les requêtes dans ce cas.
Le defaultBackend est habituellement une option de configuration du
contrôleur d'Ingress et
n'est pas indiqué dans vos ressources Ingress.
Si .spec.rules n'est pas défini, .spec.defaultBackend doit l'être.
Si defaultBackend n'est pas défini, c'est le contrôleur d'Ingress qui décide du traitement des requêtes
qui ne correspondent à aucune règle (consultez la documentation de votre contrôleur d'Ingress pour savoir comment il gère ce cas).
Si aucun des hôtes ou chemins des objets Ingress ne correspond à la requête HTTP, le trafic est
acheminé vers votre backend par défaut.
Backends de ressource
Un backend Resource est une référence (ObjectRef) vers une autre ressource Kubernetes du
même namespace que l'objet Ingress. Resource et Service s'excluent mutuellement :
la validation échoue si les deux sont indiqués. Un backend Resource sert
couramment à faire entrer des données dans un backend de stockage objet
contenant des ressources statiques.
Chaque chemin d'un Ingress doit avoir un type de chemin correspondant. Les chemins
sans pathType explicite échouent à la validation. Trois types de chemins
sont pris en charge :
ImplementationSpecific : avec ce type de chemin, la correspondance dépend de
l'IngressClass. Les implémentations peuvent le traiter comme un pathType distinct ou
de la même manière que les types de chemins Prefix ou Exact.
Exact : correspond exactement au chemin de l'URL, en tenant compte de la casse.
Prefix : correspond selon un préfixe du chemin de l'URL découpé par /. La correspondance
tient compte de la casse et se fait élément par élément. Un élément de chemin désigne
la liste des libellés du chemin découpé par le séparateur /. Une requête correspond
au chemin p si chaque p est un préfixe, élément par élément, de p dans le
chemin de la requête.
Note:
Si le dernier élément du chemin est une sous-chaîne du dernier
élément du chemin de la requête, il n'y a pas de correspondance (par exemple, /foo/bar
correspond à /foo/bar/baz, mais pas à /foo/barbaz).
Exemples
Type
Chemin(s)
Chemin(s) de la requête
Correspondance ?
Prefix
/
(tous les chemins)
Oui
Exact
/foo
/foo
Oui
Exact
/foo
/bar
Non
Exact
/foo
/foo/
Non
Exact
/foo/
/foo
Non
Prefix
/foo
/foo, /foo/
Oui
Prefix
/foo/
/foo, /foo/
Oui
Prefix
/aaa/bb
/aaa/bbb
Non
Prefix
/aaa/bbb
/aaa/bbb
Oui
Prefix
/aaa/bbb/
/aaa/bbb
Oui, ignore la barre oblique finale
Prefix
/aaa/bbb
/aaa/bbb/
Oui, correspond avec la barre oblique finale
Prefix
/aaa/bbb
/aaa/bbb/ccc
Oui, correspond au sous-chemin
Prefix
/aaa/bbb
/aaa/bbbxyz
Non, ne correspond pas au préfixe de chaîne
Prefix
/, /aaa
/aaa/ccc
Oui, correspond au préfixe /aaa
Prefix
/, /aaa, /aaa/bbb
/aaa/bbb
Oui, correspond au préfixe /aaa/bbb
Prefix
/, /aaa, /aaa/bbb
/ccc
Oui, correspond au préfixe /
Prefix
/aaa
/ccc
Non, utilise le backend par défaut
Mixte
/foo (Prefix), /foo (Exact)
/foo
Oui, préfère Exact
Correspondances multiples
Dans certains cas, plusieurs chemins d'un Ingress correspondent à une requête. La priorité
est alors donnée au chemin correspondant le plus long. Si deux chemins
correspondent toujours à égalité, la priorité est donnée aux chemins de type exact
plutôt qu'aux chemins de type préfixe.
Jokers dans les noms d'hôte
Les hôtes peuvent être des correspondances précises (par exemple « foo.bar.com ») ou un joker (par
exemple « *.foo.com »). Une correspondance précise exige que l'en-tête HTTP host
corresponde au champ host. Une correspondance avec joker exige que l'en-tête HTTP host
soit égal au suffixe de la règle avec joker.
Hôte
En-tête Host
Correspondance ?
*.foo.com
bar.foo.com
Correspond grâce au suffixe commun
*.foo.com
baz.bar.foo.com
Pas de correspondance, le joker ne couvre qu'un seul libellé DNS
*.foo.com
foo.com
Pas de correspondance, le joker ne couvre qu'un seul libellé DNS
Les Ingress peuvent être mis en œuvre par différents contrôleurs, souvent avec des
configurations différentes. Chaque Ingress devrait indiquer une classe, c'est-à-dire une référence à une
ressource IngressClass qui contient une configuration supplémentaire, dont le nom
du contrôleur chargé de mettre en œuvre la classe.
Le champ .spec.parameters d'une IngressClass vous permet de référencer une autre
ressource qui fournit la configuration associée à cette IngressClass.
Le type précis de paramètres à utiliser dépend du contrôleur d'Ingress
que vous indiquez dans le champ .spec.controller de l'IngressClass.
Portée d'une IngressClass
Selon votre contrôleur d'Ingress, vous pourrez peut-être utiliser des paramètres
définis pour tout le cluster, ou pour un seul namespace.
Par défaut, les paramètres d'une IngressClass ont une portée à l'échelle du cluster.
Si vous définissez le champ .spec.parameters sans définir
.spec.parameters.scope, ou si vous définissez .spec.parameters.scope sur
Cluster, l'IngressClass fait référence à une ressource à portée cluster.
Le kind (combiné à l'apiGroup) des paramètres
fait référence à une API à portée cluster (éventuellement une ressource personnalisée), et
le name des paramètres identifie une ressource précise à portée cluster
de cette API.
Par exemple :
---apiVersion:networking.k8s.io/v1kind:IngressClassmetadata:name:external-lb-1spec:controller:example.com/ingress-controllerparameters:# The parameters for this IngressClass are specified in a# ClusterIngressParameter (API group k8s.example.net) named# "external-config-1". This definition tells Kubernetes to# look for a cluster-scoped parameter resource.scope:ClusterapiGroup:k8s.example.netkind:ClusterIngressParametername:external-config-1
Feature state:Stable since Kubernetes v1.23
Si vous définissez le champ .spec.parameters et définissez
.spec.parameters.scope sur Namespace, l'IngressClass fait référence
à une ressource à portée namespace. Vous devez aussi définir le champ namespace
de .spec.parameters avec le namespace qui contient
les paramètres que vous voulez utiliser.
Le kind (combiné à l'apiGroup) des paramètres
fait référence à une API à portée namespace (par exemple : ConfigMap), et
le name des paramètres identifie une ressource précise
dans le namespace indiqué dans namespace.
Les paramètres à portée namespace aident l'opérateur du cluster à déléguer le contrôle de la
configuration (par exemple : réglages de l'équilibreur de charge, définition de la passerelle d'API)
utilisée pour une charge de travail. Avec un paramètre à portée cluster, soit :
l'équipe qui exploite le cluster doit approuver les modifications d'une autre équipe
chaque fois qu'un nouveau changement de configuration est appliqué ;
l'équipe qui exploite le cluster doit définir des contrôles d'accès spécifiques, comme des
rôles et des liaisons RBAC, qui permettent
à l'équipe applicative de modifier la ressource de paramètres à portée cluster.
L'API IngressClass elle-même a toujours une portée cluster.
Voici un exemple d'IngressClass qui fait référence à des paramètres
à portée namespace :
---apiVersion:networking.k8s.io/v1kind:IngressClassmetadata:name:external-lb-2spec:controller:example.com/ingress-controllerparameters:# The parameters for this IngressClass are specified in an# IngressParameter (API group k8s.example.com) named "external-config",# that's in the "external-configuration" namespace.scope:NamespaceapiGroup:k8s.example.comkind:IngressParameternamespace:external-configurationname:external-config
Annotation obsolète
Avant l'ajout de la ressource IngressClass et du champ ingressClassName dans
Kubernetes 1.18, les classes d'Ingress étaient indiquées par une annotation
kubernetes.io/ingress.class sur l'Ingress. Cette annotation n'a jamais été
définie formellement, mais elle était largement prise en charge par les contrôleurs d'Ingress.
Le champ ingressClassName, plus récent, remplace cette
annotation, sans en être un équivalent direct. Alors que l'annotation servait
généralement à référencer le nom du contrôleur d'Ingress chargé de mettre en œuvre
l'Ingress, le champ est une référence à une ressource IngressClass qui contient
une configuration d'Ingress supplémentaire, dont le nom du contrôleur d'Ingress.
IngressClass par défaut
Vous pouvez marquer une IngressClass donnée comme classe par défaut de votre cluster. Définir
l'annotation ingressclass.kubernetes.io/is-default-class sur true sur une
ressource IngressClass garantit que cette IngressClass par défaut sera attribuée
aux nouveaux Ingress qui n'indiquent pas de champ ingressClassName.
Avertissement:
Si plusieurs IngressClass sont marquées comme classe par défaut de votre cluster,
le contrôleur d'admission empêche la création de nouveaux objets Ingress qui n'indiquent pas
d'ingressClassName. Pour résoudre ce problème, assurez-vous qu'au plus une
IngressClass est marquée comme classe par défaut dans votre cluster.
Commencez par définir une
IngressClass par défaut. Il est toutefois recommandé d'indiquer l'IngressClass
par défaut :
Il existe déjà des concepts Kubernetes qui permettent d'exposer un seul Service
(voir les alternatives). Vous pouvez aussi le faire avec un Ingress en indiquant un
backend par défaut sans règles.
Si vous le créez avec kubectl apply -f, vous devriez pouvoir afficher l'état
de l'Ingress que vous avez ajouté :
kubectl get ingress test-ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
test-ingress external-lb * 203.0.113.123 80 59s
203.0.113.123 est l'adresse IP allouée par le contrôleur d'Ingress pour satisfaire
cet Ingress.
Note:
Les contrôleurs d'Ingress et les équilibreurs de charge peuvent mettre une minute ou deux à allouer une adresse IP.
En attendant, l'adresse s'affiche souvent sous la forme <pending>.
Fanout simple
Une configuration en fanout achemine le trafic d'une seule adresse IP vers plusieurs Services,
en fonction de l'URI HTTP demandée. Un Ingress vous permet de réduire au minimum le nombre
d'équilibreurs de charge. Prenons par exemple la configuration suivante :
Name: simple-fanout-example
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:4200 (10.8.0.90:4200)
/bar service2:8080 (10.8.0.91:8080)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 22s loadbalancer-controller default/test
Le contrôleur d'Ingress provisionne un équilibreur de charge propre à son implémentation
qui satisfait l'Ingress, à condition que les Services (service1, service2) existent.
Une fois que c'est fait, vous pouvez voir l'adresse de l'équilibreur de charge dans le
champ Address.
Note:
Selon le contrôleur d'Ingress
que vous utilisez, vous devrez peut-être créer un
Service default-http-backend.
Hébergement virtuel basé sur le nom
Les hôtes virtuels basés sur le nom permettent d'acheminer le trafic HTTP vers plusieurs noms d'hôte partageant la même adresse IP.
Figure. Hébergement virtuel basé sur le nom
L'Ingress suivant indique à l'équilibreur de charge sous-jacent d'acheminer les requêtes en fonction de
l'en-tête Host.
Si vous créez une ressource Ingress sans définir d'hôte dans les règles, tout
trafic web adressé à l'adresse IP de votre contrôleur d'Ingress peut correspondre sans qu'un hôte virtuel
basé sur le nom soit nécessaire.
Par exemple, l'Ingress suivant achemine le trafic
demandé pour first.bar.com vers service1, celui pour second.bar.com vers service2,
et tout trafic dont l'en-tête Host de la requête ne correspond ni à first.bar.com
ni à second.bar.com vers service3.
Vous pouvez sécuriser un Ingress en indiquant un Secret
qui contient une clé privée et un certificat TLS. La ressource Ingress ne prend en charge
qu'un seul port TLS, le 443, et suppose que la terminaison TLS se fait au point d'entrée
(le trafic vers le Service et ses Pods circule en clair).
Si la section de configuration TLS d'un Ingress indique plusieurs hôtes, ils sont
multiplexés sur le même port selon le nom d'hôte indiqué via
l'extension TLS SNI (à condition que le contrôleur d'Ingress prenne en charge SNI). Le Secret TLS
doit contenir des clés nommées tls.crt et tls.key, qui contiennent le certificat
et la clé privée à utiliser pour TLS. Par exemple :
Référencer ce Secret dans un Ingress indique au contrôleur d'Ingress de
sécuriser avec TLS le canal entre le client et l'équilibreur de charge. Vous devez vous
assurer que le Secret TLS que vous avez créé provient d'un certificat contenant un Common
Name (CN), aussi appelé nom de domaine complet (FQDN), pour https-example.foo.com.
Note:
Gardez à l'esprit que TLS ne fonctionnera pas sur la règle par défaut, car les
certificats devraient être émis pour tous les sous-domaines possibles. C'est pourquoi
les hosts de la section tls doivent correspondre explicitement au host de la section
rules.
Les fonctionnalités TLS prises en charge varient d'un contrôleur d'Ingress à l'autre.
Consultez la documentation du ou des contrôleurs d'Ingress que vous avez choisis pour
comprendre le fonctionnement de TLS dans votre environnement.
Équilibrage de charge
Un contrôleur d'Ingress démarre avec des réglages de politique d'équilibrage de charge
qu'il applique à tous les Ingress, comme l'algorithme d'équilibrage de charge, le schéma de pondération
des backends, etc. Les concepts d'équilibrage de charge plus avancés
(par exemple les sessions persistantes ou les pondérations dynamiques) ne sont pas encore exposés via
l'Ingress. Vous pouvez en revanche obtenir ces fonctionnalités grâce à l'équilibreur de charge utilisé pour
un Service.
Notez aussi que, même si les contrôles de santé (health checks) ne sont pas exposés directement
via l'Ingress, il existe dans Kubernetes des concepts parallèles, comme les
sondes de disponibilité (readiness probes),
qui permettent d'obtenir le même résultat. Consultez la documentation propre
à votre contrôleur pour savoir comment il gère les contrôles de santé.
Mettre à jour un Ingress
Pour mettre à jour un Ingress existant afin d'ajouter un nouvel hôte, vous pouvez modifier la ressource :
kubectl describe ingress test
Name: test
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:80 (10.8.0.90:80)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 35s loadbalancer-controller default/test
kubectl edit ingress test
Un éditeur s'ouvre avec la configuration existante au format YAML.
Modifiez-la pour ajouter le nouvel hôte :
Une fois vos modifications enregistrées, kubectl met à jour la ressource dans le serveur d'API, ce qui indique
au contrôleur d'Ingress de reconfigurer l'équilibreur de charge.
Vérifiez-le :
kubectl describe ingress test
Name: test
Namespace: default
Address: 178.91.123.132
Default backend: default-http-backend:80 (10.8.2.3:8080)
Rules:
Host Path Backends
---- ---- --------
foo.bar.com
/foo service1:80 (10.8.0.90:80)
bar.baz.com
/foo service2:80 (10.8.0.91:80)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 45s loadbalancer-controller default/test
Vous pouvez obtenir le même résultat en exécutant kubectl replace -f sur un fichier YAML d'Ingress modifié.
Basculement entre zones de disponibilité
Les techniques de répartition du trafic entre domaines de défaillance diffèrent d'un fournisseur de cloud à l'autre.
Consultez la documentation du contrôleur d'Ingress concerné pour plus de détails.
Alternatives
Vous pouvez exposer un Service de plusieurs manières qui n'impliquent pas directement la ressource Ingress :
Pour qu'un Ingress fonctionne dans votre cluster, un contrôleur d'Ingress doit être en cours d'exécution. Vous devez choisir au moins un contrôleur d'Ingress et vous assurer qu'il est mis en place dans votre cluster. Cette page liste des contrôleurs d'Ingress courants que vous pouvez déployer.
Note:
Le projet Kubernetes recommande d'utiliser Gateway plutôt
qu'Ingress.
L'API Ingress est figée.
Cela signifie que :
L'API Ingress est en disponibilité générale (GA) et soumise aux garanties de stabilité prévues pour les API GA.
Le projet Kubernetes n'a pas l'intention de retirer Ingress de Kubernetes.
L'API Ingress n'est plus développée et ne recevra plus aucune modification
ni mise à jour.
Contrôleurs d'Ingress
Le projet Kubernetes prend en charge et maintient les contrôleurs d'Ingress AWS et GCE.
Contrôleurs d'Ingress tiers
Note: Cette section renvoie à des projets tiers qui fournissent des fonctionnalités requises par Kubernetes. Les auteurs du projet Kubernetes ne sont pas responsables de ces projets, classés par ordre alphabétique. Pour ajouter un projet à cette liste, lisez le guide avant de soumettre une modification. Plus d'informations.
ngrok-operator est un contrôleur pour ngrok qui prend en charge à la fois Ingress et Gateway API pour exposer vos Services K8s de manière sécurisée sur Internet.
Skipper est un routeur HTTP et un proxy inverse pour la composition de services, y compris pour des cas d'usage comme Kubernetes Ingress, conçu comme une bibliothèque pour construire votre propre proxy.
Tyk Operator étend Ingress avec des ressources personnalisées pour lui apporter des fonctionnalités de gestion d'API. Tyk Operator fonctionne avec Tyk Gateway (open source) et avec le plan de contrôle Tyk Cloud.
Wallarm Ingress Controller est un contrôleur d'Ingress qui fournit des fonctionnalités de WAAP (WAF) et de sécurité des API.
Utiliser plusieurs contrôleurs d'Ingress
Vous pouvez déployer autant de contrôleurs d'Ingress que vous le souhaitez dans un cluster, grâce aux
classes d'Ingress. Notez le .metadata.name de votre ressource de classe d'Ingress. Lorsque vous créez un Ingress, vous avez besoin de ce nom pour renseigner le champ ingressClassName de votre objet Ingress (voir la référence IngressSpec v1). ingressClassName remplace l'ancienne méthode par annotation.
Si vous ne précisez pas d'IngressClass pour un Ingress et que votre cluster a exactement une IngressClass marquée comme classe par défaut, Kubernetes applique cette IngressClass par défaut du cluster à l'Ingress.
Pour marquer une IngressClass comme classe par défaut, définissez l'annotation ingressclass.kubernetes.io/is-default-class sur cette IngressClass, avec la chaîne "true".
Idéalement, tous les contrôleurs d'Ingress devraient respecter cette spécification, mais les différents
contrôleurs d'Ingress fonctionnent de manière légèrement différente.
Note:
Consultez bien la documentation de votre contrôleur d'Ingress pour connaître les points d'attention liés à ce choix.
Gateway API est une famille de types d'API qui fournissent un provisionnement dynamique de l'infrastructure et un routage avancé du trafic.
Rendez des services réseau accessibles grâce à un mécanisme de configuration extensible, orienté
rôles et conscient des protocoles. Gateway API est un add-on
qui contient des types d'API fournissant un
provisionnement dynamique de l'infrastructure et un routage avancé du trafic.
Principes de conception
Les principes suivants ont guidé la conception et l'architecture de Gateway API :
Orientée rôles : les types de Gateway API sont modélisés d'après les rôles organisationnels
chargés de gérer le réseau des services Kubernetes :
Fournisseur d'infrastructure : gère une infrastructure qui permet à plusieurs clusters isolés
de servir plusieurs locataires, par exemple un fournisseur de cloud.
Opérateur de cluster : gère des clusters et s'occupe généralement des politiques, de l'accès
réseau, des permissions des applications, etc.
Développeur d'applications : gère une application qui s'exécute dans un cluster et s'occupe
généralement de la configuration au niveau de l'application et de la composition des
Services.
Expressive : les types de Gateway API prennent en charge des fonctionnalités couvrant les cas
d'usage courants de routage du trafic, comme la correspondance sur les en-têtes ou la pondération
du trafic, entre autres, qui n'étaient possibles avec Ingress
qu'au moyen d'annotations personnalisées.
Extensible : Gateway permet de lier des ressources personnalisées à différents niveaux de l'API.
Cela rend possible une personnalisation fine aux endroits appropriés de la structure de l'API.
Modèle de ressources
Gateway API comporte quatre types d'API stables :
GatewayClass : définit un ensemble de gateways partageant une configuration commune et gérées
par un contrôleur qui implémente la classe.
Gateway : définit une instance d'infrastructure de traitement du trafic, comme un équilibreur de charge (load balancer) cloud.
HTTPRoute : définit des règles propres à HTTP pour acheminer le trafic d'un listener de Gateway
vers une représentation de points de terminaison réseau de backend. Ces points de terminaison sont
souvent représentés par un Service.
GRPCRoute : définit des règles propres à gRPC pour acheminer le trafic d'un listener de Gateway
vers une représentation de points de terminaison réseau de backend. Ces points de terminaison sont
souvent représentés par un Service.
Gateway API est organisée en différents types d'API liés par des relations d'interdépendance, afin de
refléter l'organisation par rôles des entreprises. Un objet Gateway est associé à exactement une GatewayClass ;
la GatewayClass décrit le contrôleur de gateway chargé de gérer les Gateways de cette classe.
Un ou plusieurs types de routes, comme HTTPRoute, sont ensuite associés aux Gateways. Une Gateway peut
filtrer les routes autorisées à se rattacher à ses listeners, ce qui forme un modèle de confiance
bidirectionnel avec les routes.
La figure suivante illustre les relations entre les trois types stables de Gateway API :
GatewayClass
Les Gateways peuvent être implémentées par différents contrôleurs, souvent avec des configurations
différentes. Une Gateway doit référencer une GatewayClass qui contient le nom du contrôleur qui
implémente la classe.
Dans cet exemple, un contrôleur qui implémente Gateway API est configuré pour gérer les GatewayClasses
dont le nom de contrôleur est example.com/gateway-controller. Les Gateways de cette classe seront
gérées par le contrôleur de l'implémentation.
Consultez la référence de GatewayClass
pour la définition complète de ce type d'API.
Gateway
Une Gateway décrit une instance d'infrastructure de traitement du trafic. Elle définit un point de
terminaison réseau qui peut servir à traiter le trafic, c'est-à-dire à le filtrer, à en équilibrer la charge, à le
fractionner, etc., vers des backends comme un Service. Par exemple, une Gateway peut représenter un
équilibreur de charge cloud ou un serveur proxy interne au cluster, configuré pour accepter du trafic HTTP.
Dans cet exemple, une instance d'infrastructure de traitement du trafic est programmée pour écouter
le trafic HTTP sur le port 80. Comme le champ addresses n'est pas renseigné, une adresse ou un nom
d'hôte est attribué à la Gateway par le contrôleur de l'implémentation. Cette adresse sert de point
de terminaison réseau pour traiter le trafic destiné aux points de terminaison réseau de backend
définis dans les routes.
Consultez la référence de Gateway
pour la définition complète de ce type d'API. Pour configurer des listeners HTTPS/TLS, consultez le
guide TLS de Gateway API.
Note:
Par défaut, une Gateway n'accepte que les routes du même namespace. Les routes situées dans d'autres namespaces nécessitent de configurer allowedRoutes.
HTTPRoute
Le type HTTPRoute définit le comportement de routage des requêtes HTTP, d'un listener de Gateway vers
des points de terminaison réseau de backend. Pour un backend de type Service, une implémentation peut
représenter le point de terminaison réseau du backend par l'IP du Service ou par les EndpointSlices
associées au Service. Une HTTPRoute représente une configuration appliquée à l'implémentation de
Gateway sous-jacente. Par exemple, définir une nouvelle HTTPRoute peut conduire à configurer des
routes de trafic supplémentaires dans un équilibreur de charge cloud ou dans un serveur proxy du cluster.
Dans cet exemple, le trafic HTTP provenant de la Gateway example-gateway, dont l'en-tête Host: vaut
www.example.com et dont le chemin de la requête est /login, sera acheminé vers le Service
example-svc sur le port 8080.
Consultez la référence de HTTPRoute
pour la définition complète de ce type d'API.
GRPCRoute
Le type GRPCRoute définit le comportement de routage des requêtes gRPC, d'un listener de Gateway vers
des points de terminaison réseau de backend. Pour un backend de type Service, une implémentation peut
représenter le point de terminaison réseau du backend par l'IP du Service ou par les EndpointSlices
associées au Service. Une GRPCRoute représente une configuration appliquée à l'implémentation de
Gateway sous-jacente. Par exemple, définir une nouvelle GRPCRoute peut conduire à configurer des
routes de trafic supplémentaires dans un équilibreur de charge cloud ou dans un serveur proxy du cluster.
Les Gateways qui prennent en charge GRPCRoute doivent prendre en charge HTTP/2 sans mise à niveau
initiale depuis HTTP/1, afin de garantir que le trafic gRPC circule correctement.
Dans cet exemple, le trafic gRPC provenant de la Gateway example-gateway, dont l'hôte est
svc.example.com, sera dirigé vers le Service example-svc sur le port 50051, dans le même namespace.
GRPCRoute permet de cibler des services gRPC précis, comme dans l'exemple suivant :
Dans ce cas, la GRPCRoute correspond à tout le trafic destiné à svc.example.com et applique ses règles
de routage pour transmettre le trafic au bon backend. Comme une seule correspondance est définie,
seules les requêtes vers la méthode com.example.User.Login sur svc.example.com seront
transmises. Les RPC vers toute autre méthode ne correspondront pas à cette route.
Consultez la référence de GRPCRoute
pour la définition complète de ce type d'API.
Flux des requêtes
Voici un exemple simple de trafic HTTP acheminé vers un Service à l'aide d'une Gateway et d'une HTTPRoute :
Dans cet exemple, le flux d'une requête pour une Gateway implémentée sous forme de proxy inverse est le suivant :
Le client commence à préparer une requête HTTP pour l'URL http://www.example.com.
Le résolveur DNS du client résout le nom de destination en
une ou plusieurs adresses IP associées à la Gateway.
Le client envoie une requête à l'adresse IP de la Gateway ; le proxy inverse reçoit la requête
HTTP et utilise l'en-tête Host: pour trouver une configuration issue de la Gateway et de
l'HTTPRoute rattachée.
Le proxy inverse peut éventuellement vérifier la correspondance des en-têtes et/ou du chemin
de la requête, selon les règles de correspondance de l'HTTPRoute.
Le proxy inverse peut éventuellement modifier la requête, par exemple pour ajouter ou supprimer
des en-têtes, selon les règles de filtrage de l'HTTPRoute.
Enfin, le proxy inverse transmet la requête à un ou plusieurs backends.
Conformité
Gateway API couvre un large ensemble de fonctionnalités et elle est largement implémentée. Cette
combinaison exige des définitions et des tests de conformité clairs pour garantir que l'API offre
une expérience cohérente partout où elle est utilisée.
Consultez la documentation sur la conformité
pour comprendre des notions comme les canaux de publication, les niveaux de prise en charge et
l'exécution des tests de conformité.
Migrer depuis Ingress
Gateway API succède à l'API Ingress.
Elle n'inclut cependant pas le type Ingress. Une conversion ponctuelle de vos ressources Ingress
existantes en ressources Gateway API est donc nécessaire.
Consultez le guide de migration depuis Ingress
pour savoir comment migrer des ressources Ingress vers des ressources Gateway API.
A suivre
Les ressources de Gateway API ne sont pas implémentées nativement par Kubernetes : leurs spécifications
sont définies sous forme de ressources personnalisées
prises en charge par un large éventail d'implémentations.
Installez les CRD de Gateway API ou
suivez les instructions d'installation de l'implémentation choisie. Une fois l'implémentation installée,
utilisez le guide Getting Started pour prendre en main
rapidement Gateway API.
Note:
Consultez la documentation de l'implémentation choisie pour bien en comprendre les éventuelles limites.
Consultez la spécification de l'API pour plus
de détails sur tous les types de Gateway API.
5 - EndpointSlices
L'API EndpointSlice est le mécanisme que Kubernetes utilise pour permettre à votre Service de passer à l'échelle et de gérer un grand nombre de backends, et elle permet au cluster de mettre à jour efficacement sa liste de backends sains.
Feature state:Stable since Kubernetes v1.21
Les EndpointSlices suivent les adresses IP des points de terminaison backend. Les EndpointSlices sont généralement associés à un Service et les points de terminaison backend représentent typiquement des Pods.
API EndpointSlice
Dans Kubernetes, un EndpointSlice contient des références à un ensemble de points
de terminaison réseau. Le plan de contrôle crée automatiquement des EndpointSlices
pour tout Service Kubernetes pour lequel un sélecteur est spécifié. Ces EndpointSlices contiennent des
références à tous les Pods qui correspondent au sélecteur du Service. Les EndpointSlices
regroupent les points de terminaison réseau par combinaison unique de famille d'adresses IP,
de protocole, de numéro de port et de nom de Service.
Le nom d'un objet EndpointSlice doit être un
nom de sous-domaine DNS valide.
Voici par exemple un objet EndpointSlice dont le propriétaire est le Service Kubernetes
example.
Par défaut, le plan de contrôle crée et gère des EndpointSlices qui ne contiennent
pas plus de 100 points de terminaison chacun. Vous pouvez modifier cette valeur avec l'option
--max-endpoints-per-slice de
kube-controller-manager,
jusqu'à un maximum de 1000.
Les EndpointSlices constituent la source de vérité de
kube-proxy pour déterminer
comment acheminer le trafic interne.
Types d'adresses
Les EndpointSlices prennent en charge deux types d'adresses :
IPv4
IPv6
Chaque objet EndpointSlice correspond à un type d'adresse IP précis. Si vous avez
un Service accessible en IPv4 et en IPv6, il existera au moins deux objets
EndpointSlice (un pour IPv4 et un pour IPv6).
Conditions
L'API EndpointSlice enregistre, pour les points de terminaison, des conditions qui peuvent être utiles à ses consommateurs.
Les trois conditions sont serving, terminating et ready.
Serving
Feature state:Stable since Kubernetes v1.26
La condition serving indique que le point de terminaison répond actuellement aux requêtes, et
qu'il devrait donc être utilisé comme cible pour le trafic du Service. Pour les points de terminaison
adossés à un Pod, elle correspond à la condition Ready du Pod.
Terminating
Feature state:Stable since Kubernetes v1.26
La condition terminating indique que le point de terminaison est
en cours d'arrêt. Pour les points de terminaison adossés à un Pod, cette condition est définie
dès que la suppression du Pod est demandée (c'est-à-dire lorsqu'il reçoit un horodatage
de suppression, mais très probablement avant que les conteneurs du Pod ne s'arrêtent).
Les proxys de Service ignorent normalement les points de terminaison marqués terminating,
mais ils peuvent acheminer le trafic vers des points de terminaison à la fois serving et
terminating si tous les points de terminaison disponibles sont marqués terminating. (Cela
contribue à garantir qu'aucun trafic du Service n'est perdu pendant les mises à jour progressives
des Pods sous-jacents.)
Ready
La condition ready est essentiellement un raccourci pour vérifier
« serving et non terminating » (elle vaut toutefois toujours
true pour les Services dont spec.publishNotReadyAddresses est défini sur
true).
Informations de topologie
Chaque point de terminaison d'un EndpointSlice peut contenir des informations de topologie pertinentes.
Ces informations comprennent l'emplacement du point de terminaison ainsi que des informations
sur le nœud et la zone correspondants. Elles sont disponibles dans les champs suivants,
propres à chaque point de terminaison d'un EndpointSlice :
nodeName : le nom du nœud sur lequel se trouve ce point de terminaison.
zone : la zone dans laquelle se trouve ce point de terminaison.
Gestion
Le plus souvent, c'est le plan de contrôle (plus précisément, le
contrôleur d'EndpointSlices) qui crée et
gère les objets EndpointSlice. Les EndpointSlices ont de nombreux autres cas d'usage,
comme les implémentations de service mesh, qui peuvent amener d'autres entités
ou contrôleurs à gérer des ensembles supplémentaires d'EndpointSlices.
Pour que plusieurs entités puissent gérer des EndpointSlices sans se gêner
mutuellement, Kubernetes définit le
labelendpointslice.kubernetes.io/managed-by, qui indique l'entité qui gère
un EndpointSlice.
Le contrôleur d'EndpointSlices attribue la valeur endpointslice-controller.k8s.io
à ce label sur tous les EndpointSlices qu'il gère. Les autres entités qui gèrent
des EndpointSlices doivent elles aussi attribuer une valeur unique à ce label.
Propriété
Dans la plupart des cas d'usage, le propriétaire d'un EndpointSlice est le Service dont
l'objet EndpointSlice suit les points de terminaison. Cette propriété est indiquée par une référence
de propriétaire (owner reference) sur chaque EndpointSlice, ainsi que par un label
kubernetes.io/service-name qui permet de retrouver simplement tous les EndpointSlices
d'un Service.
Répartition des EndpointSlices
Chaque EndpointSlice possède un ensemble de ports qui s'applique à tous les points de terminaison
de la ressource. Lorsqu'un Service utilise des ports nommés, les Pods peuvent se retrouver avec
des numéros de port cible différents pour un même port nommé, ce qui nécessite des
EndpointSlices distincts.
Le plan de contrôle essaie de remplir les EndpointSlices autant que possible, mais ne
les rééquilibre pas activement. La logique est assez simple :
Parcourir les EndpointSlices existants, retirer les points de terminaison qui ne sont plus
souhaités et mettre à jour les points de terminaison correspondants qui ont changé.
Parcourir les EndpointSlices modifiés lors de la première étape et
les compléter avec les nouveaux points de terminaison nécessaires.
S'il reste encore de nouveaux points de terminaison à ajouter, essayer de les placer dans un
EndpointSlice resté inchangé et/ou en créer de nouveaux.
Point important : la troisième étape privilégie la limitation des mises à jour d'EndpointSlices
plutôt qu'un remplissage optimal des EndpointSlices. Par exemple, s'il y a 10
nouveaux points de terminaison à ajouter et 2 EndpointSlices pouvant chacun en accueillir 5 de plus,
cette approche créera un nouvel EndpointSlice au lieu de remplir les 2
EndpointSlices existants. Autrement dit, une seule création d'EndpointSlice est
préférable à plusieurs mises à jour d'EndpointSlices.
Comme kube-proxy s'exécute sur chaque nœud et surveille les EndpointSlices, chaque modification
d'un EndpointSlice devient relativement coûteuse, puisqu'elle est transmise à
chaque nœud du cluster. Cette approche vise à limiter le nombre de
modifications à envoyer à chaque nœud, même si elle peut aboutir à plusieurs
EndpointSlices partiellement remplis.
En pratique, cette répartition moins qu'idéale devrait être rare. La plupart des modifications
traitées par le contrôleur d'EndpointSlices sont suffisamment petites pour tenir dans un
EndpointSlice existant ; dans le cas contraire, un nouvel EndpointSlice sera de toute façon
probablement nécessaire bientôt. Les mises à jour progressives des Deployments entraînent
aussi un réagencement naturel des EndpointSlices, puisque tous les Pods et leurs points de terminaison
correspondants sont remplacés.
Points de terminaison en double
En raison de la nature des modifications d'EndpointSlices, un point de terminaison peut figurer dans
plusieurs EndpointSlices en même temps. Cela se produit naturellement, car les modifications de
différents objets EndpointSlice peuvent parvenir au watch / cache du client Kubernetes
à des moments différents.
Note:
Les clients de l'API EndpointSlice doivent parcourir tous les EndpointSlices existants
associés à un Service et construire une liste complète de points de terminaison réseau uniques.
Il est important de noter que des points de terminaison peuvent être dupliqués dans différents EndpointSlices.
Vous trouverez une implémentation de référence de cette agrégation et de cette
déduplication des points de terminaison dans le code EndpointSliceCache de kube-proxy.
Mise en miroir des EndpointSlices
Feature state:Deprecated since Kubernetes v1.33
L'API EndpointSlice remplace l'ancienne API Endpoints. Pour
préserver la compatibilité avec les anciens contrôleurs et les charges de travail des utilisateurs qui
s'attendent à ce que kube-proxy
achemine le trafic à partir des ressources Endpoints, le plan de contrôle du cluster
reproduit (en miroir) la plupart des ressources Endpoints créées par les utilisateurs
dans des EndpointSlices correspondants.
(Cette fonctionnalité est toutefois dépréciée, comme le reste de l'API Endpoints.
Les utilisateurs qui définissent manuellement des points de terminaison pour des Services
sans sélecteur doivent le faire en créant directement des ressources EndpointSlice,
plutôt qu'en créant des ressources Endpoints et en laissant le plan de contrôle les reproduire en miroir.)
Le plan de contrôle reproduit les ressources Endpoints en miroir, sauf si :
la ressource Endpoints a un label endpointslice.kubernetes.io/skip-mirror
défini sur true ;
la ressource Endpoints a une annotation control-plane.alpha.kubernetes.io/leader ;
la ressource Service correspondante n'existe pas ;
la ressource Service correspondante a un sélecteur non nul.
Une même ressource Endpoints peut donner lieu à plusieurs EndpointSlices. C'est le
cas si une ressource Endpoints comporte plusieurs sous-ensembles (subsets) ou contient des points
de terminaison de plusieurs familles d'adresses IP (IPv4 et IPv6). Au maximum 1000 adresses par
sous-ensemble sont reproduites dans les EndpointSlices.
Si vous voulez contrôler les flux de trafic au niveau des adresses IP ou des ports (couches 3 ou 4 du modèle OSI), les NetworkPolicies vous permettent de définir des règles pour les flux de trafic au sein de votre cluster, ainsi qu'entre les Pods et le monde extérieur. Votre cluster doit utiliser un plugin réseau qui sait faire respecter les NetworkPolicies.
Si vous voulez contrôler les flux de trafic au niveau des adresses IP ou des ports pour les protocoles TCP, UDP et SCTP,
vous pouvez envisager d'utiliser les NetworkPolicies de Kubernetes pour certaines applications de votre cluster.
Les NetworkPolicies sont un mécanisme centré sur l'application, qui vous permet de définir comment un
pod est autorisé à communiquer sur le réseau avec différentes
« entités » (nous employons ici le mot « entité » pour ne pas donner un sens de plus à des termes courants comme
« endpoints » et « services », qui ont un sens précis dans Kubernetes).
Les NetworkPolicies s'appliquent à une connexion dont l'une des extrémités au moins est un pod, et ne concernent pas
les autres connexions.
Les entités avec lesquelles un Pod peut communiquer sont identifiées par une combinaison des
trois identifiants suivants :
Les autres pods autorisés (exception : un pod ne peut pas bloquer l'accès à lui-même)
Les namespaces autorisés
Les blocs d'adresses IP (exception : le trafic depuis et vers le nœud sur lequel un Pod s'exécute est toujours autorisé,
quelle que soit l'adresse IP du Pod ou du nœud)
Pour définir une NetworkPolicy basée sur les pods ou les namespaces, vous utilisez un
sélecteur pour indiquer quel trafic est autorisé
depuis et vers le ou les Pods qui correspondent à ce sélecteur.
Pour les NetworkPolicies basées sur les adresses IP, en revanche, on définit des politiques à partir de blocs d'adresses IP (plages CIDR).
Prérequis
Les politiques réseau sont mises en œuvre par le plugin réseau.
Pour utiliser les politiques réseau, il vous faut une solution réseau qui prend en charge les NetworkPolicies.
Créer une ressource NetworkPolicy sans contrôleur pour la mettre en œuvre n'aura aucun effet.
Les deux types d'isolation d'un pod
Un pod peut être isolé de deux façons : en sortie (egress) et en entrée (ingress).
Ces isolations portent sur les connexions qui peuvent être établies. Ici, « isolé » n'a rien d'absolu :
cela signifie que « certaines restrictions s'appliquent ». À l'inverse, « non isolé dans une direction » signifie
qu'aucune restriction ne s'applique dans cette direction. Les deux types d'isolation (ou leur absence) sont déclarés
indépendamment l'un de l'autre, et entrent tous deux en jeu pour une connexion d'un pod vers un autre.
Par défaut, un pod n'est pas isolé en sortie : toutes les connexions sortantes sont autorisées.
Un pod est isolé en sortie s'il existe au moins une NetworkPolicy qui sélectionne ce pod et dont
les policyTypes contiennent « Egress » ; on dit alors que cette politique s'applique au pod en sortie.
Quand un pod est isolé en sortie, les seules connexions autorisées depuis ce pod sont celles qu'autorise
la liste egress d'au moins une NetworkPolicy qui s'applique au pod en sortie. Le trafic de réponse
de ces connexions autorisées est lui aussi autorisé implicitement.
Les effets de ces listes egress s'additionnent.
Par défaut, un pod n'est pas isolé en entrée : toutes les connexions entrantes sont autorisées.
Un pod est isolé en entrée s'il existe au moins une NetworkPolicy qui sélectionne ce pod et dont
les policyTypes contiennent « Ingress » ; on dit alors que cette politique s'applique au pod en entrée.
Quand un pod est isolé en entrée, les seules connexions autorisées vers ce pod sont celles qui viennent
du nœud du pod et celles qu'autorise la liste ingress d'au moins une NetworkPolicy qui s'applique
au pod en entrée. Le trafic de réponse de ces connexions autorisées est lui aussi autorisé implicitement.
Les effets de ces listes ingress s'additionnent.
Les politiques réseau n'entrent pas en conflit : elles s'additionnent. Si une ou plusieurs politiques s'appliquent
à un pod donné dans une direction donnée, les connexions autorisées dans cette direction pour ce pod sont l'union
de ce qu'autorisent ces politiques. L'ordre d'évaluation n'a donc aucune influence sur le résultat.
Pour qu'une connexion d'un pod source vers un pod de destination soit autorisée, il faut que la politique
en sortie du pod source et la politique en entrée du pod de destination l'autorisent toutes les deux.
Si l'un des deux côtés ne l'autorise pas, la connexion n'a pas lieu.
La ressource NetworkPolicy
Consultez la référence NetworkPolicy
pour la définition complète de la ressource.
Envoyer cette ressource (POST) au serveur d'API de votre cluster n'aura aucun effet si la solution réseau
que vous avez choisie ne prend pas en charge les politiques réseau.
Champs obligatoires : comme toute autre configuration Kubernetes, une NetworkPolicy a besoin des champs apiVersion,
kind et metadata. Pour des informations générales sur l'utilisation des fichiers de configuration, consultez
Configurer un Pod pour utiliser une ConfigMap
et Gestion des objets.
spec : la spec
d'une NetworkPolicy contient toutes les informations nécessaires pour définir une politique réseau donnée dans le namespace concerné.
podSelector : chaque NetworkPolicy contient un podSelector qui sélectionne le groupe de pods
auquel la politique s'applique. La politique de l'exemple sélectionne les pods qui ont le label « role=db ». Un
podSelector vide sélectionne tous les pods du namespace.
policyTypes : chaque NetworkPolicy contient une liste policyTypes qui peut contenir Ingress,
Egress ou les deux. Le champ policyTypes indique si la politique s'applique au trafic
entrant vers les pods sélectionnés, au trafic sortant des pods sélectionnés, ou aux deux. Si aucun
policyTypes n'est indiqué dans une NetworkPolicy, Ingress est toujours défini par défaut, et
Egress l'est aussi si la NetworkPolicy contient des règles egress.
ingress : chaque NetworkPolicy peut contenir une liste de règles ingress autorisées. Chaque règle autorise
le trafic qui correspond à la fois aux sections from et ports. La politique de l'exemple contient une seule
règle, qui correspond au trafic sur un seul port, depuis l'une de trois sources : la première définie par
un ipBlock, la deuxième par un namespaceSelector et la troisième par un podSelector.
egress : chaque NetworkPolicy peut contenir une liste de règles egress autorisées. Chaque règle autorise
le trafic qui correspond à la fois aux sections to et ports. La politique de l'exemple contient une seule
règle, qui correspond au trafic sur un seul port vers n'importe quelle destination dans 10.0.0.0/24.
La NetworkPolicy de l'exemple a donc les effets suivants :
elle isole les pods role=db du namespace default pour le trafic entrant et sortant
(s'ils n'étaient pas déjà isolés)
(règles Ingress) elle autorise les connexions vers tous les pods du namespace default qui ont le label
role=db, sur le port TCP 6379, depuis :
n'importe quel pod du namespace default qui a le label role=frontend
n'importe quel pod d'un namespace qui a le label project=myproject
les adresses IP des plages 172.17.0.0–172.17.0.255 et 172.17.2.0–172.17.255.255
(c'est-à-dire tout 172.17.0.0/16 sauf 172.17.1.0/24)
(règles Egress) elle autorise les connexions depuis n'importe quel pod du namespace default qui a le label
role=db vers le CIDR 10.0.0.0/24, sur le port TCP 5978
Quatre types de sélecteurs peuvent être indiqués dans une section from d'ingress ou dans une section to
d'egress :
podSelector : sélectionne certains Pods du même namespace que la NetworkPolicy, qui doivent être
autorisés comme sources en entrée ou comme destinations en sortie.
namespaceSelector : sélectionne certains namespaces dont tous les Pods doivent être autorisés comme
sources en entrée ou comme destinations en sortie.
namespaceSelectoretpodSelector : une même entrée to/from qui indique à la fois
namespaceSelector et podSelector sélectionne certains Pods dans certains namespaces. Veillez
à utiliser une syntaxe YAML correcte. Par exemple :
Cette politique contient un seul élément from, qui autorise les connexions depuis les Pods qui ont le label
role=client dans les namespaces qui ont le label user=alice. La politique suivante, elle, est différente :
Elle contient deux éléments dans le tableau from, et autorise les connexions depuis les Pods du
namespace local qui ont le label role=client, ou depuis n'importe quel Pod de n'importe quel namespace qui a le label
user=alice.
En cas de doute, utilisez kubectl describe pour voir comment Kubernetes a interprété la politique.
ipBlock : sélectionne certaines plages CIDR d'adresses IP à autoriser comme sources en entrée ou comme
destinations en sortie. Il devrait s'agir d'adresses IP externes au cluster, car les adresses IP des Pods sont éphémères et imprévisibles.
Les mécanismes d'entrée et de sortie du cluster doivent souvent réécrire l'adresse IP source ou de destination
des paquets. Lorsque c'est le cas, rien ne définit si cette réécriture a lieu avant ou
après le traitement des NetworkPolicies, et le comportement peut varier selon la
combinaison de plugin réseau, de fournisseur cloud, d'implémentation des Service, etc.
En entrée, cela veut dire que, dans certains cas, vous pourrez filtrer les paquets entrants
selon leur véritable adresse IP source d'origine, alors que dans d'autres cas, l'« adresse IP source »
prise en compte par la NetworkPolicy peut être celle d'un LoadBalancer, du nœud du Pod, etc.
En sortie, cela veut dire que les connexions des pods vers des adresses IP de Service réécrites en
adresses IP externes au cluster peuvent être soumises ou non aux politiques basées sur ipBlock.
Politiques par défaut
Par défaut, s'il n'existe aucune politique dans un namespace, tout le trafic entrant et sortant est autorisé
vers et depuis les pods de ce namespace. Les exemples suivants vous permettent de modifier ce comportement par défaut
dans ce namespace.
Refuser par défaut tout le trafic entrant
Pour créer une politique d'isolation en entrée « par défaut » dans un namespace, créez une NetworkPolicy
qui sélectionne tous les pods mais n'autorise aucun trafic entrant vers ces pods.
Ainsi, même les pods qui ne sont sélectionnés par aucune autre NetworkPolicy restent isolés
en entrée. Cette politique n'a pas d'effet sur l'isolation en sortie des pods.
Autoriser tout le trafic entrant
Si vous voulez autoriser toutes les connexions entrantes vers tous les pods d'un namespace, vous pouvez créer une politique
qui les autorise explicitement.
Une fois cette politique en place, aucune autre politique ne peut entraîner le refus d'une connexion entrante
vers ces pods. Cette politique n'a pas d'effet sur l'isolation en sortie des pods.
Refuser par défaut tout le trafic sortant
Pour créer une politique d'isolation en sortie « par défaut » dans un namespace, créez une NetworkPolicy
qui sélectionne tous les pods mais n'autorise aucun trafic sortant depuis ces pods.
Ainsi, même les pods qui ne sont sélectionnés par aucune autre NetworkPolicy n'ont droit à aucun
trafic sortant. Cette politique ne change pas le comportement d'isolation en entrée des pods.
Avertissement:
Une politique qui refuse par défaut tout le trafic sortant bloque aussi le trafic DNS. Si vos charges de travail
ont besoin de la résolution DNS, vous devez ajouter une NetworkPolicy distincte qui autorise le trafic sortant
vers le service DNS de votre cluster.
Autoriser tout le trafic sortant
Si vous voulez autoriser toutes les connexions depuis tous les pods d'un namespace, vous pouvez créer une politique qui
autorise explicitement toutes les connexions sortantes des pods de ce namespace.
Une fois cette politique en place, aucune autre politique ne peut entraîner le refus d'une connexion sortante
depuis ces pods. Cette politique n'a pas d'effet sur l'isolation en entrée des pods.
Refuser par défaut tout le trafic entrant et sortant
Vous pouvez créer une politique « par défaut » pour un namespace qui empêche tout le trafic entrant ET sortant
en créant la NetworkPolicy suivante dans ce namespace.
Ainsi, même les pods qui ne sont sélectionnés par aucune autre NetworkPolicy n'ont droit à aucun
trafic entrant ni sortant.
Filtrage du trafic réseau
Les NetworkPolicies sont définies pour les connexions de couche 4
(TCP, UDP et, en option, SCTP). Pour tous les autres protocoles, le comportement peut varier
d'un plugin réseau à l'autre.
Note:
Vous devez utiliser un plugin CNI qui prend en charge
les NetworkPolicies pour le protocole SCTP.
Lorsqu'une politique réseau deny all est définie, elle ne garantit que le refus des connexions TCP, UDP et SCTP.
Pour les autres protocoles, comme ARP ou ICMP, le comportement n'est pas défini.
Il en va de même pour les règles d'autorisation : quand un pod précis est autorisé comme source en entrée ou comme destination en sortie,
ce qu'il advient des paquets ICMP, par exemple, n'est pas défini. Des protocoles comme ICMP peuvent être autorisés par certains
plugins réseau et refusés par d'autres.
Cibler une plage de ports
Feature state:Stable since Kubernetes v1.25
Quand vous écrivez une NetworkPolicy, vous pouvez cibler une plage de ports au lieu d'un seul port.
Pour cela, utilisez le champ endPort, comme dans l'exemple suivant :
La règle ci-dessus autorise n'importe quel Pod qui a le label role=db dans le namespace default à communiquer
avec n'importe quelle adresse IP de la plage 10.0.0.0/24 en TCP, à condition que le port
de destination soit compris entre 32000 et 32768.
Les restrictions suivantes s'appliquent à l'utilisation de ce champ :
Le champ endPort doit être supérieur ou égal au champ port.
endPort ne peut être défini que si port est aussi défini.
Les deux ports doivent être numériques.
Note:
Votre cluster doit utiliser un plugin CNI qui
prend en charge le champ endPort dans les spécifications des NetworkPolicies.
Si votre plugin réseau
ne prend pas en charge le champ endPort et que vous définissez une NetworkPolicy qui l'utilise,
seul le champ port sera pris en compte.
Cibler plusieurs namespaces par label
Dans ce scénario, votre NetworkPolicy Egress cible plusieurs namespaces grâce à leurs
labels. Pour que cela fonctionne, vous devez poser un label sur les namespaces cibles. Par exemple :
Il n'est pas possible d'indiquer directement le nom des namespaces dans une NetworkPolicy.
Vous devez utiliser un namespaceSelector avec matchLabels ou matchExpressions pour sélectionner
les namespaces selon leurs labels.
Cibler un namespace par son nom
Le plan de contrôle de Kubernetes pose sur tous les namespaces un label immuable kubernetes.io/metadata.name,
dont la valeur est le nom du namespace.
Une NetworkPolicy ne peut pas cibler un namespace par son nom via un champ de l'objet, mais vous pouvez utiliser
ce label standardisé pour cibler un namespace précis.
Cycle de vie d'un pod
Note:
Ce qui suit s'applique aux clusters qui disposent d'un plugin réseau conforme et d'une implémentation conforme
des NetworkPolicies.
Quand un nouvel objet NetworkPolicy est créé, le plugin réseau peut mettre un certain temps
à le prendre en compte. Si un pod concerné par une NetworkPolicy
est créé avant que le plugin réseau ait fini de traiter cette NetworkPolicy,
ce pod peut démarrer sans protection, et les règles d'isolation seront appliquées une fois
le traitement de la NetworkPolicy terminé.
Une fois la NetworkPolicy traitée par le plugin réseau :
Tous les nouveaux pods concernés par une NetworkPolicy donnée seront isolés avant de démarrer.
Les implémentations des NetworkPolicies doivent garantir que le filtrage est effectif pendant tout
le cycle de vie du Pod, dès le tout premier instant où l'un des conteneurs de ce Pod démarre.
Comme elles s'appliquent au niveau du Pod, les NetworkPolicies s'appliquent de la même façon aux conteneurs d'initialisation,
aux conteneurs sidecar et aux conteneurs ordinaires.
Les règles d'autorisation finiront par être appliquées après les règles d'isolation (ou peut-être en même temps).
Dans le pire des cas, un pod nouvellement créé peut n'avoir aucune connectivité réseau au démarrage, si
les règles d'isolation étaient déjà appliquées mais pas encore les règles d'autorisation.
Chaque NetworkPolicy créée finira par être traitée par un plugin réseau, mais l'API Kubernetes
ne permet pas de savoir à quel moment précis.
Les pods doivent donc pouvoir démarrer avec une connectivité réseau différente
de celle attendue. Si vous devez vous assurer que le pod peut joindre certaines destinations
avant de démarrer, vous pouvez utiliser un conteneur d'initialisation
qui attend que ces destinations soient joignables avant que le kubelet ne démarre les conteneurs de l'application.
Chaque NetworkPolicy finira par être appliquée à tous les pods sélectionnés.
Comme le plugin réseau peut mettre en œuvre les NetworkPolicies de manière distribuée,
il est possible que les pods aient une vue légèrement incohérente des politiques réseau
au moment de la création d'un pod, ou quand des pods ou des politiques changent.
Par exemple, un pod nouvellement créé qui doit pouvoir joindre à la fois le Pod A
sur le Nœud 1 et le Pod B sur le Nœud 2 peut constater qu'il joint le Pod A immédiatement,
mais qu'il ne peut joindre le Pod B que quelques secondes plus tard.
NetworkPolicy et pods hostNetwork
Le comportement des NetworkPolicies pour les pods hostNetwork n'est pas défini, mais il devrait se limiter à deux possibilités :
Le plugin réseau sait distinguer le trafic des pods hostNetwork de tout le reste du trafic
(y compris distinguer le trafic de différents pods hostNetwork sur
le même nœud), et applique les NetworkPolicies aux pods hostNetwork comme
aux pods qui utilisent le réseau des pods.
Le plugin réseau ne sait pas distinguer correctement le trafic des pods hostNetwork,
et ignore donc les pods hostNetwork lorsqu'il évalue podSelector et namespaceSelector.
Le trafic depuis et vers les pods hostNetwork est traité comme tout autre trafic depuis et vers l'adresse IP du nœud.
(C'est l'implémentation la plus courante.)
Cela s'applique quand
un pod hostNetwork est sélectionné par spec.podSelector.
...spec:podSelector:matchLabels:role:client...
un pod hostNetwork est sélectionné par un podSelector ou un namespaceSelector dans une règle ingress ou egress.
Par ailleurs, comme les pods hostNetwork ont la même adresse IP que le nœud sur lequel ils s'exécutent,
leurs connexions sont traitées comme des connexions du nœud. Par exemple, vous pouvez autoriser le trafic
venant d'un Pod hostNetwork avec une règle ipBlock.
Ce que les politiques réseau ne permettent pas de faire (du moins, pas encore)
Dans Kubernetes 1.37, les fonctionnalités suivantes n'existent pas dans
l'API NetworkPolicy, mais vous pouvez peut-être les contourner avec des composants du système d'exploitation
(comme SELinux, OpenVSwitch, IPTables, etc.), des technologies de couche 7 (contrôleurs
d'Ingress, implémentations de service mesh) ou des contrôleurs d'admission. Si vous découvrez la
sécurité réseau dans Kubernetes, sachez que les cas d'usage suivants ne peuvent pas (encore) être
mis en œuvre avec l'API NetworkPolicy.
Forcer le trafic interne du cluster à passer par une passerelle commune (un service mesh ou un autre proxy
est sans doute plus adapté).
Tout ce qui touche à TLS (utilisez un service mesh ou un contrôleur d'Ingress pour cela).
Des politiques propres à un nœud (vous pouvez utiliser la notation CIDR, mais vous ne pouvez pas cibler les nœuds
par leur identité Kubernetes).
Cibler des services par leur nom (vous pouvez en revanche cibler des pods ou des namespaces par leurs
labels, ce qui est souvent un bon moyen de contourner le problème).
Créer ou gérer des « demandes de politique » traitées par un tiers.
Des politiques par défaut appliquées à tous les namespaces ou à tous les pods (certains projets et distributions
Kubernetes tiers savent le faire).
Des outils avancés d'interrogation des politiques et d'analyse d'accessibilité.
Journaliser les événements de sécurité réseau (par exemple les connexions bloquées ou acceptées).
Refuser explicitement par une politique (actuellement, le modèle des NetworkPolicies refuse par
défaut et permet seulement d'ajouter des règles d'autorisation).
Empêcher le trafic de loopback ou le trafic entrant venant de l'hôte (les Pods ne peuvent pas, à l'heure actuelle, bloquer l'accès
à localhost, ni bloquer l'accès depuis le nœud sur lequel ils s'exécutent).
Impact des NetworkPolicies sur les connexions existantes
Quand l'ensemble des NetworkPolicies qui s'appliquent à une connexion existante change (parce que les NetworkPolicies
sont modifiées, ou parce que les labels concernés des namespaces ou des pods sélectionnés par la
politique, côté sujet comme côté pairs, changent pendant une connexion existante), c'est
l'implémentation qui détermine si le changement s'applique ou non à cette connexion existante.
Exemple : une politique est créée et refuse une connexion jusque-là autorisée. C'est l'implémentation
du plugin réseau sous-jacent qui détermine si cette nouvelle politique ferme ou non les connexions existantes.
Il est recommandé de ne pas modifier les politiques, les pods ou les namespaces d'une façon qui pourrait affecter les connexions existantes.
Retrouvez des exemples pour des
scénarios courants rendus possibles par la ressource NetworkPolicy.
7 - DNS pour les Services et les Pods
Vos charges de travail peuvent découvrir les Services de votre cluster grâce au DNS ; cette page explique comment cela fonctionne.
Kubernetes crée des enregistrements DNS pour les Services et les Pods. Vous pouvez joindre
les Services avec des noms DNS stables plutôt qu'avec des adresses IP.
Kubernetes publie des informations sur les Pods et les Services, qui servent
à configurer le DNS. Le kubelet configure le DNS des Pods pour que les conteneurs en cours d'exécution
puissent trouver les Services par leur nom plutôt que par leur adresse IP.
Les Services définis dans le cluster reçoivent des noms DNS. Par défaut, la
liste de recherche DNS d'un Pod client contient le namespace du Pod lui-même et le
domaine par défaut du cluster.
Namespaces des Services
Une requête DNS peut renvoyer des résultats différents selon le namespace du Pod qui
l'envoie. Les requêtes DNS qui n'indiquent pas de namespace sont limitées au namespace
du Pod. Pour accéder aux Services d'autres namespaces, indiquez le namespace dans la requête DNS.
Prenons par exemple un Pod dans un namespace test, et un Service data dans
le namespace prod.
Une requête pour data ne renvoie aucun résultat, car elle utilise le namespace test du Pod.
Une requête pour data.prod renvoie le résultat attendu, car elle indique le
namespace.
Les requêtes DNS peuvent être complétées à l'aide du fichier /etc/resolv.conf du Pod. Le kubelet
configure ce fichier pour chaque Pod. Par exemple, une requête pour data seul peut être
complétée en data.test.svc.cluster.local. Ce sont les valeurs de l'option search
qui servent à compléter les requêtes. Pour en savoir plus sur les requêtes DNS, consultez
la page de manuel de resolv.conf.
En résumé, un Pod du namespace test peut résoudre aussi bien
data.prod que data.prod.svc.cluster.local.
Enregistrements DNS
Quels objets reçoivent des enregistrements DNS ?
Les Services
Les Pods
Les sections suivantes décrivent en détail les types d'enregistrements DNS et la structure
pris en charge. Toute autre structure, tout autre nom ou toute autre requête qui se trouverait fonctionner
relève de détails d'implémentation susceptibles de changer sans préavis.
Pour une spécification plus à jour, consultez
Kubernetes DNS-Based Service Discovery.
Services
Enregistrements A/AAAA
Les Services « normaux » (non headless) reçoivent des enregistrements DNS A et/ou AAAA,
selon la ou les familles d'adresses IP du Service, avec un nom de la forme
my-svc.my-namespace.svc.cluster-domain.example. Ce nom est résolu en l'adresse IP de cluster
du Service.
Les Services headless
(sans IP de cluster) reçoivent eux aussi des enregistrements DNS A et/ou AAAA,
avec un nom de la forme my-svc.my-namespace.svc.cluster-domain.example. Contrairement aux Services
normaux, ce nom est résolu en l'ensemble des adresses IP de tous les Pods sélectionnés par le Service.
Les clients sont censés utiliser cet ensemble, ou bien y choisir une adresse
en round-robin standard.
Enregistrements SRV
Des enregistrements SRV sont créés pour les ports nommés des Services normaux ou
headless.
Pour chaque port nommé, l'enregistrement SRV a la forme
_port-name._port-protocol.my-svc.my-namespace.svc.cluster-domain.example.
Pour un Service normal, il est résolu en le numéro de port et le nom de domaine
my-svc.my-namespace.svc.cluster-domain.example.
Pour un Service headless, il est résolu en plusieurs réponses, une pour chaque Pod
sous-jacent au Service. Chaque réponse contient le numéro de port et le nom de domaine du Pod,
de la forme hostname.my-svc.my-namespace.svc.cluster-domain.example.
Pods
Enregistrements A/AAAA
Avant la mise en œuvre de la
spécification DNS,
les versions de Kube-DNS utilisaient la résolution DNS suivante :
Par exemple, si un Pod du namespace default a l'adresse IP 172.17.0.3,
et que le nom de domaine de votre cluster est cluster.local, le Pod a le nom DNS suivant :
172-17-0-3.default.pod.cluster.local
Certains mécanismes DNS de cluster, comme CoreDNS, fournissent aussi des enregistrements A de la forme :
Par exemple, si un Pod du namespace cafe a l'adresse IP 172.17.0.3,
qu'il est un point de terminaison d'un Service nommé barista et que le nom de domaine de votre cluster est
cluster.local, le Pod aura l'enregistrement DNS A suivant, propre au Service.
172-17-0-3.barista.cafe.svc.cluster.local
Champs hostname et subdomain d'un Pod
Actuellement, lorsqu'un Pod est créé, son nom d'hôte (vu depuis l'intérieur du Pod)
est la valeur metadata.name du Pod.
La spec du Pod a un champ facultatif hostname, qui permet d'indiquer un
autre nom d'hôte. Lorsqu'il est renseigné, il prime sur le nom du Pod pour
définir le nom d'hôte du Pod (toujours vu depuis l'intérieur du Pod). Par exemple,
un Pod dont spec.hostname vaut "my-host" aura pour
nom d'hôte "my-host".
La spec du Pod a aussi un champ facultatif subdomain, qui permet d'indiquer
que le Pod fait partie d'un sous-groupe du namespace. Par exemple, un Pod dont spec.hostname
vaut "foo" et spec.subdomain vaut "bar", dans le namespace "my-namespace", aura
pour nom d'hôte "foo" et pour nom de domaine pleinement qualifié (FQDN)
"foo.bar.my-namespace.svc.cluster.local" (là encore, vu depuis l'intérieur
du Pod).
S'il existe un Service headless dans le même namespace que le Pod, avec
le même nom que le sous-domaine, le serveur DNS du cluster renvoie aussi des enregistrements A et/ou AAAA
pour le nom d'hôte pleinement qualifié du Pod.
Exemple :
apiVersion:v1kind:Servicemetadata:name:busybox-subdomainspec:selector:name:busyboxclusterIP:Noneports:- name:foo# name is not required for single-port Servicesport:1234---apiVersion:v1kind:Podmetadata:name:busybox1labels:name:busyboxspec:hostname:busybox-1subdomain:busybox-subdomaincontainers:- image:busybox:1.28command:- sleep- "3600"name:busybox---apiVersion:v1kind:Podmetadata:name:busybox2labels:name:busyboxspec:hostname:busybox-2subdomain:busybox-subdomaincontainers:- image:busybox:1.28command:- sleep- "3600"name:busybox
Avec le Service "busybox-subdomain" ci-dessus et les Pods dont spec.subdomain
vaut "busybox-subdomain", le premier Pod verra
"busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example" comme son propre FQDN. Le DNS fournit
des enregistrements A et/ou AAAA pour ce nom, qui pointent vers l'adresse IP du Pod. Les deux Pods « busybox1 » et
« busybox2 » auront chacun leurs propres enregistrements d'adresse.
Un EndpointSlice peut indiquer
le nom d'hôte DNS de n'importe quelle adresse de point de terminaison, avec son adresse IP.
Note:
Aucun enregistrement A ou AAAA n'est créé pour les noms de Pods si le Pod n'a pas de hostname.
Pour un Pod sans hostname mais avec un subdomain, seul
l'enregistrement A ou AAAA du Service headless (busybox-subdomain.my-namespace.svc.cluster-domain.example)
est créé ; il pointe vers les adresses IP des Pods. Par ailleurs, le Pod doit être prêt (ready) pour avoir un
enregistrement, sauf si publishNotReadyAddresses=True est défini sur le Service.
Champ setHostnameAsFQDN d'un Pod
Feature state:Stable since Kubernetes v1.22
Lorsqu'un Pod est configuré pour avoir un nom de domaine pleinement qualifié (FQDN), son
nom d'hôte est le nom d'hôte court. Par exemple, pour un Pod dont le nom de domaine
pleinement qualifié est busybox-1.busybox-subdomain.my-namespace.svc.cluster-domain.example,
la commande hostname exécutée dans ce Pod renvoie par défaut busybox-1, et la
commande hostname --fqdn renvoie le FQDN.
Lorsque vous définissez setHostnameAsFQDN: true dans la spec du Pod, le kubelet écrit le FQDN du Pod
comme nom d'hôte dans le namespace de ce Pod. Dans ce cas, hostname et hostname --fqdn
renvoient tous les deux le FQDN du Pod.
Note:
Sous Linux, le champ hostname du noyau (le champ nodename de struct utsname) est limité à 64 caractères.
Si un Pod active cette fonctionnalité et que son FQDN dépasse 64 caractères, il ne pourra pas démarrer.
Le Pod restera à l'état Pending (ContainerCreating dans kubectl) et générera
des événements d'erreur, comme Failed to construct FQDN from Pod hostname and cluster domain,
FQDN long-FQDN is too long (64 characters is the max, 70 characters requested).
Pour améliorer l'expérience utilisateur dans ce cas, vous pouvez créer un
contrôleur de webhook d'admission
qui vérifie la taille du FQDN lorsque les utilisateurs créent des objets de premier niveau, par exemple un Deployment.
Politique DNS d'un Pod
Les politiques DNS se définissent Pod par Pod. Actuellement, Kubernetes prend en charge
les politiques DNS suivantes pour les Pods. Elles sont indiquées dans le
champ dnsPolicy de la spec du Pod.
« Default » : le Pod hérite de la configuration de résolution de noms du nœud
sur lequel il s'exécute.
Consultez la discussion à ce sujet
pour plus de détails.
« ClusterFirst » : toute requête DNS qui ne correspond pas au suffixe de domaine configuré
pour le cluster, comme « www.kubernetes.io », est transmise par le serveur DNS à un serveur
de noms en amont. Les administrateurs du cluster peuvent avoir configuré des serveurs DNS supplémentaires,
pour des domaines de délégation (stub domains) ou en amont.
Consultez la discussion à ce sujet
pour savoir comment les requêtes DNS sont traitées dans ces cas.
« ClusterFirstWithHostNet » : pour les Pods qui s'exécutent avec hostNetwork, il faut
régler explicitement leur politique DNS sur « ClusterFirstWithHostNet ». Sinon, les Pods
qui s'exécutent avec hostNetwork et "ClusterFirst" se comporteront comme
avec la politique "Default".
Note:
Ce n'est pas pris en charge sous Windows. Pour plus de détails, voir ci-dessous.
« None » : permet à un Pod d'ignorer les paramètres DNS de l'environnement
Kubernetes. Tous les paramètres DNS sont alors censés être fournis par le
champ dnsConfig de la spec du Pod.
Consultez la sous-section Configuration DNS d'un Pod ci-dessous.
Note:
« Default » n'est pas la politique DNS par défaut. Si dnsPolicy n'est pas
indiqué explicitement, c'est « ClusterFirst » qui est utilisé.
L'exemple ci-dessous montre un Pod dont la politique DNS est
« ClusterFirstWithHostNet », car son champ hostNetwork vaut true.
La configuration DNS d'un Pod donne aux utilisateurs plus de contrôle sur les paramètres DNS de ce Pod.
Le champ dnsConfig est facultatif et fonctionne avec n'importe quelle valeur de dnsPolicy.
En revanche, lorsque le dnsPolicy d'un Pod vaut « None », le champ dnsConfig doit
être renseigné.
Voici les propriétés qu'un utilisateur peut indiquer dans le champ dnsConfig :
nameservers : une liste d'adresses IP qui serviront de serveurs DNS au
Pod. On peut indiquer au maximum 3 adresses IP. Lorsque le dnsPolicy du Pod
vaut « None », la liste doit contenir au moins une adresse IP ; dans les autres cas,
cette propriété est facultative.
Les serveurs indiqués sont ajoutés aux serveurs de noms de base générés à partir de la
politique DNS choisie, les adresses en double étant supprimées.
searches : une liste de domaines de recherche DNS pour la résolution des noms d'hôte dans le Pod.
Cette propriété est facultative. Si elle est renseignée, la liste fournie est fusionnée
avec les domaines de recherche de base générés à partir de la politique DNS choisie.
Les noms de domaine en double sont supprimés.
Kubernetes accepte jusqu'à 32 domaines de recherche.
options : une liste facultative d'objets, dont chacun peut avoir une propriété name
(obligatoire) et une propriété value (facultative). Le contenu de cette
propriété est fusionné avec les options générées à partir de la politique DNS choisie.
Les entrées en double sont supprimées.
Voici un exemple de Pod avec des paramètres DNS personnalisés :
apiVersion:v1kind:Podmetadata:namespace:defaultname:dns-examplespec:containers:- name:testimage:nginxdnsPolicy:"None"dnsConfig:nameservers:- 192.0.2.1# this is an examplesearches:- ns1.svc.cluster-domain.example- my.dns.search.suffixoptions:- name:ndotsvalue:"2"- name:edns0
Une fois le Pod ci-dessus créé, le fichier /etc/resolv.conf du conteneur test
a le contenu suivant :
Kubernetes lui-même ne limite la configuration DNS que lorsque la liste des domaines de recherche
dépasse 32 éléments, ou que la longueur totale de tous les domaines de recherche dépasse 2048.
Cette limite s'applique respectivement au fichier de configuration du résolveur du nœud, à la configuration DNS
du Pod et à la configuration DNS fusionnée.
Note:
Les anciennes versions de certains environnements d'exécution de conteneurs peuvent imposer leurs propres restrictions
sur le nombre de domaines de recherche DNS. Selon l'environnement d'exécution
de conteneurs, les Pods qui ont beaucoup de domaines de recherche DNS peuvent rester bloqués
à l'état Pending.
Ce problème est connu pour containerd v1.5.5 et versions antérieures, ainsi que pour
CRI-O v1.21 et versions antérieures.
Résolution DNS sur les nœuds Windows
ClusterFirstWithHostNet n'est pas pris en charge pour les Pods qui s'exécutent sur des nœuds Windows.
Windows considère tout nom qui contient un . comme un FQDN et ne fait pas de résolution FQDN.
Sous Windows, plusieurs résolveurs DNS peuvent être utilisés. Comme leurs
comportements diffèrent légèrement, il est recommandé d'utiliser la
cmdlet PowerShell Resolve-DNSName
pour résoudre les noms.
Sous Linux, vous disposez d'une liste de suffixes DNS, utilisée lorsque la résolution d'un nom
en tant que nom pleinement qualifié a échoué.
Sous Windows, vous ne pouvez avoir qu'un seul suffixe DNS : celui associé au
namespace du Pod (par exemple mydns.svc.cluster.local). Windows peut résoudre les FQDN, les Services
ou les noms réseau résolubles avec ce seul suffixe. Par exemple, un Pod lancé
dans le namespace default aura le suffixe DNS default.svc.cluster.local.
Dans un Pod Windows, vous pouvez résoudre à la fois kubernetes.default.svc.cluster.local
et kubernetes, mais pas les noms partiellement qualifiés (kubernetes.default ou
kubernetes.default.svc).
Le routage tenant compte de la topologie (Topology Aware Routing) fournit un mécanisme qui aide à garder le trafic réseau dans sa zone d'origine. Privilégier le trafic dans la même zone entre les Pods de votre cluster peut améliorer la fiabilité, les performances (latence et débit réseau) ou réduire les coûts.
Feature state:Beta since Kubernetes v1.23
Note:
Avant Kubernetes 1.27, cette fonctionnalité s'appelait Topology Aware Hints.
Le routage tenant compte de la topologie adapte le comportement du routage pour
garder de préférence le trafic dans sa zone d'origine. Dans certains cas,
cela peut réduire les coûts ou améliorer les performances réseau.
Motivation
Les clusters Kubernetes sont de plus en plus souvent déployés dans des
environnements multizones. Le routage tenant compte de la topologie fournit un
mécanisme qui aide à garder le trafic dans sa zone d'origine. Lorsqu'il
calcule les points de terminaison d'un Service, le contrôleur EndpointSlice tient compte
de la topologie (région et zone) de chaque point de terminaison et renseigne le
champ hints (indications) pour l'attribuer à une zone. Les composants du
cluster, comme kube-proxy, peuvent ensuite utiliser ces
indications pour orienter le routage du trafic (en privilégiant les points de
terminaison topologiquement les plus proches).
Activer le routage tenant compte de la topologie
Note:
Avant Kubernetes 1.27, ce comportement était contrôlé par l'annotation
service.kubernetes.io/topology-aware-hints.
Vous pouvez activer le routage tenant compte de la topologie pour un Service en
définissant l'annotation service.kubernetes.io/topology-mode sur Auto.
Lorsque chaque zone dispose de suffisamment de points de terminaison
disponibles, des indications de topologie sont ajoutées aux EndpointSlices pour attribuer chaque
point de terminaison à une zone précise. Le trafic est alors acheminé plus près
de son origine.
Quand cela fonctionne le mieux
Cette fonctionnalité donne les meilleurs résultats lorsque :
1. Le trafic entrant est réparti uniformément
Si une grande partie du trafic provient d'une seule zone, ce trafic risque de
surcharger le sous-ensemble de points de terminaison attribués à cette zone.
Cette fonctionnalité est déconseillée lorsque le trafic entrant est censé
provenir d'une seule zone.
2. Le Service a au moins 3 points de terminaison par zone
Dans un cluster à trois zones, cela représente au moins 9 points de terminaison.
Avec moins de 3 points de terminaison par zone, il y a une forte probabilité
(environ 50 %) que le contrôleur EndpointSlice ne parvienne pas à répartir les
points de terminaison de manière équilibrée et se rabatte sur le routage par
défaut à l'échelle du cluster.
Fonctionnement
L'heuristique « Auto » tente d'attribuer à chaque zone un nombre de points de
terminaison proportionnel. Cette heuristique donne de meilleurs résultats pour
les Services qui ont un nombre important de points de terminaison.
Contrôleur EndpointSlice
Le contrôleur EndpointSlice est chargé de définir les indications sur les
EndpointSlices lorsque cette heuristique est activée. Le contrôleur attribue à
chaque zone une part proportionnelle des points de terminaison. Cette proportion
dépend du nombre de cœurs CPU
allouables
des nœuds de cette zone. Par exemple, si une zone dispose de 2 cœurs CPU et
une autre d'un seul, le contrôleur attribuera deux fois plus de points de
terminaison à la zone qui dispose de 2 cœurs.
L'exemple suivant montre un EndpointSlice dont les indications ont été
renseignées :
Le composant kube-proxy filtre les points de terminaison vers lesquels il
achemine le trafic en fonction des indications définies par le contrôleur EndpointSlice. Dans
la plupart des cas, kube-proxy peut ainsi acheminer le trafic vers des points de
terminaison de la même zone. Il arrive que le contrôleur attribue des points de
terminaison d'une autre zone pour mieux équilibrer leur répartition entre les
zones. Une partie du trafic est alors acheminée vers d'autres zones.
Garde-fous
Le plan de contrôle de Kubernetes et le kube-proxy de chaque nœud appliquent
certains garde-fous avant d'utiliser les indications de topologie. Si
l'un d'eux n'est pas respecté, kube-proxy choisit des points de terminaison
n'importe où dans le cluster, quelle que soit la zone.
Nombre insuffisant de points de terminaison : s'il y a moins de points de
terminaison que de zones dans le cluster, le contrôleur n'attribue aucune
indication.
Répartition équilibrée impossible : dans certains cas, il est impossible
de répartir les points de terminaison de manière équilibrée entre les zones.
Par exemple, si la zone-a est deux fois plus grande que la zone-b mais qu'il
n'y a que 2 points de terminaison, celui attribué à la zone-a risque de
recevoir deux fois plus de trafic que celui de la zone-b. Le contrôleur
n'attribue pas d'indications s'il ne parvient pas à ramener cette valeur de
« surcharge estimée » sous un seuil acceptable pour chaque zone. À noter :
ce calcul ne repose pas sur des mesures en temps réel. Un point de
terminaison peut toujours se retrouver surchargé.
Informations insuffisantes sur un ou plusieurs nœuds : si un nœud n'a pas
de label topology.kubernetes.io/zone ou ne remonte pas de valeur de CPU
allouable, le plan de contrôle ne définit aucune indication de topologie sur
les points de terminaison, et kube-proxy ne filtre donc pas les points de
terminaison par zone.
Un ou plusieurs points de terminaison n'ont pas d'indication de zone :
kube-proxy considère alors qu'un passage aux indications de topologie, ou
leur abandon, est en cours. Filtrer les points de terminaison d'un Service
dans cet état serait risqué : kube-proxy se rabat donc sur tous les points de
terminaison.
Une zone n'apparaît dans aucune indication : si kube-proxy ne trouve
aucun point de terminaison dont l'indication désigne la zone dans laquelle il
s'exécute, il utilise les points de terminaison de toutes les zones. Cette
situation se produit surtout lorsque vous ajoutez une nouvelle zone à un
cluster existant.
Contraintes
Les indications de topologie ne sont pas utilisées lorsque internalTrafficPolicy
vaut Local sur un Service. Les deux fonctionnalités peuvent coexister dans un
même cluster sur des Services différents, mais pas sur le même Service.
Cette approche fonctionne mal pour les Services dont une grande partie du
trafic provient d'un sous-ensemble de zones. Elle suppose au contraire que le
trafic entrant est à peu près proportionnel à la capacité des nœuds de chaque
zone.
Le contrôleur EndpointSlice ignore les nœuds qui ne sont pas prêts lorsqu'il
calcule la part de chaque zone. Cela peut avoir des conséquences inattendues
si une grande partie des nœuds ne sont pas prêts.
Le contrôleur EndpointSlice ignore les nœuds qui portent le label
node-role.kubernetes.io/control-plane ou node-role.kubernetes.io/master.
Cela peut poser problème si des charges de travail s'exécutent aussi sur ces
nœuds.
Le contrôleur EndpointSlice ne tient pas compte des tolérances lors du déploiement ni lors du
calcul de la part de chaque zone. Si les Pods d'un Service sont limités à un
sous-ensemble des nœuds du cluster, cela n'est pas pris en compte.
Cela peut mal fonctionner avec la mise à l'échelle automatique. Par exemple,
si une grande partie du trafic provient d'une seule zone, seuls les points de terminaison attribués
à cette zone traiteront ce trafic. Il se peut alors que l'Horizontal Pod Autoscaler ne
détecte pas cette situation, ou que les nouveaux pods démarrent dans une autre
zone.
Heuristiques personnalisées
Kubernetes est déployé de bien des façons, et aucune heuristique unique
d'attribution des points de terminaison aux zones ne convient à tous les cas
d'usage. L'un des principaux objectifs de cette fonctionnalité est de permettre
le développement d'heuristiques personnalisées lorsque l'heuristique intégrée ne
convient pas à votre cas d'usage. Les premiers éléments permettant des
heuristiques personnalisées ont été intégrés dans la version 1.27. Il s'agit
d'une implémentation limitée, qui ne couvre peut-être pas encore certaines
situations pertinentes et plausibles.
Découvrir le champ
trafficDistribution,
étroitement lié à l'annotation service.kubernetes.io/topology-mode, qui offre
des options souples pour le routage du trafic dans Kubernetes.
9 - Allocation des ClusterIP des Services
Dans Kubernetes, les Services sont un moyen abstrait
d'exposer une application qui s'exécute sur un ensemble de Pods. Les Services
peuvent disposer d'une adresse IP virtuelle à l'échelle du cluster (avec un Service de type: ClusterIP).
Les clients peuvent se connecter à cette adresse IP virtuelle, et Kubernetes répartit alors
le trafic destiné à ce Service entre les différents Pods sous-jacents.
Comment les ClusterIP des Services sont-elles allouées ?
Lorsque Kubernetes doit attribuer une adresse IP virtuelle à un Service,
cette attribution se fait de l'une des deux manières suivantes :
dynamiquement
le plan de contrôle du cluster choisit automatiquement une adresse IP libre dans la plage configurée pour les Services de type: ClusterIP.
statiquement
vous indiquez l'adresse IP de votre choix, dans la plage configurée pour les Services.
Dans tout le cluster, chaque ClusterIP de Service doit être unique.
Tenter de créer un Service avec une ClusterIP précise qui a déjà
été allouée renvoie une erreur.
Pourquoi réserver des ClusterIP des Services ?
Il peut arriver que vous souhaitiez que des Services soient joignables à des adresses IP bien connues, afin que
d'autres composants et utilisateurs du cluster puissent les utiliser.
Le meilleur exemple est le Service DNS du cluster. Par convention informelle, certains outils d'installation de Kubernetes attribuent la 10e adresse IP
de la plage des Services au Service DNS. Si vous avez configuré votre cluster avec la plage d'adresses IP des Services
10.96.0.0/16 et que vous voulez que l'adresse IP de votre Service DNS soit 10.96.0.10, il vous faudrait créer un Service comme
celui-ci :
Mais, comme expliqué précédemment, l'adresse IP 10.96.0.10 n'a pas été réservée.
Si d'autres Services sont créés avec une allocation dynamique avant lui ou en même temps que lui, l'un d'eux risque de se voir attribuer cette adresse IP.
Vous ne pourrez alors pas créer le Service DNS, car sa création échouera avec une erreur de conflit.
Comment éviter les conflits de ClusterIP des Services ?
La stratégie d'allocation mise en œuvre dans Kubernetes pour attribuer des ClusterIP aux Services réduit le
risque de collision.
La plage de ClusterIP est divisée selon la formule min(max(16, cidrSize / 16), 256),
que l'on peut décrire ainsi : jamais moins de 16 ni plus de 256, avec une progression graduelle entre les deux.
L'attribution dynamique d'adresses IP puise par défaut dans la bande supérieure ; une fois celle-ci épuisée, elle
puise dans la bande inférieure. Les utilisateurs peuvent ainsi recourir à des allocations statiques dans la bande inférieure avec un faible
risque de collision.
Exemples
Exemple 1
Cet exemple utilise la plage d'adresses IP 10.96.0.0/24 (notation CIDR) pour les adresses IP
des Services.
Taille de la plage : 28 - 2 = 254 Décalage de la bande : min(max(16, 256/16), 256) = min(16, 256) = 16 Début de la bande statique : 10.96.0.1 Fin de la bande statique : 10.96.0.16 Fin de la plage : 10.96.0.254
pie showData
title 10.96.0.0/24
"Statique" : 16
"Dynamique" : 238
Exemple 2
Cet exemple utilise la plage d'adresses IP 10.96.0.0/20 (notation CIDR) pour les adresses IP
des Services.
Taille de la plage : 212 - 2 = 4094 Décalage de la bande : min(max(16, 4096/16), 256) = min(256, 256) = 256 Début de la bande statique : 10.96.0.1 Fin de la bande statique : 10.96.1.0 Fin de la plage : 10.96.15.254
pie showData
title 10.96.0.0/20
"Statique" : 256
"Dynamique" : 3838
Exemple 3
Cet exemple utilise la plage d'adresses IP 10.96.0.0/16 (notation CIDR) pour les adresses IP
des Services.
Taille de la plage : 216 - 2 = 65534 Décalage de la bande : min(max(16, 65536/16), 256) = min(4096, 256) = 256 Début de la bande statique : 10.96.0.1 Fin de la bande statique : 10.96.1.0 Fin de la plage : 10.96.255.254
pie showData
title 10.96.0.0/16
"Statique" : 256
"Dynamique" : 65278
Si deux Pods de votre cluster veulent communiquer et qu'ils s'exécutent effectivement tous les deux sur le même nœud, utilisez la politique de trafic interne des Services pour que le trafic réseau reste sur ce nœud. Éviter un aller-retour par le réseau du cluster peut contribuer à la fiabilité, aux performances (latence et débit réseau) ou à la réduction des coûts.
Feature state:Stable since Kubernetes v1.26
La politique de trafic interne des Services (Service Internal Traffic Policy)
permet de restreindre le trafic interne afin qu'il ne soit acheminé que vers les
points de terminaison situés sur le nœud d'où provient ce trafic. Le trafic
« interne » désigne ici le trafic émis par les Pods du cluster courant. Cela peut
aider à réduire les coûts et à améliorer les performances.
Utiliser la politique de trafic interne des Services
Vous pouvez activer la politique de trafic « interne uniquement » pour un
Service en définissant son champ
.spec.internalTrafficPolicy sur Local. Cela indique à kube-proxy de n'utiliser
que les points de terminaison locaux au nœud pour le trafic interne au cluster.
Note:
Pour les Pods situés sur des nœuds qui n'ont aucun point de terminaison pour un
Service donné, le Service se comporte comme s'il n'avait aucun point de terminaison
(pour les Pods de ce nœud), même s'il en possède bel et bien sur d'autres nœuds.
L'exemple suivant montre un Service dont le champ
.spec.internalTrafficPolicy est défini sur Local :
kube-proxy filtre les points de terminaison vers lesquels il achemine le trafic en
fonction du paramètre spec.internalTrafficPolicy. Lorsqu'il vaut Local, seuls
les points de terminaison locaux au nœud sont pris en compte. Lorsqu'il vaut
Cluster (la valeur par défaut) ou qu'il n'est pas défini, Kubernetes prend en
compte tous les points de terminaison.