Un guide de l’architecture Kubernetes

Vous utilisez Kubernetes pour orchestrer les conteneurs. C’est une description facile à dire, mais comprendre ce que cela signifie réellement et comment vous y parvenez est une tout autre affaire. Si vous exécutez ou gérez un cluster Kubernetes, vous savez que Kubernetes se compose d’un ordinateur désigné comme plan de contrôle et de nombreux autres ordinateurs désignés comme nœuds de travail. Chacun d’eux a une pile complexe mais robuste rendant l’orchestration possible, et se familiariser avec chaque composant aide à comprendre comment tout cela fonctionne.
Contents
Composants du plan de contrôle
Vous installez Kubernetes sur une machine appelée le plan de contrôle. C’est celui qui exécute le démon Kubernetes, et c’est celui avec lequel vous communiquez lors du démarrage des conteneurs et des pods. Les sections suivantes décrivent les composants du plan de contrôle.
etc.
Etcd est un catalogue clé-valeur rapide, distribué et cohérent et il est utilisé comme catalogue de sauvegarde pour stocker de manière persistante les données d’objet Kubernetes telles que les pods, les contrôleurs de réplication, les secrets et les services. Etcd est le seul endroit où Kubernetes stocke l’état et les métadonnées du cluster. Le seul composant qui communique directement avec etcd est le serveur d’API Kubernetes. Tous les autres composants lisent et écrivent des données sur etcd indirectement via le serveur API.
Etcd implémente également une fonction de surveillance, qui fournit une interface basée sur les événements pour surveiller de manière asynchrone les modifications apportées aux clés. Une fois que vous modifiez une clé, ses observateurs sont avertis. Le composant du serveur d’API en dépend fortement pour être averti et déplacer l’état actuel d’etcd vers l’état souhaité.
Pourquoi le nombre d’instances etcd devrait-il être un nombre impair ?
Vous auriez généralement trois, cinq ou sept instances etcd s’exécutant dans un environnement à haute disponibilité (HA), mais pourquoi ? Parce qu’etcd est un catalogue de données distribué. Il est possible de le mettre à l’échelle horizontalement, mais vous devez également vous assurer que les données de chaque instance sont cohérentes, et pour cela, votre système doit parvenir à un consensus sur ce qu’est l’état. Etcd utilise l’algorithme de consensus RAFT pour ça.
L’algorithme nécessite une majorité (ou quorum) pour que le cluster passe à l’état suivant. Si vous n’avez que deux instances ectd et que l’une d’entre elles échoue, le cluster etcd ne peut pas passer à un nouvel état car aucune majorité n’existe. Si vous avez trois instances ectd, une instance peut échouer mais avoir encore une majorité d’instances disponibles pour atteindre un quorum.
Serveur d’API
Le serveur d’API est le seul composant de Kubernetes qui interagit directement avec etcd. Tous les autres composants de Kubernetes doivent passer par le serveur d’API pour fonctionner avec l’état du cluster, y compris les clients (kubectl). Le serveur API a les fonctions suivantes :
- Fournit un moyen cohérent de stocker des objets dans etcd.
- Effectue la validation de ces objets afin que les clients ne puissent pas stocker des objets mal configurés (ce qui pourrait arriver s’ils écrivent directement dans le catalogue de données etcd).
- Fournit une API RESTful pour créer, mettre à jour, modifier ou supprimer une ressource.
- Fournit verrouillage de concurrence optimisteafin que les autres clients ne remplacent jamais les modifications apportées à un objet en cas de mises à jour simultanées.
- Effectue l’authentification et l’autorisation d’une demande envoyée par le client. Il utilise les plugins pour extraire le nom d’utilisateur du client, l’ID utilisateur, les groupes auxquels l’utilisateur appartient et déterminer si l’utilisateur authentifié peut effectuer l’action demandée sur la ressource demandée.
- Responsable de controle d’admission si la demande tente de créer, modifier ou supprimer une ressource. Par exemple, AlwaysPullImages, DefaultStorageClass et ResourceQuota.
- Implémente un mécanisme de surveillance (similaire à etcd) pour que les clients surveillent les changements. Cela permet aux composants tels que le planificateur et le gestionnaire de contrôleur d’interagir avec le serveur API de manière lâche.
Gestionnaire de contrôleur
Dans Kubernetes, les contrôleurs sont des boucles de contrôle qui surveillent l’état de votre cluster, puis apportent ou demandent des modifications si nécessaire. Chaque contrôleur essaie de rapprocher l’état actuel du cluster de l’état souhaité. Le contrôleur suit au moins un type de ressource Kubernetes, et ces objets ont un champ de spécification qui représente l’état souhaité.
Exemples de contrôleur :
- Replication Manager (un contrôleur pour les ressources ReplicationController)
- Contrôleurs ReplicaSet, DaemonSet et Job
- Contrôleur de déploiement
- Contrôleur StatefulSet
- Contrôleur de nœud
- Contrôleur de services
- Contrôleur de points de terminaison
- Contrôleur d’espace de noms
- Contrôleur PersistentVolume
Les contrôleurs utilisent le mécanisme de surveillance pour être informés des changements. Ils surveillent le serveur d’API pour les modifications apportées aux ressources et effectuent des opérations pour chaque modification, qu’il s’agisse de la création d’un nouvel objet ou de la mise à jour ou de la suppression d’un objet existant. La plupart du temps, ces opérations incluent la création d’autres ressources ou la mise à jour des ressources surveillées elles-mêmes. Néanmoins, comme l’utilisation de montres ne garantit pas que le contrôleur ne manquera pas un événement, il effectue également une opération de réinscription périodiquement pour s’assurer qu’il n’a rien manqué.
Le gestionnaire de contrôleur exécute également des fonctions de cycle de vie telles que la création et le cycle de vie d’un espace de noms, la récupération de place d’événements, la récupération de place de pod terminé, récupération de place avec suppression en cascade, et la récupération de place du nœud. Voir Gestionnaire de contrôleur Cloud pour plus d’informations.
Planificateur
Le planificateur est un processus de plan de contrôle qui attribue des pods aux nœuds. Il surveille les pods nouvellement créés qui n’ont aucun nœud attribué. Pour chaque pod découvert par le planificateur, le planificateur devient responsable de la recherche du meilleur nœud sur lequel ce pod doit s’exécuter.
Les nœuds qui répondent aux exigences de planification d’un pod sont appelés nœuds réalisables. Si aucun des nœuds ne convient, le pod reste non planifié jusqu’à ce que le planificateur puisse le placer. Une fois qu’il trouve un nœud réalisable, il exécute un ensemble de fonctions pour noter les nœuds, et le nœud avec le score le plus élevé est sélectionné. Il informe ensuite le serveur API du nœud sélectionné. Ils appellent ce processus contraignant.
La sélection des nœuds est un processus en deux étapes :
- Filtrage de la liste de tous les nœuds pour obtenir une liste de nœuds acceptables sur lesquels vous pouvez planifier le pod (par exemple, le filtre PodFitsResources vérifie si un nœud candidat dispose de suffisamment de ressources disponibles pour répondre aux demandes de ressources spécifiques d’un pod).
- Noter la liste des nœuds obtenus à partir de la première étape et les classer pour choisir le meilleur nœud. Si plusieurs nœuds ont le score le plus élevé, un processus circulaire garantit que les pods sont déployés uniformément sur chacun d’eux.
Les facteurs à prendre en compte pour les décisions de planification comprennent :
- Le pod demande-t-il des ressources matérielles/logicielles ? Le nœud signale-t-il une condition de mémoire ou de pression de disque ?
- Le nœud a-t-il une étiquette qui correspond au sélecteur de nœud dans la spécification du pod ?
- Si le pod demande une liaison à un port hôte spécifique, ce port est-il disponible ?
- Le pod tolère-t-il les souillures du nœud ?
- Le pod spécifie-t-il des règles d’affinité ou d’anti-affinité de nœud ?
Le planificateur n’ordonne pas au nœud sélectionné d’exécuter le pod. Tout ce que fait le planificateur est de mettre à jour la définition de pod via le serveur d’API. Le serveur d’API informe ensuite le kubelet que le pod a été planifié via le mécanisme de surveillance. Ensuite, le service kubelet sur le nœud cible voit que le pod a été planifié sur son nœud, il crée et exécute les conteneurs du pod.
Composants de nœud de travail
Les nœuds de travail exécutent l’agent kubelet, ce qui leur permet d’être recrutés par le plan de contrôle pour traiter les tâches. Semblable au plan de contrôle, le nœud de travail utilise plusieurs composants différents pour rendre cela possible. Les sections suivantes décrivent les composants du noeud worker.
Kubelet
Kubelet est un agent qui s’exécute sur chaque nœud du cluster et est responsable de tout ce qui s’exécute sur un nœud de travail. Il garantit que les conteneurs s’exécutent dans le pod.
Les principales fonctions du service kubelet sont :
- Enregistrez le nœud sur lequel il s’exécute en créant une ressource de nœud dans le serveur d’API.
- Surveillez en permanence le serveur d’API pour les pods qui ont été planifiés sur le nœud.
- Démarrez les conteneurs du pod à l’aide de l’environnement d’exécution de conteneur configuré.
- Surveillez en permanence les conteneurs en cours d’exécution et signalez leur état, les événements et la consommation de ressources au serveur d’API.
- Exécutez les sondes de vivacité du conteneur, redémarrez les conteneurs lorsque les sondes échouent et terminez les conteneurs lorsque leur pod est supprimé du serveur d’API (en informant le serveur de la résiliation du pod).
Mandataire de services
Le proxy de service (kube-proxy) s’exécute sur chaque nœud et garantit qu’un pod peut parler à un autre pod, qu’un nœud peut parler à un autre nœud et qu’un conteneur peut parler à un autre conteneur. Il est chargé de surveiller le serveur d’API pour les modifications apportées aux services et aux définitions de pod afin de maintenir que l’ensemble de la configuration du réseau est à jour. Lorsqu’un service est soutenu par plusieurs pods, le proxy effectue un équilibrage de charge sur ces pods.
Le kube-proxy tire son nom du fait qu’il a commencé comme un véritable serveur proxy qui acceptait les connexions et les transmettait aux pods. L’implémentation actuelle utilise des règles iptables pour rediriger les paquets vers un pod principal sélectionné au hasard sans les faire passer par un serveur proxy réel.
Une vue d’ensemble de son fonctionnement :
- Lorsque vous créez un service, une adresse IP virtuelle est immédiatement attribuée.
- Le serveur d’API informe les agents kube-proxy exécutés sur les noeuds worker qu’un nouveau service existe.
- Chaque kube-proxy rend le service adressable en configurant des règles iptables, en veillant à ce que chaque paire IP/port de service soit interceptée et que l’adresse de destination soit modifiée en l’un des pods qui soutiennent le service.
- Surveille le serveur d’API pour les modifications apportées aux services ou à ses objets de point de terminaison.
Exécution du conteneur
Il existe deux catégories d’environnements d’exécution de conteneur :
- Exécutions de conteneur de niveau inférieur : Ceux-ci se concentrent sur l’exécution des conteneurs et la configuration de l’espace de noms et des groupes de contrôle pour les conteneurs.
- Exécutions de conteneur de niveau supérieur (moteur de conteneur) : Ceux-ci se concentrent sur les formats, le déballage, la gestion, le partage d’images et la fourniture d’API pour les développeurs.
L’exécution du conteneur prend en charge :
- Extrait l’image de conteneur requise d’un registre d’images si elle n’est pas disponible localement.
- Extrait l’image sur un système de fichiers de copie sur écriture et toutes les couches de conteneur se superposent pour créer un système de fichiers fusionné.
- Prépare un point de montage de conteneur.
- Définit les métadonnées de l’image du conteneur comme le remplacement de CMD, ENTRYPOINT à partir des entrées de l’utilisateur et configure les règles SECCOMP, garantissant que le conteneur s’exécute comme prévu.
- Modifie le noyau pour attribuer une isolation comme le processus, la mise en réseau et le système de fichiers à ce conteneur.
- Alerte le noyau pour assigner certaines limites de ressources comme les limites de CPU ou de mémoire.
- Passez l’appel système (syscall) au noyau pour démarrer le conteneur.
- Garantit que la configuration de SElinux/AppArmor est correcte.
Travailler ensemble
Les composants au niveau du système fonctionnent ensemble pour garantir que chaque partie d’un cluster Kubernetes peut réaliser son objectif et exécuter ses fonctions. Cela peut parfois être écrasant (lorsque vous êtes plongé dans l’édition d’un fichier YAML) pour comprendre comment vos demandes sont communiquées au sein de votre cluster. Maintenant que vous avez une carte de la façon dont les pièces s’emboîtent, vous pouvez mieux comprendre ce qui se passe à l’intérieur de Kubernetes, ce qui vous aide à diagnostiquer les problèmes, à maintenir un cluster sain et à optimiser votre propre flux de travail.