Version imprimable multipages. Cliquer ici pour imprimer.
Services, Equilibreur de charge, et Réseau
1 - EndpointSlices
Kubernetes v1.17 [beta]
EndpointSlices offrent une méthode simple pour suivre les Endpoints d'un réseau au sein d'un cluster de Kubernetes. Ils offrent une alternative plus évolutive et extensible aux Endpoints.
Ressource pour EndpointSlice
Dans Kubernetes, un EndpointSlice contient des références à un ensemble de Endpoints. Le controleur d'EndpointSlice crée automatiquement des EndpointSlices pour un Service quand un sélecteur est spécifié. Ces EndpointSlices vont inclure des références à n'importe quels Pods qui correspondent aux selecteurs de Service. EndpointSlices groupent ensemble les Endpoints d'un réseau par combinaisons uniques de Services et de Ports.
Par exemple, voici un échantillon d'une ressource EndpointSlice pour le Kubernetes Service exemple
.
apiVersion: discovery.k8s.io/v1beta1
kind: EndpointSlice
metadata:
name: exemple-abc
labels:
kubernetes.io/service-name: exemple
addressType: IPv4
ports:
- name: http
protocol: TCP
port: 80
endpoints:
- addresses:
- "10.1.2.3"
conditions:
ready: true
hostname: pod-1
topology:
kubernetes.io/hostname: node-1
topology.kubernetes.io/zone: us-west2-a
Les EndpointSlices gérés par le contrôleur d'EndpointSlice n'auront, par défaut, pas plus de 100 Endpoints chacun. En dessous de cette échelle, EndpointSlices devraient mapper 1:1 les Endpoints et les Services et devraient avoir une performance similaire.
EndpointSlices peuvent agir en tant que source de vérité pour kube-proxy quand il s'agit du routage d'un trafic interne. Lorsqu'ils sont activés, ils devraient offrir une amélioration de performance pour les services qui ont une grand quantité d'Endpoints.
Types d'addresses
Les EndpointSlices supportent 3 types d'addresses :
- IPv4
- IPv6
- FQDN (Fully Qualified Domain Name) - [nom de domaine entièrement qualifié]
Topologie
Chaque Endpoint dans un EndpointSlice peut contenir des informations de topologie pertinentes. Ceci est utilisé pour indiquer où se trouve un Endpoint, qui contient les informations sur le Node, zone et région correspondantes. Lorsque les valeurs sont disponibles, les labels de Topologies suivants seront définis par le contrôleur EndpointSlice:
kubernetes.io/hostname
- Nom du Node sur lequel l'Endpoint se situe.topology.kubernetes.io/zone
- Zone dans laquelle l'Endpoint se situe.topology.kubernetes.io/region
- Région dans laquelle l'Endpoint se situe.
Le contrôleur EndpointSlice surveille les Services et les Pods pour assurer que leurs correspondances avec les EndpointSlices sont à jour. Le contrôleur gère les EndpointSlices pour tous les Services qui ont un sélecteur - [référence: sélecteur] - specifié. Celles-ci représenteront les IPs des Pods qui correspondent au sélecteur.
Capacité d'EndpointSlices
Les EndpointSlices sont limités à une capacité de 100 Endpoints chacun, par défaut. Vous pouvez configurer ceci avec l'indicateur --max-endpoints-per-slice
kube-controller-manager jusqu'à un maximum de 1000.
Distribution d'EndpointSlices
Chaque EndpointSlice a un ensemble de ports qui s'applique à tous les Endpoints dans la ressource. Lorsque les ports nommés sont utilisés pour un Service, les Pods peuvent se retrouver avec différents ports cibles pour le même port nommé, nécessitant différents EndpointSlices.
Le contrôleur essaie de remplir les EndpointSlices aussi complètement que possible, mais ne les rééquilibre pas activement. La logique du contrôleur est assez simple:
- Itérer à travers les EndpointSlices existants, retirer les Endpoints qui ne sont plus voulus et mettre à jour les Endpoints qui ont changé.
- Itérer à travers les EndpointSlices qui ont été modifiés dans la première étape et les remplir avec n'importe quel Endpoint nécéssaire.
- S'il reste encore des Endpoints nouveaux à ajouter, essayez de les mettre dans une slice qui n'a pas été changée et/ou en créer une nouvelle.
Par-dessus tout, la troisième étape priorise la limitation de mises à jour d'EndpointSlice sur une distribution complètement pleine d'EndpointSlices. Par exemple, s'il y avait 10 nouveaux Endpoints à ajouter et 2 EndpointSlices qui peuvent contenir 5 Endpoints en plus chacun; cette approche créera un nouveau EndpointSlice au lieu de remplir les EndpointSlice existants. C'est à dire, une seule création EndpointSlice est préférable à plusieurs mises à jour d'EndpointSlices.
Avec kube-proxy exécuté sur chaque Node et surveillant EndpointSlices, chaque changement d'un EndpointSlice devient relativement coûteux puisqu'ils seront transmis à chaque Node du cluster. Cette approche vise à limiter le nombre de modifications qui doivent être envoyées à chaque Node, même si ça peut causer plusieurs EndpointSlices non remplis.
En pratique, cette distribution bien peu idéale devrait être rare. La plupart des changements traités par le contrôleur EndpointSlice seront suffisamment petits pour tenir dans un EndpointSlice existant, et sinon, un nouveau EndpointSlice aurait probablement été bientôt nécessaire de toute façon. Les mises à jour continues des déploiements fournissent également une compaction naturelle des EndpointSlices avec tous leurs pods et les Endpoints correspondants qui se feront remplacer.
Motivation
L'API des Endpoints fournit une méthode simple et facile à suivre pour les Endpoints dans Kubernetes. Malheureusement, comme les clusters Kubernetes et Services sont devenus plus grands, les limitations de cette API sont devenues plus visibles. Plus particulièrement, celles-ci comprennent des limitations liées au dimensionnement vers un plus grand nombre d'Endpoints d'un réseau.
Puisque tous les Endpoints d'un réseau pour un Service ont été stockés dans une seule ressource Endpoints, ces ressources pourraient devenir assez lourdes. Cela affecte les performances des composants Kubernetes (notamment le plan de contrôle) et cause une grande quantité de trafic réseau et de traitements lorsque les Endpoints changent. Les EndpointSlices aident à atténuer ces problèmes ainsi qu'à fournir une plate-forme extensible pour des fonctionnalités supplémentaires telles que le routage topologique.
A suivre
2 - Service
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=MyApp
:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
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=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".
port
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:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
É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:
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- ip: 192.0.2.42
ports:
- port: 9376
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
Kubernetes v1.17 [beta]
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
Kubernetes v1.11 [stable]
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-robinlc
: least connection (plus petit nombre de connexions ouvertes)dh
: destination hashingsh
: source hashingsed
: shortest expected delaynq
: never queue
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:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
- name: https
protocol: TCP
port: 443
targetPort: 9377
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:
REDIS_MASTER_SERVICE_HOST=10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
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 duServiceType
par défaut.NodePort
: Expose le service sur l'IP de chaque nœud sur un port statique (leNodePort
). Un serviceClusterIP
, vers lequel le serviceNodePort
est automatiquement créé. Vous pourrez contacter le serviceNodePort
, 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 servicesNodePort
etClusterIP
, vers lesquels les itinéraires de l'équilibreur de charge externe, sont automatiquement créés.ExternalName
: Mappe le service au contenu du champexternalName
(par exemplefoo.bar.example.com
), en renvoyant un enregistrementCNAME
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 typeExternalName
.
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,
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:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 192.0.2.127
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é.
LoadBalancer
.
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
.
Spécifiez l'adresse IP attribuée en tant que loadBalancerIP.
Assurez-vous d'avoir mis à jour le securityGroupName dans le fichier de configuration du fournisseur de cloud.
Pour plus d'informations sur le dépannage CreatingLoadBalancerFailed
relatif aux permissions consultez: Use a static IP address with the Azure Kubernetes Service (AKS) load balancer ou CreatingLoadBalancerFailed on AKS cluster with advanced networking.
Load Balancer interne
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.
Sélectionnez l'un des onglets.
[...]
metadata:
name: my-service
annotations:
cloud.google.com/load-balancer-type: "Internal"
[...]
[...]
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
[...]
[...]
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
[...]
[...]
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/openstack-internal-load-balancer: "true"
[...]
[...]
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/cce-load-balancer-internal-vpc: "true"
[...]
[...]
metadata:
annotations:
service.kubernetes.io/qcloud-loadbalancer-internal-subnetid: subnet-xxxxx
[...]
Prise en charge TLS sur AWS
Pour une prise en charge partielle de TLS / SSL sur des clusters exécutés sur AWS, vous pouvez ajouter trois annotations à un service LoadBalancer
:
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012
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.
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: (https|http|ssl|tcp)
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:
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443,8443"
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
:
aws elb describe-load-balancer-policies --query 'PolicyDescriptions[].PolicyName'
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:
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: "ELBSecurityPolicy-TLS-1-2-2017-01"
Prise en charge du protocole PROXY sur AWS
Pour activer protocole PROXY prise en charge des clusters exécutés sur AWS, vous pouvez utiliser l'annotation de service suivante:
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
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-service
annotations:
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 balancer
service.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és
service.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.
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true"
service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout: "60"
Autres annotations ELB
Il existe d'autres annotations pour gérer les Elastic Load Balancers décrits ci-dessous.
metadata:
name: my-service
annotations:
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 balancer
service.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 balancer
service.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 10
service.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 10
service.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 300
service.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 60
service.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
Kubernetes v1.15 [beta]
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
.
metadata:
name: my-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
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"
.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-service
annotations:
# Lier des load balancers avec des nœuds spécifiques
service.kubernetes.io/qcloud-loadbalancer-backends-label: key in (value1, value2)
# ID d'un load balancer existant
service.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 LB
service.kubernetes.io/service.extensiveParameters: ""
# Paramètres personnalisés pour le listener LB
service.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
:
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
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.
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é.
IP externes
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 "80.11.12.10:80
" (externalIP:port
)
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
externalIPs:
- 80.11.12.10
Lacunes
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
Kubernetes v1.0 [stable]
Vous pouvez utiliser TCP pour tout type de service, et c'est le protocole réseau par défaut.
UDP
Kubernetes v1.0 [stable]
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
Kubernetes v1.1 [stable]
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.
Protocole PROXY
Kubernetes v1.1 [stable]
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
Kubernetes v1.12 [alpha]
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
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
Windows
Userspace kube-proxy
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.
A suivre
- Voir Connecting Applications with Services
- Voir Ingress
- Voir Endpoint Slices
3 - DNS pour les services et les pods
Cette page fournit une vue d'ensemble du support DNS par Kubernetes.
Introduction
Kubernetes planifie un pod et un service DNS sur le cluster et configure les kubelets pour indiquer à chaque conteneur d'utiliser l'adresse IP du service DNS pour résoudre les noms DNS.
Quels composants obtiennent des noms DNS?
Chaque service défini dans le cluster (y compris le serveur DNS lui-même) a un nom DNS. Par défaut, la liste de recherche DNS du client d'un pod inclura le namespace (espace de nommage) du pod et le domaine par défaut du cluster. C'est mieux illustré par un exemple :
Supposons un service nommé foo
dans le namespace Kubernetes bar
. Un pod en cours d'exécution dans le namespace bar
peut rechercher ce service en faisant simplement une requête DNS "foo". Un pod qui tourne dans le namespace quux
peut rechercher ce service en effectuant une requête DNS foo.bar
.
Les sections suivantes détaillent les types d’enregistrement et la structure supportée par Kubernetes. Toute autre structure ou noms ou requêtes qui fonctionnent sont considérés comme des détails d'implémentation et peuvent changer sans préavis. Pour une spécification plus à jour, voir Découverte des services basée sur le DNS Kubernetes.
Services
Enregistrement A
Les services "normaux" (pas sans en-tête) se voient attribuer un enregistrement DNS A, et ont un nom sous la forme : mon-service.mon-namespace.svc.cluster.local
. La résolution de ce nom donne l'adresse ClusterIP
du service.
Les Services "Headless" (ou sans en-tête, c'est à dire sans ClusterIP) auront également un enregistrement type A, donc un nom sous la forme : mon-service.mon-namespace.svc.cluster.local
. Contrairement aux Services Normaux, cela résout l'ensemble des adresses IP des pods sélectionnés par le Service.
On s'attend à ce que les clients consomment l'ensemble ou utilisent le standard de sélection round-robin de l'ensemble.
Enregistrement SRV
Les enregistrements SRV sont créés pour les ports nommés faisant partie des services normaux ou Headless (sans en-tête).
Pour chaque port nommé, l'enregistrement SRV aurait la forme
_mon-nom-de-port._mon-protocole-de-port.mon-service.mon-namespace.svc.cluster.local
.
Pour un service régulier, cela se traduit par le numéro de port et le nom de domaine :
mon-service.mon-namespace.svc.cluster.local
.
Pour un service sans en-tête, cela pourrait être résolu en plusieurs réponses, une réponse pour chaque pod lié à ce service et qui contient le numéro de port, ainsi le nom de domaine du pod est sous la forme nom-auto-genere.mon-service.mon-namespace.svc.cluster.local
.
Pods
Enregistrement A
Lorsque cette option est activée, un enregistrement DNS A est attribué aux pods sous la forme adresse-ip-du-pod.mon-namespace.pod.cluster.local
.
Par exemple, un pod avec l’IP 1.2.3.4
dans le namespace (espace de nommage) default
avec un nom DNS de cluster.local
aurait une entrée : 1-2-3-4.default.pod.cluster.local
.
Nom d'hôte et sous-domaine d'un pod
Actuellement, lorsqu'un pod est créé, son nom d'hôte a la valeur metadata.name
du pod.
La spécification du pod a un champ optionnel hostname
, qui peut être utilisé pour spécifier la valeur du nom d'hôte du pod. Quand c'est spécifié, ce dernier a la priorité sur le nom du pod. Par exemple, si un pod a un hostname
ayant la valeur "mon-hote
", son nom d'hôte sera "mon-hote
".
La spécification du pod a également un champ optionnel subdomain
qui peut être utilisé pour spécifier son sous-domaine. Par exemple, un pod avec une valeur "foo
" du champ hostname
et une valeur "bar
" du champ subdomain
, dans le namespace "mon-namespace
", aura un nom de domaine (FQDN) "foo.bar.mon-namespace.svc.cluster.local
".
Exemple :
apiVersion: v1
kind: Service
metadata:
name: sous-domaine-par-default
spec:
selector:
name: busybox
clusterIP: None
ports:
- name: foo # En vrai, cette définition de port est à titre d'exemple, nous n'avons pas vraiment besoin de ports pour cette application.
port: 1234
targetPort: 1234
---
apiVersion: v1
kind: Pod
metadata:
name: busybox1
labels:
name: busybox
spec:
hostname: busybox-1
subdomain: sous-domaine-par-default
containers:
- image: busybox:1.28
command:
- sleep
- "3600"
name: busybox
---
apiVersion: v1
kind: Pod
metadata:
name: busybox2
labels:
name: busybox
spec:
hostname: busybox-2
subdomain: sous-domaine-par-default
containers:
- image: busybox:1.28
command:
- sleep
- "3600"
name: busybox
Si un service sans en-tête (headless) est dans le même namespace que son pod et avec le même nom que le sous-domaine, le serveur KubeDNS du cluster renvoie également un enregistrement A pour le nom d’hôte (hostname) du pod.
Par exemple, si un pod dont le nom d’hôte est " busybox-1
" et le sous-domaine est "sous-domaine-par-default
", et un service sans en-tête nommé "sous-domaine-par-default
" dans le même namespace, le pod verra son propre nom de domaine complet "busybox-1.sous-domaine-par-default.mon-namespace.svc.cluster.local
". Le DNS sert un enregistrement A portant ce nom, et pointant vers l'adresse IP du pod. Les deux Pods "busybox1
" et " busybox2
" peuvent avoir leurs enregistrements A distincts.
L’objet Endpoints peut spécifier le hostname
pour n’importe quelle adresse d'endpoint (noeud final), avec son adresse IP.
hostname
est requis pour la création de l'enregistrement A du pod. Un pod sans hostname
mais avec subdomain
(sous domaine) ne créera que l'enregistrement A pour le service sans en-tête (sous-domaine-par-default.mon-namespace.svc.cluster.local
), pointant vers l'adresse IP du pod.
Politique DNS du Pod
Les stratégies DNS peuvent être définies par pod. Actuellement, Kubernetes supporte des stratégies DNS qui sont spécifiques au pod. Ces politiques sont spécifiées dans le
Champ dnsPolicy
de la spécification du pod.
- "
Default
" : le pod hérite de la configuration de résolution des noms du node (noeud) sur lequel ce même pod est en train de tourner. Voir discussion liée pour plus de détails. - "
ClusterFirst
" : toute requête DNS ne correspondant pas au suffixe du domaine configuré dans le cluster, tel que "www.kubernetes.io
", sera transmise au serveur en amont hérité du node (noeud). Les administrateurs du cluster peuvent configurer des serveurs DNS supplémentaires que ce soit des serveurs secondaires (locaux) ou des vrais serveurs récursifs en amont pour faire la résolution. Voir discussion liée pour plus de détails sur la manière dont les requêtes DNS sont traitées dans ces cas. - "
ClusterFirstWithHostNet
" : pour les pods exécutés avechostNetwork
, vous devez explicitement définir sa politique DNS "ClusterFirstWithHostNet
". - "
None
" : une nouvelle valeur optionnelle introduite dans Kubernetes v1.9 (Beta dans v1.10). Elle permet à un pod d’ignorer les configurations DNS de l’environnement Kubernetes. Ainsi, toutes les configurations DNS sont supposées être fournies dans le champdnsConfig
de la spécification du pod. Voir la sous-section Config DNS ci-dessous.
dnsPolicy
n'est pas explicitement spécifié, ClusterFirst
sera utilisé.
L’exemple ci-dessous montre un pod avec une stratégie DNS "ClusterFirstWithHostNet
" car il a le champ hostNetwork
défini à true
.
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- image: busybox:1.28
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: busybox
restartPolicy: Always
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
Configuration DNS du pod
Kubernetes v1.9 introduit une fonctionnalité Alpha (version beta de v1.10) qui permet aux utilisateurs d'avoir plus de contrôle sur les paramètres DNS d'un pod. Cette fonctionnalité est activée par défaut dans la version 1.10.
Pour activer cette fonctionnalité dans la version 1.9, l'administrateur du cluster doit activer la feature gate (porte de fonctionnalité) CustomPodDNS
sur les serveurs apiserver et kubelet, par exemple, "--feature-gates=CustomPodDNS=true,...
".
Lorsque la fonction est activée, les utilisateurs peuvent mettre le champ dnsPolicy
d’un pod à "None
" et ils peuvent rajouter un nouveau champ dnsConfig
à la spécification du pod.
Le champ dnsConfig
est facultatif et peut fonctionner avec toute configuration dnsPolicy
.
Cependant, quand dnsPolicy
du pod est réglé sur "None
", le champ dnsConfig
doit être explicitement spécifié.
Vous trouverez ci-dessous les propriétés qu'un utilisateur peut spécifier dans le champ dnsConfig
:
nameservers
: liste d'adresses IP qui seront utilisées comme serveurs DNS pour le Pod. Il peut y avoir au plus 3 adresses IP spécifiées. Quand le champdnsPolicy
du Pod est mis à "None
", la liste doit contenir au moins une adresse IP, sinon cette propriété est facultative. Les serveurs listés seront combinés avec les nameservers (serveurs de noms) de base générés à partir de la stratégie DNS spécifiée, tout en supprimant les adresses en double.searches
: liste des domaines de recherche DNS pour la recherche du nom d'hôte dans le pod. Cette propriété est facultative. Si elle est spécifiée, la liste fournie sera fusionnée avec les noms de domaine de recherche de base générés à partir de la stratégie DNS choisie. Les noms de domaine en double sont supprimés. Kubernetes permet au plus 6 domaines de recherche.options
: une liste optionnelle d'objets où chaque objet peut avoir une propriéténame
(obligatoire) et une propriétévalue
(facultatif). Le contenu de cette propriété sera fusionné avec les options générées à partir de la stratégie DNS spécifiée. Les entrées en double sont supprimées.
Voici un exemple de Pod avec des configurations DNS personnalisées :
apiVersion: v1
kind: Pod
metadata:
namespace: default
name: exemple-dns
spec:
containers:
- name: test
image: nginx
dnsPolicy: "None"
dnsConfig:
nameservers:
- 1.2.3.4
searches:
- ns1.svc.cluster.local
- mon.dns.search.suffix
options:
- name: ndots
value: "2"
- name: edns0
Lorsque le Pod ci-dessus est créé, le conteneur test
obtient le contenu suivant dans son fichier /etc/resolv.conf
:
nameserver 1.2.3.4
search ns1.svc.cluster.local mon.dns.search.suffix
options ndots:2 edns0
Pour la configuration IPv6, le chemin de recherche et le serveur de noms doivent être configurés comme suit :
$ kubectl exec -it exemple-dns -- cat /etc/resolv.conf
nameserver fd00:79:30::a
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
A suivre
Pour obtenir des recommendations sur l’administration des configurations DNS, consultez Configurer le service DNS
4 - Ingress
Un Ingress est un objet Kubernetes qui gère l'accès externe aux services dans un cluster, généralement du trafic HTTP.
Un Ingress peut fournir un équilibrage de charge, une terminaison TLS et un hébergement virtuel basé sur un nom.
Terminologie
Par souci de clarté, ce guide définit les termes suivants :
- Nœud (Node) : une seule machine virtuelle ou physique dans un cluster Kubernetes.
- Cluster : groupe de nœuds protégés par un pare-feu du trafic provenant d'Internet et constituant les principales ressources de calcul gérées par Kubernetes.
- Routeur Edge : routeur appliquant la stratégie de pare-feu pour votre cluster. Il peut s’agir d’une passerelle gérée par un fournisseur de cloud ou d’un matériel physique.
- Réseau de cluster : ensemble de liens, logiques ou physiques, facilitant la communication au sein d'un cluster selon le modèle de réseau Kubernetes.
- Service : un Kubernetes Service identifiant un ensemble de pods à l'aide de sélecteurs d'étiquettes. Sauf indication contraire, les services sont supposés avoir des adresses IP virtuelles routables uniquement dans le réseau du cluster.
Qu'est-ce qu'un Ingress ?
Ingress (ou une entrée réseau), ajouté à Kubernetes v1.1, expose les routes HTTP et HTTPS de l'extérieur du cluster à des services au sein du cluster. Le routage du trafic est contrôlé par des règles définies sur la ressource Ingress.
internet
|
[ Ingress ]
--|-----|--
[ Services ]
Un Ingress peut être configuré pour donner aux services des URLs accessibles de l'extérieur, un équilibrage du trafic de charge externe, la terminaison SSL/TLS et un hébergement virtuel basé sur le nom. Un contrôleur d'Ingress est responsable de l'exécution de l'Ingress, généralement avec un load-balancer (équilibreur de charge), bien qu'il puisse également configurer votre routeur périphérique ou des interfaces supplémentaires pour aider à gérer le trafic.
Un Ingress n'expose pas de ports ni de protocoles arbitraires. Exposer des services autres que HTTP et HTTPS à Internet généralement utilise un service de type Service.Type=NodePort ou Service.Type=LoadBalancer.
Conditions préalables
Kubernetes v1.1 [beta]
Avant de commencer à utiliser un Ingress, vous devez comprendre certaines choses. Un Ingress est une ressource en "version Beta".
GCE/GKE (Google Cloud Engine / Google Kubernetes Engine) déploie un contrôleur d’Ingress sur le master (le maître de kubernetes). Revoir les limitations beta de ce contrôleur si vous utilisez GCE/GKE.
Dans les environnements autres que GCE/GKE, vous devrez peut-être déployer un contrôleur d'Ingress. Il y a un certain nombre de contrôleurs d'Ingress parmi lesquels vous pouvez choisir.
Avant de commencer
Dans l’idéal, tous les contrôleurs d’Ingress devraient correspondre à cette spécification. Cependant le fonctionnement est légèrement différent d'un contrôleur à un autre (en fonction de son implémentation).
La ressource Ingress
Exemple de ressource Ingress minimale :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
service:
name: test
port:
number: 80
Comme pour toutes les autres ressources Kubernetes, un Ingress (une entrée) a besoin des champs apiVersion
, kind
et metadata
.
Pour des informations générales sur l'utilisation des fichiers de configuration, voir déployer des applications, configurer des conteneurs, gestion des ressources.
Ingress utilise fréquemment des annotations pour configurer certaines options en fonction du contrôleur Ingress, dont un exemple
est l'annotation rewrite-target.
Différents Ingress controller prennent en charge différentes annotations. Consultez la documentation du contrôleur Ingress de votre choix pour savoir quelles annotations sont prises en charge.
La spécification de la ressource Ingress dispose de toutes les informations nécessaires pour configurer un loadbalancer ou un serveur proxy. Plus important encore, il contient une liste de règles d'appariement de toutes les demandes entrantes. La ressource Ingress ne supporte que les règles pour diriger le trafic HTTP.
Ingress rules
Chaque règle http contient les informations suivantes :
- Un hôte optionnel. Dans cet exemple, aucun hôte n'est spécifié. La règle s'applique donc à tous les appels entrants. Le trafic HTTP via l'adresse IP est spécifié. 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 étant associé à un backend associé défini par un
serviceName
etservicePort
. L’hôte et le chemin doivent correspondre au contenu d’une demande entrante avant que le load-balancer ne dirige le trafic vers le service référencé. - Un backend est une combinaison de noms de services et de ports, comme décrit dans services doc. Les requêtes HTTP (et HTTPS) envoyées à l'Ingress correspondant à l'hôte et au chemin de la règle seront envoyées au backend indiqué.
Un backend par défaut est souvent configuré dans un contrôleur d’Ingress qui traite toutes les demandes qui ne correspondent à aucun chemin dans la spécification.
Backend par défaut
Un Ingress sans règles envoie tout le trafic à un seul backend par défaut. Le backend par défaut est généralement une option de configuration du Contrôleur d'ingress et n'est pas spécifié dans vos ressources Ingress.
Si aucun des hôtes ou chemins ne correspond à la demande HTTP dans les objets Ingress, le trafic est routé vers votre backend par défaut.
Types d'Ingress
Ingress pour service unique
Il existe des concepts Kubernetes qui vous permettent d’exposer un seul service. (voir alternatives). Vous pouvez également le faire avec un Ingress en spécifiant un backend par défaut sans règles.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
spec:
defaultBackend:
service:
name: testsvc
port:
number: 80
Si vous le créez en utilisant kubectl create -f
, vous devriez voir :
kubectl get ingress test-ingress
NAME HOSTS ADDRESS PORTS AGE
test-ingress * 107.178.254.228 80 59s
Où 107.178.254.228
est l’adresse IP allouée par le contrôleur d’Ingress pour satisfaire cette entrée.
<pending>
(en attente).
Fanout simple
Une configuration de type fanout achemine le trafic d'une adresse IP unique vers plusieurs services, en se basant sur l'URI HTTP demandée. Une entrée vous permet de garder le nombre de loadbalancers au minimum. Par exemple, une configuration comme :
foo.bar.com -> 178.91.123.132 -> / foo service1:4200
/ bar service2:8080
ceci nécessitera un Ingress défini comme suit :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple-fanout-example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
pathType: Prefix
backend:
service:
name: service1
port:
number: 4200
- path: /bar
pathType: Prefix
backend:
service:
name: service2
port:
number: 8080
Lorsque vous créez l'ingress avec kubectl create -f
:
kubectl describe ingress simple-fanout-example
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)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 22s loadbalancer-controller default/test
Le contrôleur d’Ingress fournit une implémentation spécifique aux load-balancers qui satisfait l'Ingress, tant que les services (s1
, s2
) existent.
Lorsque cela est fait, vous pouvez voir l’adresse du load-balancer sur le champ d'adresse.
Hébergement virtuel basé sur le nom
Les hôtes virtuels basés sur des noms prennent en charge le routage du trafic HTTP vers plusieurs noms d'hôte basés sur la même adresse IP.
foo.bar.com --| |-> foo.bar.com s1:80
| 178.91.123.132 |
bar.foo.com --| |-> bar.foo.com s2:80
L’Ingress suivant indique au load-balancer de router les requêtes en fonction de En-tête du hôte.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
- host: bar.foo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service2
port:
number: 80
Si vous créez une ressource Ingress sans aucun hôte défini dans les règles, tout trafic Web à destination de l'adresse IP de votre contrôleur d'Ingress peut être mis en correspondance sans qu'un hôte virtuel basé sur le nom ne soit requis. Par exemple, la ressource Ingress suivante acheminera le trafic demandé pour first.bar.com
au service1
second.foo.com
au service2
, et à tout trafic à l'adresse IP sans nom d'hôte défini dans la demande (c'est-à-dire sans en-tête de requête présenté) au service3
.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: first.bar.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
- host: second.foo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service2
port:
number: 80
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service3
port:
number: 80
TLS
Vous pouvez sécuriser un Ingress en définissant un secret qui contient une clé privée et un certificat TLS. Actuellement, l'Ingress prend seulement en charge l'unique port TLS, 443, et suppose une terminaison TLS. Si la section de configuration TLS dans un Ingress spécifie différents hôtes, ils seront multiplexés sur le même port en fonction du nom d’hôte spécifié via l'extension SNI TLS (à condition que le contrôleur d’Ingress prenne en charge SNI). Le secret de TLS doit contenir les clés tls.crt
et tls.key
contenant le certificat et clé privée à utiliser pour TLS, par exemple :
apiVersion: v1
data:
tls.crt: base64 encoded cert
tls.key: base64 encoded key
kind: Secret
metadata:
name: testsecret-tls
namespace: default
type: kubernetes.io/tls
Référencer ce secret dans un Ingress indiquera au contrôleur d'Ingress de sécuriser le canal du client au load-balancer à l'aide de TLS. Vous devez vous assurer que le secret TLS que vous avez créé provenait d'un certificat contenant un Common Name (CN), aussi appelé nom de domaine pleinement qualifié (FQDN), pour https-example.foo.com
.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- https-example.foo.com
secretName: testsecret-tls
rules:
- host: https-example.foo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
L'équilibrage de charge
Un contrôleur d’Ingress est démarré avec certains paramètres de politique d’équilibrage de charge qui s'appliquent à toutes les entrées, tels que l'algorithme d'équilibrage de la charge, le régime de pondérations des backends, et d'autres. Les concepts un peu plus avancés d'équilibrage de charge (p. ex. sessions persistantes, pondérations dynamiques) ne sont pas encore exposés pour l'Ingress. Vous pouvez toujours obtenir ces fonctionnalités via le service loadbalancer.
Il est également intéressant de noter que même si les health checks (contrôles de santé) ne sont pas exposés directement via l'Ingress, il existe des concepts parallèles dans Kubernetes, tels que readiness probes qui vous permettent d'obtenir le même résultat final. Veuillez consulter les documents spécifiques au contrôleur pour voir comment il gère les health checks. (nginx,GCE).
Mise à jour d'un Ingress
Pour mettre à jour un Ingress existant afin d'ajouter un nouvel hôte, vous pouvez le mettre à jour en modifiant 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 s1:80 (10.8.0.90:80)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 35s loadbalancer-controller default/test
kubectl edit ingress test
Cela devrait faire apparaître un éditeur avec le yaml existant, modifiez-le pour inclure le nouvel hôte :
spec:
rules:
- host: foo.bar.com
http:
paths:
- backend:
service:
name: s1
port:
number: 80
path: /foo
pathType: Prefix
- host: bar.baz.com
http:
paths:
- backend:
service:
name: s2
port:
number: 80
path: /foo
pathType: Prefix
..
L'enregistrement du yaml mettra à jour la ressource dans le serveur d'API, ce qui devrait indiquer au contrôleur d'Ingress de reconfigurer le load-balancer.
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 s1:80 (10.8.0.90:80)
bar.baz.com
/foo s2:80 (10.8.0.91:80)
Annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 45s loadbalancer-controller default/test
Vous pouvez obtenir le même résultat en appelant kubectl replace -f
sur un fichier Ingress yaml modifié.
Échec dans les zones de disponibilité
Les techniques permettant de répartir le trafic sur plusieurs domaines de défaillance diffèrent d'un fournisseur de cloud à l'autre. Veuillez consulter la documentation du Contrôleur d'ingress pour plus de détails. Vous pouvez également vous référer à la documentation de la fédération pour plus d'informations sur le déploiement d'Ingress dans un cluster fédéré.
Travail futur
Suivez SIG network (groupe d'intérêt spécial Réseau) pour plus de détails sur l'évolution de l'Ingress et des ressources associées. Vous pouvez également suivre le Dépôt Ingress pour plus de détails sur l'évolution des différents contrôleurs d’Ingress.
Alternatives
Vous pouvez exposer un service de plusieurs manières sans impliquer directement la ressource Ingress :
- Utilisez Service.Type=LoadBalancer
- Utilisez Service.Type=NodePort
- Utilisez un Proxy du port