Architecture du cluster

Les concepts architecturaux derrière Kubernetes.

Un cluster Kubernetes est composé d'un plan de contrôle et d'un ensemble de machines de travail, appelées nœuds, qui exécutent des applications conteneurisées. Chaque cluster a besoin d'au moins un nœud de travail pour exécuter des Pods.

Les nœuds de travail hébergent les Pods qui sont les composants de la charge de travail de l'application. Le plan de contrôle gère les nœuds de travail et les Pods du cluster. Dans les environnements de production, le plan de contrôle s'exécute généralement sur plusieurs ordinateurs et un cluster exécute généralement plusieurs nœuds, offrant une tolérance aux pannes et une haute disponibilité.

Ce document décrit les différents composants nécessaires pour avoir un cluster Kubernetes complet et fonctionnel.

Le plan de contrôle (kube-apiserver, etcd, kube-controller-manager, kube-scheduler) et plusieurs nœuds. Chaque nœud exécute un kubelet et kube-proxy.

Composants du cluster Kubernetes

Remarque : Ce diagramme présente une architecture de référence d'exemple pour un cluster Kubernetes. La répartition réelle des composants peut varier en fonction des configurations et des exigences spécifiques du cluster.

Composants du plan de contrôle

Les composants du plan de contrôle prennent des décisions globales sur le cluster (par exemple, la planification), ainsi que la détection et la réponse aux événements du cluster (par exemple, démarrer un nouveau pod lorsque le champ replicas d'un déploiement n'est pas satisfait).

Les composants du plan de contrôle peuvent s'exécuter sur n'importe quelle machine du cluster. Cependant, pour simplifier, les scripts d'installation démarrent généralement tous les composants du plan de contrôle sur la même machine et n'exécutent pas de conteneurs utilisateur sur cette machine. Consultez Création de clusters hautement disponibles avec kubeadm pour un exemple de configuration du plan de contrôle s'exécutant sur plusieurs machines.

kube-apiserver

Composant sur le master qui expose l'API Kubernetes. Il s'agit du front-end pour le plan de contrôle Kubernetes.

Il est conçu pour une mise à l'échelle horizontale, ce qui veut dire qu'il met à l'échelle en déployant des instances supplémentaires. Voir Construire des Clusters en Haute Disponibilité.

etcd

Base de données clé-valeur consistante et hautement disponible utilisée comme mémoire de sauvegarde pour toutes les données du cluster.

Si votre cluster Kubernetes utilise etcd comme mémoire de sauvegarde, assurez-vous d'avoir un plan de back up pour ces données.

Vous pouvez trouver plus d'informations à propos d'etcd dans la documentation officielle.

kube-scheduler

Composant sur le master qui surveille les pods nouvellement créés qui ne sont pas assignés à un nœud et sélectionne un nœud sur lequel ils vont s'exécuter.

Les facteurs pris en compte pour les décisions de planification (scheduling) comprennent les exigences individuelles et collectives en ressources, les contraintes matérielles/logicielles/politiques, les spécifications d'affinité et d'anti-affinité, la localité des données, les interférences entre charges de travail et les dates limites.

kube-controller-manager

Composant du master qui exécute les contrôleurs.

Logiquement, chaque contrôleur est un processus à part mais, pour réduire la complexité, les contrôleurs sont tous compilés dans un seul binaire et s'exécutent dans un seul processus.

Il existe de nombreux types de contrôleurs différents. Voici quelques exemples :

  • Contrôleur de nœuds : Responsable de la détection et de la réponse lorsque les nœuds tombent en panne.
  • Contrôleur de tâches : Surveille les objets Job qui représentent des tâches ponctuelles, puis crée des Pods pour exécuter ces tâches jusqu'à leur achèvement.
  • Contrôleur EndpointSlice : Remplit les objets EndpointSlice (pour établir un lien entre les Services et les Pods).
  • Contrôleur ServiceAccount : Crée des comptes de service par défaut pour les nouveaux espaces de noms.

Ce qui précède n'est pas une liste exhaustive.

cloud-controller-manager

Le Cloud Controller Manager est une fonctionnalité alpha de la version 1.8. Dans les prochaines versions, il deviendra le moyen privilégié pour l'intégration de Kubernetes à n'importe quel cloud.

Le cloud-controller-manager exécute uniquement des contrôleurs spécifiques à votre fournisseur de cloud. Si vous exécutez Kubernetes sur vos propres serveurs ou dans un environnement d'apprentissage sur votre propre PC, le cluster n'a pas de cloud-controller-manager.

Comme pour kube-controller-manager, cloud-controller-manager combine plusieurs boucles de contrôle logiquement indépendantes en un seul binaire que vous exécutez en tant que processus unique. Vous pouvez mettre à l'échelle horizontalement (exécuter plusieurs copies) pour améliorer les performances ou pour aider à tolérer les pannes.

Les contrôleurs suivants peuvent avoir des dépendances vis-à-vis du fournisseur de cloud :

  • Contrôleur de nœuds : Pour vérifier auprès du fournisseur de cloud si un nœud a été supprimé dans le cloud après avoir cessé de répondre
  • Contrôleur de routage : Pour configurer les routes dans l'infrastructure cloud sous-jacente
  • Contrôleur de service : Pour créer, mettre à jour et supprimer des équilibreurs de charge du fournisseur de cloud

Composants du nœud

Les composants du nœud s'exécutent sur chaque nœud, maintenant les Pods en cours d'exécution et fournissant l'environnement d'exécution Kubernetes.

kubelet

Un agent qui s'exécute sur chaque nœud du cluster. Il s'assure que les conteneurs fonctionnent dans un pod.

Le kubelet prend un ensemble de PodSpecs fournis par divers mécanismes et s'assure du fonctionnement et de la santé des conteneurs décrits dans ces PodSpecs. Le kubelet ne gère que les conteneurs créés par Kubernetes.

kube-proxy (optionnel)

kube-proxy est un proxy réseau qui s'exécute sur chaque nœud du cluster et implémente une partie du concept Kubernetes de Service.

kube-proxy maintient les règles réseau sur les nœuds. Ces règles réseau permettent une communication réseau vers les Pods depuis des sessions réseau à l'intérieur ou à l'extérieur du cluster.

kube-proxy utilise la couche de filtrage de paquets du système d'exploitation s'il y en a une et qu'elle est disponible. Sinon, kube-proxy transmet le trafic lui-même.

Si vous utilisez un plugin réseau qui implémente le transfert de paquets pour les Services par lui-même, et fournissant un comportement équivalent à kube-proxy, alors vous n'avez pas besoin d'exécuter kube-proxy sur les nœuds de votre cluster.

Runtime de conteneur

L'environnement d'exécution de conteneurs est le logiciel responsable de l'exécution des conteneurs.

Kubernetes est compatible avec plusieurs environnements d'exécution de conteneur: Docker, containerd, cri-o, rktlet ainsi que toute implémentation de Kubernetes CRI (Container Runtime Interface).

Add-ons

Les add-ons utilisent des ressources Kubernetes (DaemonSet, Déploiement, etc.) pour implémenter des fonctionnalités de cluster. Étant donné qu'ils fournissent des fonctionnalités au niveau du cluster, les ressources des add-ons appartiennent au namespace kube-system.

Certains add-ons sélectionnés sont décrits ci-dessous ; pour une liste étendue d'add-ons disponibles, veuillez consulter Add-ons.

DNS

Bien que les autres add-ons ne soient pas strictement nécessaires, tous les clusters Kubernetes devraient avoir DNS du cluster, car de nombreux exemples en dépendent.

Le DNS du cluster est un serveur DNS, en plus des autres serveur(s) DNS de votre environnement, qui fournit des enregistrements DNS pour les services Kubernetes.

Les conteneurs démarrés par Kubernetes incluent automatiquement ce serveur DNS dans leurs recherches DNS.

Interface utilisateur Web (Dashboard)

Dashboard est une interface utilisateur basée sur le web, générale, pour les clusters Kubernetes. Il permet aux utilisateurs de gérer et de résoudre les problèmes des applications en cours d'exécution dans le cluster, ainsi que du cluster lui-même.

Surveillance des ressources des conteneurs

Surveillance des ressources des conteneurs enregistre des métriques génériques de séries chronologiques sur les conteneurs dans une base de données centrale et fournit une interface utilisateur pour parcourir ces données.

Journalisation au niveau du cluster

Un mécanisme de journalisation au niveau du cluster est responsable de l'enregistrement des journaux des conteneurs dans un magasin de journaux central avec une interface de recherche/parcours.

Plugins réseau

Les plugins réseau sont des composants logiciels qui implémentent la spécification de l'interface réseau de conteneur (CNI). Ils sont responsables de l'allocation des adresses IP aux pods et de leur permettre de communiquer entre eux au sein du cluster.

Variations de l'architecture

Bien que les composants principaux de Kubernetes restent cohérents, la manière dont ils sont déployés et gérés peut varier. Comprendre ces variations est crucial pour concevoir et maintenir des clusters Kubernetes répondant à des besoins opérationnels spécifiques.

Options de déploiement du plan de contrôle

Les composants du plan de contrôle peuvent être déployés de plusieurs manières :

Déploiement traditionnel
Les composants du plan de contrôle s'exécutent directement sur des machines dédiées ou des machines virtuelles, souvent gérées en tant que services systemd.
Pods statiques
Les composants du plan de contrôle sont déployés en tant que Pods statiques, gérés par le kubelet sur des nœuds spécifiques. Il s'agit d'une approche courante utilisée par des outils tels que kubeadm.
Auto-hébergé
Le plan de contrôle s'exécute en tant que Pods au sein du cluster Kubernetes lui-même, gérés par des déploiements et des StatefulSets ou d'autres primitives Kubernetes.
Services Kubernetes gérés
Les fournisseurs de cloud abstraient souvent le plan de contrôle, en gérant ses composants dans le cadre de leur offre de services.

Considérations pour le placement de la charge de travail

Le placement des charges de travail, y compris les composants du plan de contrôle, peut varier en fonction de la taille du cluster, des exigences de performance et des politiques opérationnelles :

  • Dans les clusters plus petits ou de développement, les composants du plan de contrôle et les charges de travail des utilisateurs peuvent s'exécuter sur les mêmes nœuds.
  • Les clusters de production plus importants dédient souvent des nœuds spécifiques aux composants du plan de contrôle, les séparant des charges de travail des utilisateurs.
  • Certaines organisations exécutent des add-ons critiques ou des outils de surveillance sur les nœuds du plan de contrôle.

Outils de gestion de cluster

Des outils tels que kubeadm, kops et Kubespray offrent différentes approches pour le déploiement et la gestion des clusters, chacun avec sa propre méthode de disposition et de gestion des composants.

La flexibilité de l'architecture de Kubernetes permet aux organisations d'adapter leurs clusters à des besoins spécifiques, en équilibrant des facteurs tels que la complexité opérationnelle, les performances et la charge de gestion.

Personnalisation et extensibilité

L'architecture de Kubernetes permet une personnalisation significative :

  • Des ordonnanceurs personnalisés peuvent être déployés pour travailler aux côtés de l'ordonnanceur Kubernetes par défaut ou pour le remplacer entièrement.
  • Les serveurs API peuvent être étendus avec des CustomResourceDefinitions et une agrégation d'API.
  • Les fournisseurs de cloud peuvent s'intégrer profondément à Kubernetes en utilisant le cloud-controller-manager.

La flexibilité de l'architecture de Kubernetes permet aux organisations d'adapter leurs clusters à des besoins spécifiques, en équilibrant des facteurs tels que la complexité opérationnelle, les performances et la charge de gestion.

A suivre

En savoir plus sur les sujets suivants :

1 - Noeuds

Kubernetes exécute votre charge de travail en plaçant des conteneurs dans des Pods pour s'exécuter sur des nœuds. Un nœud peut être une machine virtuelle ou physique, selon le cluster. Chaque nœud est géré par le plan de contrôle et contient les services nécessaires pour exécuter Pods.

Typiquement, vous avez plusieurs nœuds dans un cluster ; dans un environnement d'apprentissage ou limité en ressources, vous pourriez n'avoir qu'un seul nœud.

Les composants sur un nœud incluent le kubelet, un runtime de conteneur, et le kube-proxy.

Gestion

Il existe deux principales façons d'ajouter des nœuds au serveur API :

  1. Le kubelet sur un nœud s'enregistre automatiquement auprès du plan de contrôle.
  2. Vous (ou un autre utilisateur humain) ajoutez manuellement un objet Nœud.

Après avoir créé un objet Nœud, ou lorsque le kubelet sur un nœud s'enregistre automatiquement, le plan de contrôle vérifie si le nouvel objet Nœud est valide. Par exemple, si vous essayez de créer un Nœud à partir du manifeste JSON suivant :

{
  "kind": "Node",
  "apiVersion": "v1",
  "metadata": {
    "name": "10.240.79.157",
    "labels": {
      "name": "my-first-k8s-node"
    }
  }
}

Kubernetes crée un objet Nœud en interne (la représentation). Kubernetes vérifie qu'un kubelet s'est enregistré auprès du serveur API correspondant au champ metadata.name du Nœud. Si le nœud est en bonne santé (c'est-à-dire que tous les services nécessaires sont en cours d'exécution), alors il est éligible pour exécuter un Pod. Sinon, ce nœud est ignoré pour toute activité du cluster jusqu'à ce qu'il redevienne en bonne santé.

Le nom d'un objet Nœud doit être un nom de sous-domaine DNS valide.

Unicité du nom du nœud

Le nom identifie un Nœud. Deux Nœuds ne peuvent pas avoir le même nom en même temps. Kubernetes suppose également qu'une ressource avec le même nom est le même objet. Dans le cas d'un Nœud, on suppose implicitement qu'une instance utilisant le même nom aura le même état (par exemple, les paramètres réseau, le contenu du disque racine) et les mêmes attributs tels que les étiquettes du nœud. Cela peut entraîner des incohérences si une instance a été modifiée sans changer son nom. Si le Nœud doit être remplacé ou mis à jour de manière significative, l'objet Nœud existant doit être supprimé du serveur API en premier lieu, puis ré-ajouté après la mise à jour.

Auto-enregistrement des nœuds

Lorsque le drapeau kubelet --register-node est vrai (par défaut), le kubelet tente de s'enregistrer auprès du serveur API. C'est le modèle préféré, utilisé par la plupart des distributions.

Pour l'auto-enregistrement, le kubelet est démarré avec les options suivantes :

  • --kubeconfig - Chemin vers les informations d'identification pour s'authentifier auprès du serveur API.

  • --cloud-provider - Comment communiquer avec un fournisseur de cloud pour lire les métadonnées à son sujet.

  • --register-node - S'enregistrer automatiquement auprès du serveur API.

  • --register-with-taints - Enregistrer le nœud avec la liste donnée de taints (séparées par des virgules <clé>=<valeur>:<effet>).

    Ne fait rien si register-node est faux.

  • --node-ip - Liste facultative de adresses IP séparées par des virgules pour le nœud. Vous ne pouvez spécifier qu'une seule adresse pour chaque famille d'adresses. Par exemple, dans un cluster IPv4 à pile unique, vous définissez cette valeur comme l'adresse IPv4 que le kubelet doit utiliser pour le nœud. Consultez configurer une pile double IPv4/IPv6 pour plus de détails sur l'exécution d'un cluster à double pile.

    Si vous ne fournissez pas cet argument, le kubelet utilise l'adresse IPv4 par défaut du nœud, le cas échéant ; si le nœud n'a pas d'adresses IPv4, alors le kubelet utilise l'adresse IPv6 par défaut du nœud.

  • --node-labels - Étiquettes à ajouter lors de l'enregistrement du nœud dans le cluster (voir les restrictions d'étiquettes appliquées par le plugin d'admission NodeRestriction).

  • --node-status-update-frequency - Spécifie à quelle fréquence le kubelet envoie son état de nœud au serveur API.

Lorsque le mode d'autorisation du nœud et le plugin d'admission NodeRestriction sont activés, les kubelets sont autorisés uniquement à créer/modifier leur propre ressource Nœud.

Administration manuelle des nœuds

Vous pouvez créer et modifier des objets Nœud en utilisant kubectl.

Lorsque vous souhaitez créer manuellement des objets Nœud, définissez le drapeau kubelet --register-node=false.

Vous pouvez modifier des objets Nœud indépendamment du paramètre --register-node. Par exemple, vous pouvez définir des étiquettes sur un Nœud existant ou le marquer comme non planifiable.

Vous pouvez utiliser des étiquettes sur les Nœuds en conjonction avec des sélecteurs de nœuds sur les Pods pour contrôler la planification. Par exemple, vous pouvez restreindre un Pod à s'exécuter uniquement sur un sous-ensemble des nœuds disponibles.

Le marquage d'un nœud comme non planifiable empêche le planificateur de placer de nouveaux pods sur ce Nœud, mais n'affecte pas les Pods existants sur le Nœud. Cela est utile comme étape préparatoire avant un redémarrage du nœud ou une autre opération de maintenance.

Pour marquer un Nœud comme non planifiable, exécutez :

kubectl cordon $NOM_DU_NŒUD

Consultez Évacuation sécurisée d'un nœud pour plus de détails.

État du nœud

L'état d'un Nœud contient les informations suivantes :

Vous pouvez utiliser kubectl pour afficher l'état d'un Nœud et d'autres détails :

kubectl describe node <insérez-le-nom-du-nœud-ici>

Consultez État du nœud pour plus de détails.

Battements de cœur du nœud

Les battements de cœur, envoyés par les nœuds Kubernetes, aident votre cluster à déterminer la disponibilité de chaque nœud et à prendre des mesures en cas de détection de défaillances.

Pour les nœuds, il existe deux formes de battements de cœur :

  • Mises à jour de l'.status d'un Nœud.
  • Objets Lease dans le namespace kube-node-lease. Chaque Nœud a un objet Lease associé.

Contrôleur de nœud

Le contrôleur de nœud est un composant du plan de contrôle Kubernetes qui gère différents aspects des nœuds.

Le contrôleur de nœud a plusieurs rôles dans la vie d'un nœud. Le premier est d'attribuer un bloc CIDR au nœud lors de son enregistrement (si l'attribution CIDR est activée).

Le deuxième est de maintenir à jour la liste interne des nœuds du contrôleur de nœud avec la liste des machines disponibles du fournisseur de cloud. Lorsqu'il s'exécute dans un environnement cloud et chaque fois qu'un nœud est en mauvaise santé, le contrôleur de nœud demande au fournisseur de cloud si la VM pour ce nœud est toujours disponible. Si ce n'est pas le cas, le contrôleur de nœud supprime le nœud de sa liste de nœuds.

Le troisième est de surveiller la santé des nœuds. Le contrôleur de nœud est responsable de :

  • Dans le cas où un nœud devient injoignable, mettre à jour la condition Ready dans le champ .status du Nœud. Dans ce cas, le contrôleur de nœud définit la condition Ready à Unknown.
  • Si un nœud reste injoignable : déclencher l'éviction initiée par l'API pour tous les Pods sur le nœud injoignable. Par défaut, le contrôleur de nœud attend 5 minutes entre le marquage du nœud comme Unknown et la soumission de la première demande d'éviction.

Par défaut, le contrôleur de nœud vérifie l'état de chaque nœud toutes les 5 secondes. Cette période peut être configurée à l'aide du drapeau --node-monitor-period sur le composant kube-controller-manager.

Limites de taux sur l'éviction

Dans la plupart des cas, le contrôleur de nœud limite le taux d'éviction à --node-eviction-rate (par défaut 0,1) par seconde, ce qui signifie qu'il n'évacuera pas les pods de plus d'un nœud toutes les 10 secondes.

Le comportement d'éviction des nœuds change lorsqu'un nœud dans une zone de disponibilité donnée devient en mauvaise santé. Le contrôleur de nœud vérifie quel pourcentage de nœuds dans la zone sont en mauvaise santé (la condition Ready est Unknown ou False) en même temps :

  • Si la fraction de nœuds en mauvaise santé est d'au moins --unhealthy-zone-threshold (par défaut 0,55), alors le taux d'éviction est réduit.
  • Si le cluster est petit (c'est-à-dire qu'il a moins ou égal à --large-cluster-size-threshold nœuds - par défaut 50), alors les évictions sont arrêtées.
  • Sinon, le taux d'éviction est réduit à --secondary-node-eviction-rate (par défaut 0,01) par seconde.

La raison pour laquelle ces politiques sont mises en œuvre par zone de disponibilité est que une zone de disponibilité peut être isolée du plan de contrôle tandis que les autres restent connectées. Si votre cluster ne s'étend pas sur plusieurs zones de disponibilité du fournisseur de cloud, alors le mécanisme d'éviction ne prend pas en compte l'indisponibilité par zone.

Une raison clé de répartir vos nœuds sur plusieurs zones de disponibilité est de permettre le déplacement de la charge de travail vers des zones saines lorsque toute une zone est hors service. Par conséquent, si tous les nœuds d'une zone sont en mauvaise santé, alors le contrôleur de nœud évacue au taux normal de --node-eviction-rate. Le cas particulier est lorsque toutes les zones sont complètement en mauvaise santé (aucun des nœuds du cluster n'est en bonne santé). Dans un tel cas, le contrôleur de nœud suppose qu'il y a un problème de connectivité entre le plan de contrôle et les nœuds, et n'effectue aucune éviction. (S'il y a eu une panne et que certains nœuds réapparaissent, le contrôleur de nœud évacue les pods des nœuds restants qui sont en mauvaise santé ou injoignables).

Le contrôleur de nœud est également responsable de l'éviction des pods s'exécutant sur des nœuds avec des taints NoExecute, sauf si ces pods tolèrent cette taint. Le contrôleur de nœud ajoute également des taints correspondant aux problèmes du nœud, tels que le nœud injoignable ou non prêt. Cela signifie que le planificateur ne placera pas de Pods sur des nœuds en mauvaise santé.

Suivi de la capacité des ressources du nœud

Les objets Nœud suivent des informations sur la capacité des ressources du Nœud : par exemple, la quantité de mémoire disponible et le nombre de CPU. Les nœuds qui s'enregistrent automatiquement rapportent leur capacité lors de l'enregistrement. Si vous les ajoutez manuellement, alors vous devez définir les informations de capacité du nœud lors de son ajout. Les nœuds qui s'enregistrent automatiquement rapportent leur capacité lors de l'enregistrement. Si vous les ajoutez manuellement, alors vous devez définir les informations de capacité du nœud lors de son ajout.

Le planificateur Kubernetes s'assure qu'il y a suffisamment de ressources pour tous les Pods sur un Nœud. Le planificateur vérifie que la somme des demandes des conteneurs sur le nœud n'est pas supérieure à la capacité du nœud. Cette somme de demandes inclut tous les conteneurs gérés par le kubelet, mais exclut tout conteneur démarré directement par le runtime de conteneur, ainsi que tout processus s'exécutant en dehors du contrôle du kubelet.

Topologie du nœud

FEATURE STATE: Kubernetes v1.27 [stable] (enabled by default: true)

Si vous avez activé la fonctionnalité TopologyManager feature gate, alors le kubelet peut utiliser des indications de topologie lors de la prise de décision d'attribution des ressources. Consultez la section Contrôler les stratégies de gestion de la topologie sur un nœud pour plus d'informations.

Gestion de la mémoire swap

FEATURE STATE: Kubernetes v1.30 [beta] (enabled by default: true)

Pour activer la mémoire swap sur un nœud, la fonctionnalité NodeSwap doit être activée sur le kubelet (par défaut, elle est activée), et le drapeau de ligne de commande --fail-swap-on ou le paramètre de configuration failSwapOn setting doit être défini sur false. Pour permettre aux Pods d'utiliser la mémoire swap, swapBehavior ne doit pas être défini sur NoSwap (qui est le comportement par défaut) dans la configuration du kubelet.

Un utilisateur peut également configurer facultativement memorySwap.swapBehavior afin de spécifier comment un nœud utilisera la mémoire swap. Par exemple,

memorySwap:
  swapBehavior: LimitedSwap
  • NoSwap (par défaut) : Les charges de travail Kubernetes n'utiliseront pas la mémoire swap.
  • LimitedSwap : L'utilisation de la mémoire swap par les charges de travail Kubernetes est soumise à des limitations. Seuls les Pods de QoS Burstable sont autorisés à utiliser la mémoire swap.

Si la configuration pour memorySwap n'est pas spécifiée et que la fonctionnalité est activée, par défaut, le kubelet appliquera le même comportement que le paramètre NoSwap.

Avec LimitedSwap, les Pods qui ne relèvent pas de la classification QoS Burstable (c'est-à-dire les Pods QoS BestEffort/Guaranteed) sont interdits d'utiliser la mémoire swap. Pour maintenir les garanties de sécurité et de santé du nœud mentionnées ci-dessus, ces Pods ne sont pas autorisés à utiliser la mémoire swap lorsque LimitedSwap est en vigueur.

Avant de détailler le calcul de la limite d'échange, il est nécessaire de définir les termes suivants :

  • nodeTotalMemory : La quantité totale de mémoire physique disponible sur le nœud.
  • totalPodsSwapAvailable : La quantité totale de mémoire swap sur le nœud disponible pour une utilisation par les Pods (une partie de la mémoire swap peut être réservée à des fins système).
  • containerMemoryRequest : La demande de mémoire du conteneur.

La limitation d'échange est configurée comme suit : (containerMemoryRequest / nodeTotalMemory) * totalPodsSwapAvailable.

Il est important de noter que, pour les conteneurs dans les Pods de QoS Burstable, il est possible de désactiver l'utilisation de l'échange en spécifiant des demandes de mémoire égales aux limites de mémoire. Les conteneurs configurés de cette manière n'auront pas accès à la mémoire swap.

L'échange est pris en charge uniquement avec cgroup v2, cgroup v1 n'est pas pris en charge.

Pour plus d'informations, et pour aider aux tests et fournir des commentaires, veuillez consulter l'article de blog sur Kubernetes 1.28 : NodeSwap passe en version Beta1, KEP-2400 et sa proposition de conception.

A suivre

En savoir plus sur les éléments suivants :

2 - Communication entre les nœuds et le plan de contrôle

Ce document répertorie les chemins de communication entre le serveur API et le cluster Kubernetes. L'objectif est de permettre aux utilisateurs de personnaliser leur installation pour renforcer la configuration réseau afin que le cluster puisse fonctionner sur un réseau non fiable (ou sur des adresses IP publiques complètement) fournies par un fournisseur de cloud.

Nœud vers le plan de contrôle

Kubernetes utilise un modèle d'API de type "hub-et-spoke". Toutes les utilisations de l'API à partir des nœuds (ou des pods qu'ils exécutent) se terminent au niveau du serveur API. Aucun des autres composants du plan de contrôle n'est conçu pour exposer des services distants. Le serveur API est configuré pour écouter les connexions distantes sur un port HTTPS sécurisé (généralement le port 443) avec une ou plusieurs formes d'authentification client activées. Une ou plusieurs formes d'autorisation devraient être activées, en particulier si les requêtes anonymes ou les jetons de compte de service sont autorisés.

Les nœuds doivent être provisionnés avec le certificat racine public pour le cluster afin qu'ils puissent se connecter de manière sécurisée au serveur API avec des informations d'identification client valides. Une bonne approche consiste à ce que les informations d'identification client fournies au kubelet soient sous la forme d'un certificat client. Consultez l'amorçage TLS du kubelet pour la provision automatisée des certificats client du kubelet.

Les pods qui souhaitent se connecter au serveur API peuvent le faire de manière sécurisée en utilisant un compte de service de sorte que Kubernetes injecte automatiquement le certificat racine public et un jeton d'accès valide dans le pod lors de son instanciation. Le service kubernetes (dans le namespace default) est configuré avec une adresse IP virtuelle qui est redirigée (via kube-proxy) vers le point de terminaison HTTPS du serveur API.

Les composants du plan de contrôle communiquent également avec le serveur API via le port sécurisé.

Par conséquent, le mode de fonctionnement par défaut des connexions des nœuds et des pods exécutés sur les nœuds vers le plan de contrôle est sécurisé par défaut et peut fonctionner sur des réseaux non fiables et/ou publics.

Plan de contrôle vers le nœud

Il existe deux chemins de communication principaux du plan de contrôle (le serveur API) vers les nœuds. Le premier est du serveur API au processus kubelet qui s'exécute sur chaque nœud du cluster. Le deuxième est du serveur API vers n'importe quel nœud, pod ou service via la fonctionnalité de proxy du serveur API.

Serveur API vers kubelet

Les connexions du serveur API au kubelet sont utilisées pour :

  • Récupérer les journaux des pods.
  • Se connecter (généralement via kubectl) aux pods en cours d'exécution.
  • Fournir la fonctionnalité de transfert de port du kubelet.

Ces connexions se terminent au niveau du point de terminaison HTTPS du kubelet. Par défaut, le serveur API ne vérifie pas le certificat de service du kubelet, ce qui rend la connexion vulnérable aux attaques de l'homme du milieu et non sécurisée pour une utilisation sur des réseaux non fiables et/ou publics.

Pour vérifier cette connexion, utilisez le paramètre --kubelet-certificate-authority pour fournir au serveur API un ensemble de certificats racine à utiliser pour vérifier le certificat de service du kubelet.

Si cela n'est pas possible, utilisez le tunnel SSH entre le serveur API et le kubelet si nécessaire pour éviter de se connecter via un réseau non fiable ou public.

Enfin, l'authentification et/ou l'autorisation du kubelet devraient être activées pour sécuriser l'API du kubelet.

Serveur API vers les nœuds, les pods et les services

Les connexions du serveur API vers un nœud, un pod ou un service sont par défaut des connexions HTTP non sécurisées et ne sont donc ni authentifiées ni chiffrées. Elles peuvent être exécutées via une connexion HTTPS sécurisée en préfixant https: au nom du nœud, du pod ou du service dans l'URL de l'API, mais elles ne vérifieront pas le certificat fourni par le point de terminaison HTTPS ni ne fourniront des informations d'identification client. Ainsi, bien que la connexion soit chiffrée, elle ne garantira aucune intégrité. Ces connexions ne sont actuellement pas sûres pour une utilisation sur des réseaux non fiables ou publics.

Tunnels SSH

Kubernetes prend en charge les tunnels SSH pour protéger les chemins de communication du plan de contrôle vers les nœuds. Dans cette configuration, le serveur API initie un tunnel SSH vers chaque nœud du cluster (en se connectant à le serveur SSH qui écoute sur le port 22) et fait passer tout le trafic destiné à un kubelet, un nœud, un pod ou un service à travers le tunnel. Ce tunnel garantit que le trafic n'est pas exposé en dehors du réseau dans lequel les nœuds sont exécutés.

Service Konnectivity

FEATURE STATE: Kubernetes v1.18 [beta]

En remplacement des tunnels SSH, le service Konnectivity fournit un proxy de niveau TCP pour la communication entre le plan de contrôle et le cluster. Le service Konnectivity se compose de deux parties : le serveur Konnectivity dans le réseau du plan de contrôle et les agents Konnectivity dans le réseau des nœuds. Les agents Konnectivity initient des connexions vers le serveur Konnectivity et maintiennent les connexions réseau. Après avoir activé le service Konnectivity, tout le trafic du plan de contrôle vers les nœuds passe par ces connexions.

Suivez la tâche du service Konnectivity pour configurer le service Konnectivity dans votre cluster.

A suivre

3 - Contrôleurs

En robotique et automatisation, une boucle de contrôle est une boucle non terminante qui régule l'état d'un système.

Voici un exemple de boucle de contrôle : un thermostat dans une pièce.

Lorsque vous réglez la température, vous indiquez au thermostat votre état souhaité. La température réelle de la pièce est l' état actuel. Le thermostat agit pour rapprocher l'état actuel de l'état souhaité, en allumant ou éteignant l'équipement.

Boucle de contrôle surveillant l'état partagé du cluster à travers l'apiserver et effectuant des changements en essayant de déplacer l'état actuel vers l'état désiré.

Modèle de contrôleur

Un contrôleur suit au moins un type de ressource Kubernetes. Ces objets ont un champ spec qui représente l'état souhaité. Les contrôleurs de cette ressource sont responsables de rapprocher l'état actuel de cet état souhaité.

Le contrôleur peut effectuer lui-même l'action ; plus couramment, dans Kubernetes, un contrôleur enverra des messages au serveur API qui ont des effets secondaires utiles. Vous verrez des exemples de cela ci-dessous.

Contrôle via le serveur API

Le contrôleur de Job est un exemple de contrôleur intégré à Kubernetes. Les contrôleurs intégrés gèrent l'état en interagissant avec le serveur API du cluster.

Job est une ressource Kubernetes qui exécute un Pod, ou peut-être plusieurs Pods, pour effectuer une tâche, puis s'arrête.

(Une fois planifiés, les objets Pod font partie de l' état souhaité pour un kubelet).

Lorsque le contrôleur de Job voit une nouvelle tâche, il s'assure que, quelque part dans votre cluster, les kubelets sur un ensemble de nœuds exécutent le bon nombre de Pods pour effectuer le travail. Le contrôleur de Job n'exécute aucun Pod ou conteneur lui-même. Au lieu de cela, le contrôleur de Job demande au serveur API de créer ou supprimer des Pods. D'autres composants du plan de contrôle agissent sur les nouvelles informations (il y a de nouveaux Pods à planifier et à exécuter), et finalement le travail est terminé.

Après avoir créé un nouveau Job, l'état souhaité est que ce Job soit terminé. Le contrôleur de Job rapproche l'état actuel de ce Job de votre état souhaité : en créant des Pods qui effectuent le travail que vous avez demandé pour ce Job, de sorte que le Job soit plus proche de l'achèvement.

Les contrôleurs mettent également à jour les objets qui les configurent. Par exemple : une fois le travail terminé pour un Job, le contrôleur de Job met à jour cet objet Job pour le marquer comme Terminé.

(C'est un peu comme certains thermostats éteignent une lumière pour indiquer que votre pièce est maintenant à la température que vous avez réglée).

Contrôle direct

Contrairement à Job, certains contrôleurs doivent apporter des modifications à des éléments en dehors de votre cluster.

Par exemple, si vous utilisez une boucle de contrôle pour vous assurer qu'il y a suffisamment de nœuds dans votre cluster, alors ce contrôleur a besoin de quelque chose en dehors du cluster actuel pour configurer de nouveaux nœuds lorsque cela est nécessaire.

Les contrôleurs qui interagissent avec un état externe trouvent leur état souhaité à partir du serveur API, puis communiquent directement avec un système externe pour rapprocher l'état actuel en ligne.

(Il existe en fait un contrôleur qui met à l'échelle horizontalement les nœuds de votre cluster.)

Le point important ici est que le contrôleur apporte certaines modifications pour atteindre votre état souhaité, puis rapporte l'état actuel à votre serveur API de cluster. D'autres boucles de contrôle peuvent observer ces données rapportées et prendre leurs propres mesures.

Dans l'exemple du thermostat, si la pièce est très froide, un autre contrôleur pourrait également allumer un radiateur de protection contre le gel. Avec les clusters Kubernetes, le plan de contrôle fonctionne indirectement avec des outils de gestion des adresses IP, des services de stockage, des API de fournisseurs de cloud et d'autres services en étendant Kubernetes pour les implémenter.

État souhaité par rapport à l'état actuel

Kubernetes adopte une vision nativement cloud des systèmes et est capable de gérer un changement constant.

Votre cluster peut changer à tout moment à mesure que le travail se déroule et que les boucles de contrôle corrigent automatiquement les défaillances. Cela signifie que, potentiellement, votre cluster n'atteint jamais un état stable.

Tant que les contrôleurs de votre cluster sont en cours d'exécution et capables de effectuer des modifications utiles, il n'importe pas si l'état global est stable ou non.

Conception

En tant que principe de sa conception, Kubernetes utilise de nombreux contrôleurs qui gèrent chacun un aspect particulier de l'état du cluster. Le plus souvent, une boucle de contrôle (contrôleur) utilise un type de ressource comme état souhaité et gère un autre type de ressource pour réaliser cet état souhaité. Par exemple, un contrôleur pour les Jobs suit les objets Job (pour découvrir un nouveau travail) et les objets Pod (pour exécuter les Jobs, puis voir quand le travail est terminé). Dans ce cas, quelque chose d'autre crée les Jobs, tandis que le contrôleur de Job crée les Pods.

Il est utile d'avoir des contrôleurs simples plutôt qu'un ensemble monolithique de boucles de contrôle interconnectées. Les contrôleurs peuvent échouer, c'est pourquoi Kubernetes est conçu pour le permettre.

Modes d'exécution des contrôleurs

Kubernetes est livré avec un ensemble de contrôleurs intégrés qui s'exécutent à l'intérieur du kube-controller-manager. Ces contrôleurs intégrés fournissent des comportements de base importants.

Le contrôleur de Déploiement et le contrôleur de Job sont des exemples de contrôleurs qui font partie de Kubernetes lui-même (contrôleurs "intégrés"). Kubernetes vous permet d'exécuter un plan de contrôle résilient, de sorte que si l'un des contrôleurs intégrés venait à échouer, une autre partie du plan de contrôle prendra en charge le travail.

Vous pouvez trouver des contrôleurs qui s'exécutent en dehors du plan de contrôle pour étendre Kubernetes. Ou, si vous le souhaitez, vous pouvez écrire vous-même un nouveau contrôleur. Vous pouvez exécuter votre propre contrôleur sous la forme d'un ensemble de Pods, ou en dehors de Kubernetes. Ce qui convient le mieux dépendra de ce que ce contrôleur particulier fait.

A suivre

4 - Lease

Les systèmes distribués ont souvent besoin de Lease, qui fournissent un mécanisme pour verrouiller les ressources partagées et coordonner l'activité entre les membres d'un ensemble. Dans Kubernetes, le concept de bail est représenté par les objets Lease dans le groupe d'API coordination.k8s.io Groupe d'API, qui sont utilisés pour des fonctionnalités critiques du système telles que les battements de cœur des nœuds et l'élection du leader au niveau des composants.

Battements de cœur des nœuds

Kubernetes utilise l'API Lease pour communiquer les battements de cœur des nœuds kubelet au serveur API Kubernetes. Pour chaque Node, il existe un objet Lease avec un nom correspondant dans le namespace kube-node-lease. Sous le capot, chaque battement de cœur kubelet est une demande de mise à jour de cet objet Lease, mettant à jour le champ spec.renewTime pour le bail. Le plan de contrôle Kubernetes utilise le horodatage de ce champ pour déterminer la disponibilité de ce Node.

Consultez Objets de bail de nœud pour plus de détails.

Élection du leader

Kubernetes utilise également des Lease pour s'assurer qu'une seule instance d'un composant est en cours d'exécution à tout moment. Cela est utilisé par les composants du plan de contrôle tels que kube-controller-manager et kube-scheduler dans les configurations HA, où une seule instance du composant doit être en cours d'exécution activement tandis que les autres instances sont en attente.

Lisez élection coordonnée du leader pour en savoir plus sur la façon dont Kubernetes s'appuie sur l'API Lease pour sélectionner quelle instance de composant agit en tant que leader.

Identité du serveur API

FEATURE STATE: Kubernetes v1.26 [beta] (enabled by default: true)

À partir de Kubernetes v1.26, chaque kube-apiserver utilise l'API Lease pour publier son identité au reste du système. Bien que cela ne soit pas particulièrement utile en soi, cela fournit un mécanisme pour les clients afin de découvrir combien d'instances de kube-apiserver opèrent sur le plan de contrôle Kubernetes. L'existence des Lease kube-apiserver permet des fonctionnalités futures qui peuvent nécessiter une coordination entre chaque kube-apiserver.

Vous pouvez inspecter les Lease détenus par chaque kube-apiserver en vérifiant les objets de bail dans le namespace kube-system avec le nom kube-apiserver-<sha256-hash>. Alternativement, vous pouvez utiliser le sélecteur d'étiquettes apiserver.kubernetes.io/identity=kube-apiserver:

kubectl -n kube-system get lease -l apiserver.kubernetes.io/identity=kube-apiserver
NOM                                         HOLDER                                                                           ÂGE
apiserver-07a5ea9b9b072c4a5f3d1c3702        apiserver-07a5ea9b9b072c4a5f3d1c3702_0c8914f7-0f35-440e-8676-7844977d3a05        5m33s
apiserver-7be9e061c59d368b3ddaf1376e        apiserver-7be9e061c59d368b3ddaf1376e_84f2a85d-37c1-4b14-b6b9-603e62e4896f        4m23s
apiserver-1dfef752bcb36637d2763d1868        apiserver-1dfef752bcb36637d2763d1868_c5ffa286-8a9a-45d4-91e7-61118ed58d2e        4m43s

Le hachage SHA256 utilisé dans le nom du bail est basé sur le nom d'hôte du système d'exploitation tel que vu par ce serveur API. Chaque kube-apiserver devrait être configuré pour utiliser un nom d'hôte qui est unique dans le cluster. Les nouvelles instances de kube-apiserver qui utilisent le même nom d'hôte prendront le contrôle des Lease existants en utilisant une nouvelle identité de détenteur, au lieu d'instancier de nouveaux objets de bail. Vous pouvez vérifier le nom d'hôte utilisé par kube-apisever en vérifiant la valeur de l'étiquette kubernetes.io/hostname:

kubectl -n kube-system get lease apiserver-07a5ea9b9b072c4a5f3d1c3702 -o yaml
apiVersion: coordination.k8s.io/v1
kind: Lease
metadata:
  creationTimestamp: "2023-07-02T13:16:48Z"
  labels:
    apiserver.kubernetes.io/identity: kube-apiserver
    kubernetes.io/hostname: master-1
  name: apiserver-07a5ea9b9b072c4a5f3d1c3702
  namespace: kube-system
  resourceVersion: "334899"
  uid: 90870ab5-1ba9-4523-b215-e4d4e662acb1
spec:
  holderIdentity: apiserver-07a5ea9b9b072c4a5f3d1c3702_0c8914f7-0f35-440e-8676-7844977d3a05
  leaseDurationSeconds: 3600
  renewTime: "2023-07-04T21:58:48.065888Z"

Les Lease expirés des kube-apiservers qui n'existent plus sont collectés par les nouveaux kube-apiservers après 1 heure.

Vous pouvez désactiver les Lease d'identité du serveur API en désactivant la fonctionnalité APIServerIdentity feature gate.

Charges de travail

Votre propre charge de travail peut définir son propre usage des Lease. Par exemple, vous pouvez exécuter un contrôleur personnalisé où un membre principal ou leader effectue des opérations que ses pairs ne font pas. Vous définissez un bail afin que les réplicas du contrôleur puissent sélectionner ou élire un leader, en utilisant l'API Kubernetes pour la coordination. Si vous utilisez un bail, il est bon de pratiquer de définir un nom pour le bail qui est clairement lié au produit ou au composant. Par exemple, si vous avez un composant nommé Example Foo, utilisez un bail nommé example-foo.

Si un opérateur de cluster ou un autre utilisateur final peut déployer plusieurs instances d'un composant, sélectionnez un préfixe de nom et choisissez un mécanisme (comme le hachage du nom du déploiement) pour éviter les collisions de noms pour les Lease.

Vous pouvez utiliser une autre approche tant qu'elle atteint le même résultat : les différents produits logiciels ne entrent pas en conflit les uns avec les autres.

5 - Gestionnaire du contrôleur de cloud

FEATURE STATE: Kubernetes v1.11 [beta]

Les technologies d'infrastructure cloud vous permettent d'exécuter Kubernetes sur des clouds publics, privés et hybrides. Kubernetes croit en une infrastructure automatisée pilotée par API sans couplage étroit entre les composants.

Le gestionnaire du contrôleur de cloud est le Cloud Controller Manager est une fonctionnalité alpha de la version 1.8. Dans les prochaines versions, il deviendra le moyen privilégié pour l'intégration de Kubernetes à n'importe quel cloud.

Kubernetes v1.6 contient un nouveau binaire appelé cloud-controller-manager. Le cloud-controller-manager est un service qui intègre des boucles de contrôle propres au cloud. Ces boucles de contrôle spécifiques au cloud se trouvaient à l'origine dans le kube-controller-manager. Étant donné que les fournisseurs de cloud développent et mettent à jour leurs produits à un rythme différent de celui du projet Kubernetes, l'abstraction du code spécifique au fournisseur, au niveau du binaire cloud-controller-manager, permet aux fournisseurs de cloud d'évoluer indépendamment du code principal de Kubernetes.

Le gestionnaire du contrôleur de cloud est structuré à l'aide d'un mécanisme de plugin qui permet aux différents fournisseurs de cloud d'intégrer leurs plateformes à Kubernetes.

Conception

Composants de Kubernetes

Le gestionnaire du contrôleur de cloud s'exécute dans le plan de contrôle en tant qu'ensemble répliqué de processus (généralement, ce sont des conteneurs dans des Pods). Chaque gestionnaire du contrôleur de cloud implémente plusieurs contrôleurs dans un seul processus.

Fonctions du gestionnaire du contrôleur de cloud

Les contrôleurs à l'intérieur du gestionnaire du contrôleur de cloud comprennent :

Contrôleur de nœud

Le contrôleur de nœud est responsable de la mise à jour des objets Nœud lorsque de nouveaux serveurs sont créés dans votre infrastructure cloud. Le contrôleur de nœud obtient des informations sur les hôtes en cours d'exécution dans votre tenancy avec le fournisseur de cloud. Le contrôleur de nœud effectue les fonctions suivantes :

  1. Mettre à jour un objet Nœud avec l'identifiant unique du serveur obtenu à partir de l'API du fournisseur de cloud.
  2. Annoter et étiqueter l'objet Nœud avec des informations spécifiques au cloud, telles que la région dans laquelle le nœud est déployé et les ressources (CPU, mémoire, etc.) dont il dispose.
  3. Obtenir le nom d'hôte et les adresses réseau du nœud.
  4. Vérifier la santé du nœud. Si un nœud devient non réactif, ce contrôleur vérifie auprès de l'API de votre fournisseur de cloud si le serveur a été désactivé / supprimé / terminé. Si le nœud a été supprimé du cloud, le contrôleur supprime l'objet Nœud de votre cluster Kubernetes.

Certaines implémentations de fournisseurs de cloud divisent cela en un contrôleur de nœud et un contrôleur de cycle de vie de nœud distinct.

Contrôleur de route

Le contrôleur de route est responsable de la configuration des routes dans le cloud de manière appropriée afin que les conteneurs sur différents nœuds de votre cluster Kubernetes puissent communiquer entre eux.

Selon le fournisseur de cloud, le contrôleur de route peut également allouer des blocs d'adresses IP pour le réseau de Pod.

Contrôleur de service

Les services s'intègrent aux composants d'infrastructure cloud tels que les équilibreurs de charge gérés, les adresses IP, le filtrage des paquets réseau et la vérification de l'état de la cible. Le contrôleur de service interagit avec les API de votre fournisseur de cloud pour configurer les équilibreurs de charge et autres composants d'infrastructure lorsque vous déclarez une ressource Service qui les nécessite.

Autorisation

Cette section détaille l'accès requis par le gestionnaire du contrôleur de cloud sur divers objets API pour effectuer ses opérations.

Contrôleur de nœud

Le contrôleur de nœud ne fonctionne qu'avec les objets Nœud. Il nécessite un accès complet pour lire et modifier les objets Nœud.

v1/Node :

  • get
  • list
  • create
  • update
  • patch
  • watch
  • delete

Contrôleur de route

Le contrôleur de route écoute la création d'objets Nœud et configure les routes de manière appropriée. Il nécessite un accès Get aux objets Nœud.

v1/Node :

  • get

Contrôleur de service

Le contrôleur de service surveille les événements de création, de mise à jour et de suppression des objets Service, puis configure les Endpoints pour ces Services de manière appropriée (pour les EndpointSlices, le kube-controller-manager les gère à la demande).

Pour accéder aux Services, il nécessite un accès list et watch. Pour mettre à jour les Services, il nécessite un accès patch et update.

Pour configurer les ressources Endpoints pour les Services, il nécessite un accès create, list, get, watch et update.

v1/Service :

  • list
  • get
  • watch
  • patch
  • update

Autres

La mise en œuvre du cœur du gestionnaire du contrôleur de cloud nécessite un accès pour créer des objets Event et pour assurer un fonctionnement sécurisé, il nécessite un accès pour créer des comptes de service.

v1/Event :

  • create
  • patch
  • update

v1/ServiceAccount :

  • create

Le ClusterRole RBAC pour le gestionnaire du contrôleur de cloud ressemble à ceci :

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cloud-controller-manager
rules:
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
  - update
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - '*'
- apiGroups:
  - ""
  resources:
  - nodes/status
  verbs:
  - patch
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - list
  - patch
  - update
  - watch
- apiGroups:
  - ""
  resources:
  - serviceaccounts
  verbs:
  - create
- apiGroups:
  - ""
  resources:
  - persistentvolumes
  verbs:
  - get
  - list
  - update
  - watch
- apiGroups:
  - ""
  resources:
  - endpoints
  verbs:
  - create
  - get
  - list
  - watch
  - update

A suivre

  • Administration du gestionnaire du contrôleur de cloud contient des instructions sur l'exécution et la gestion du gestionnaire du contrôleur de cloud.

  • Pour mettre à niveau un plan de contrôle haute disponibilité pour utiliser le gestionnaire du contrôleur de cloud, consultez Migrer le plan de contrôle répliqué pour utiliser le gestionnaire du contrôleur de cloud.

  • Vous voulez savoir comment implémenter votre propre gestionnaire du contrôleur de cloud ou étendre un projet existant ?

    • Le gestionnaire du contrôleur de cloud utilise des interfaces Go, en particulier, l'interface CloudProvider définie dans cloud.go de kubernetes/cloud-provider pour permettre l'intégration de toutes les implémentations de cloud.
    • La mise en œuvre des contrôleurs partagés mis en évidence dans ce document (Nœud, Route et Service), ainsi que certaines structures de base avec l'interface cloudprovider partagée, font partie du cœur de Kubernetes. Les implémentations spécifiques aux fournisseurs de cloud se trouvent en dehors du cœur de Kubernetes et implémentent l'interface CloudProvider.
    • Pour plus d'informations sur le développement de plugins, consultez Développement du gestionnaire du contrôleur de cloud.

6 - À propos de cgroup v2

Sur Linux, les groupes de contrôle limitent les ressources allouées aux processus.

Le kubelet et le runtime de conteneur sous-jacent doivent interagir avec les cgroups pour appliquer la gestion des ressources pour les pods et les conteneurs, ce qui inclut les demandes et les limites de CPU/mémoire pour les charges de travail conteneurisées.

Il existe deux versions de cgroups sur Linux : cgroup v1 et cgroup v2. cgroup v2 est la nouvelle génération de l'API cgroup.

Qu'est-ce que cgroup v2 ?

FEATURE STATE: Kubernetes v1.25 [stable]

cgroup v2 est la prochaine version de l'API cgroup de Linux. cgroup v2 offre un système de contrôle unifié avec des capacités de gestion des ressources améliorées.

cgroup v2 propose plusieurs améliorations par rapport à cgroup v1, telles que :

  • Conception d'une hiérarchie unifiée unique dans l'API
  • Délégation plus sûre des sous-arbres aux conteneurs
  • Nouvelles fonctionnalités telles que Pressure Stall Information
  • Gestion améliorée de l'allocation des ressources et de l'isolation sur plusieurs ressources
    • Comptabilité unifiée pour différents types d'allocations de mémoire (mémoire réseau, mémoire du noyau, etc.)
    • Comptabilité des modifications de ressources non immédiates, telles que les écritures de cache de pages

Certaines fonctionnalités de Kubernetes utilisent exclusivement cgroup v2 pour une gestion des ressources et une isolation améliorées. Par exemple, la fonctionnalité MemoryQoS améliore la QoS de la mémoire et repose sur les primitives cgroup v2.

Utilisation de cgroup v2

La manière recommandée d'utiliser cgroup v2 est d'utiliser une distribution Linux qui active et utilise cgroup v2 par défaut.

Pour vérifier si votre distribution utilise cgroup v2, consultez Identifier la version de cgroup sur les nœuds Linux.

Exigences

cgroup v2 a les exigences suivantes :

  • La distribution OS active cgroup v2
  • La version du noyau Linux est 5.8 ou ultérieure
  • Le runtime de conteneur prend en charge cgroup v2. Par exemple :
  • Le kubelet et le runtime de conteneur sont configurés pour utiliser le driver cgroup systemd

Prise en charge de cgroup v2 par les distributions Linux

Pour une liste des distributions Linux qui utilisent cgroup v2, consultez la documentation cgroup v2

  • Container Optimized OS (depuis M97)
  • Ubuntu (depuis 21.10, 22.04+ recommandé)
  • Debian GNU/Linux (depuis Debian 11 bullseye)
  • Fedora (depuis 31)
  • Arch Linux (depuis avril 2021)
  • RHEL et les distributions similaires à RHEL (depuis 9)

Pour vérifier si votre distribution utilise cgroup v2, consultez la documentation de votre distribution ou suivez les instructions de Identifier la version de cgroup sur les nœuds Linux.

Vous pouvez également activer manuellement cgroup v2 sur votre distribution Linux en modifiant les arguments de démarrage de la ligne de commande du noyau. Si votre distribution utilise GRUB, systemd.unified_cgroup_hierarchy=1 doit être ajouté dans GRUB_CMDLINE_LINUX sous /etc/default/grub, suivi de sudo update-grub. Cependant, l'approche recommandée est d'utiliser une distribution qui active déjà cgroup v2 par défaut.

Migration vers cgroup v2

Pour migrer vers cgroup v2, assurez-vous de respecter les exigences, puis mettez à jour vers une version du noyau qui active cgroup v2 par défaut.

Le kubelet détecte automatiquement si le système d'exploitation utilise cgroup v2 et agit en conséquence, sans nécessiter de configuration supplémentaire.

Il ne devrait pas y avoir de différence perceptible dans l'expérience utilisateur lors du passage à cgroup v2, sauf si les utilisateurs accèdent directement au système de fichiers cgroup soit sur le nœud, soit depuis les conteneurs.

cgroup v2 utilise une API différente de cgroup v1, donc si des applications accèdent directement au système de fichiers cgroup, elles doivent être mises à jour vers des versions plus récentes qui prennent en charge cgroup v2. Par exemple :

  • Certains agents de surveillance et de sécurité tiers peuvent dépendre du système de fichiers cgroup. Mettez à jour ces agents vers des versions qui prennent en charge cgroup v2.
  • Si vous exécutez cAdvisor en tant que DaemonSet autonome pour surveiller les pods et les conteneurs, mettez-le à jour vers la version 0.43.0 ou ultérieure.
  • Si vous déployez des applications Java, préférez utiliser des versions qui prennent en charge pleinement cgroup v2 :
  • Si vous utilisez le package uber-go/automaxprocs, assurez-vous d'utiliser la version v1.5.1 ou supérieure.

Identifier la version de cgroup sur les nœuds Linux

La version de cgroup dépend de la distribution Linux utilisée et de la version de cgroup par défaut configurée sur le système d'exploitation. Pour vérifier quelle version de cgroup votre distribution utilise, exécutez la commande stat -fc %T /sys/fs/cgroup/ sur le nœud :

stat -fc %T /sys/fs/cgroup/

Pour cgroup v2, la sortie est cgroup2fs.

Pour cgroup v1, la sortie est tmpfs.

A suivre

7 - Interface de Runtime de Conteneur (CRI)

Le CRI (Container Runtime Interface) est une interface de plugin qui permet au kubelet d'utiliser une grande variété de runtimes de conteneurs, sans avoir besoin de recompiler les composants du cluster.

Vous avez besoin d'un runtime de conteneur fonctionnel sur chaque nœud de votre cluster, afin que le kubelet puisse lancer Pods et leurs conteneurs.

L'Interface de Runtime de Conteneur (CRI) est le protocole principal pour la communication entre le kubelet et le Runtime de Conteneur.

L'Interface du Runtime de Conteneur (CRI) de Kubernetes définit le protocole principal gRPC pour la communication entre les composants du nœud kubelet et le runtime de conteneur.

L'API

FEATURE STATE: Kubernetes v1.23 [stable]

Le kubelet agit en tant que client lorsqu'il se connecte au runtime de conteneur via gRPC. Les points de terminaison du service de runtime et d'image doivent être disponibles dans le runtime de conteneur, ce qui peut être configuré séparément dans le kubelet en utilisant les indicateurs de ligne de commande --image-service-endpoint (voir la référence des options du kubelet).

Pour Kubernetes v1.31, le kubelet préfère utiliser CRI v1. Si un runtime de conteneur ne prend pas en charge v1 de CRI, alors le kubelet essaie de négocier toute version plus ancienne prise en charge. Le kubelet de v1.31 peut également négocier CRI v1alpha2, mais cette version est considérée comme obsolète. Si le kubelet ne peut pas négocier une version de CRI prise en charge, le kubelet abandonne et ne s'enregistre pas en tant que nœud.

Mise à niveau

Lors de la mise à niveau de Kubernetes, le kubelet essaie de sélectionner automatiquement la dernière version de CRI lors du redémarrage du composant. Si cela échoue, alors le fallback aura lieu comme mentionné ci-dessus. Si une nouvelle connexion gRPC était nécessaire car le runtime de conteneur a été mis à niveau, alors le runtime de conteneur doit également prendre en charge la version initialement sélectionnée, sinon la reconnexion est censée échouer. Cela nécessite un redémarrage du kubelet.

A suivre

  • En savoir plus sur la définition du protocole CRI ici

8 - Collecte des déchets

Le Garbage collection est un terme générique désignant les différents mécanismes utilisés par Kubernetes pour nettoyer les ressources du cluster. Cela permet le nettoyage des ressources suivantes :

Propriétaires et dépendants

De nombreux objets dans Kubernetes sont liés les uns aux autres par le biais de références de propriétaire. Les références de propriétaire indiquent au plan de contrôle quels objets dépendent des autres. Kubernetes utilise les références de propriétaire pour permettre au plan de contrôle et aux autres clients de l'API de nettoyer les ressources associées avant de supprimer un objet. Dans la plupart des cas, Kubernetes gère automatiquement les références de propriétaire.

La propriété est différente du mécanisme étiquettes et sélecteurs que certains ressources utilisent également. Par exemple, considérez un Service qui crée des objets EndpointSlice. Le Service utilise des étiquettes pour permettre au plan de contrôle de déterminer quels objets EndpointSlice sont utilisés pour ce Service. En plus des étiquettes, chaque EndpointSlice géré au nom d'un Service a une référence de propriétaire. Les références de propriétaire aident les différentes parties de Kubernetes à éviter d'interférer avec les objets qu'elles ne contrôlent pas.

Suppression en cascade

Kubernetes vérifie et supprime les objets qui n'ont plus de références de propriétaire, comme les pods laissés derrière lors de la suppression d'un ReplicaSet. Lorsque vous supprimez un objet, vous pouvez contrôler si Kubernetes supprime automatiquement les objets dépendants, dans un processus appelé suppression en cascade. Il existe deux types de suppression en cascade, comme suit :

  • Suppression en cascade en premier plan
  • Suppression en cascade en arrière-plan

Vous pouvez également contrôler comment et quand la collecte des déchets supprime les ressources qui ont des références de propriétaire en utilisant les finalizers Kubernetes.

Suppression en cascade en premier plan

Dans la suppression en cascade en premier plan, l'objet propriétaire que vous supprimez entre d'abord dans un état de suppression en cours. Dans cet état, les actions suivantes se produisent sur l'objet propriétaire :

  • Le serveur API Kubernetes définit le champ metadata.deletionTimestamp de l'objet sur l'heure à laquelle l'objet a été marqué pour suppression.
  • Le serveur API Kubernetes définit également le champ metadata.finalizers sur foregroundDeletion.
  • L'objet reste visible via l'API Kubernetes jusqu'à ce que le processus de suppression soit terminé.

Après que l'objet propriétaire entre dans l'état de suppression en cours, le contrôleur supprime les dépendants. Après avoir supprimé tous les objets dépendants, le contrôleur supprime l'objet propriétaire. À ce stade, l'objet n'est plus visible dans l'API Kubernetes.

Pendant la suppression en cascade en premier plan, seuls les dépendants qui bloquent la suppression du propriétaire sont ceux qui ont le champ ownerReference.blockOwnerDeletion=true. Consultez Utiliser la suppression en cascade en premier plan pour en savoir plus.

Suppression en cascade en arrière-plan

Dans la suppression en cascade en arrière-plan, le serveur API Kubernetes supprime immédiatement l'objet propriétaire et le contrôleur nettoie les objets dépendants en arrière-plan. Par défaut, Kubernetes utilise la suppression en cascade en arrière-plan, sauf si vous utilisez manuellement la suppression en premier plan ou choisissez d'abandonner les objets dépendants.

Consultez Utiliser la suppression en cascade en arrière-plan pour en savoir plus.

Dépendants orphelins

Lorsque Kubernetes supprime un objet propriétaire, les dépendants laissés derrière sont appelés objets orphelins. Par défaut, Kubernetes supprime les objets dépendants. Pour apprendre comment outrepasser ce comportement, consultez Supprimer les objets propriétaires et les dépendants orphelins.

Collecte des déchets des conteneurs et des images inutilisés

Le kubelet effectue la collecte des déchets sur les images inutilisées toutes les deux minutes et sur les conteneurs inutilisés toutes les minutes. Vous devez éviter d'utiliser des outils de collecte des déchets externes, car ils peuvent perturber le comportement du kubelet et supprimer des conteneurs qui devraient exister.

Pour configurer les options de collecte des déchets des conteneurs et des images inutilisés, ajustez le kubelet en utilisant un fichier de configuration et modifiez les paramètres liés à la collecte des déchets en utilisant le type de ressource KubeletConfiguration.

Cycle de vie des images de conteneur

Kubernetes gère le cycle de vie de toutes les images via son gestionnaire d'images, qui fait partie du kubelet, en collaboration avec cadvisor. Le kubelet prend en compte les limites d'utilisation du disque suivantes lors de la prise de décision de collecte des déchets :

  • HighThresholdPercent
  • LowThresholdPercent

Une utilisation du disque supérieure à la valeur configurée de HighThresholdPercent déclenche la collecte des déchets, qui supprime les images dans l'ordre en fonction de leur dernière utilisation, en commençant par les plus anciennes en premier. Le kubelet supprime les images jusqu'à ce que l'utilisation du disque atteigne la valeur LowThresholdPercent.

Collecte des déchets pour les images de conteneur inutilisées

FEATURE STATE: Kubernetes v1.30 [beta] (enabled by default: true)

En tant que fonctionnalité bêta, vous pouvez spécifier la durée maximale pendant laquelle une image locale peut rester inutilisée, indépendamment de l'utilisation du disque. Il s'agit d'un paramètre du kubelet que vous configurez pour chaque nœud.

Pour configurer le paramètre, activez la fonctionnalité ImageMaximumGCAge feature gate pour le kubelet, et définissez également une valeur pour le champ imageMaximumGCAge dans le fichier de configuration du kubelet.

La valeur est spécifiée en tant que durée Kubernetes ; Les unités de temps valides pour le champ imageMaximumGCAge dans le fichier de configuration du kubelet sont :

  • "ns" pour les nanosecondes
  • "us" ou "µs" pour les microsecondes
  • "ms" pour les millisecondes
  • "s" pour les secondes
  • "m" pour les minutes
  • "h" pour les heures

Par exemple, vous pouvez définir le champ de configuration sur 12h45m, ce qui signifie 12 heures et 45 minutes.

Collecte des déchets des conteneurs

Le kubelet collecte les conteneurs inutilisés en fonction des variables suivantes, que vous pouvez définir :

  • MinAge : l'âge minimum auquel le kubelet peut collecter les conteneurs. Désactivez en définissant sur 0.
  • MaxPerPodContainer : le nombre maximum de conteneurs inactifs que chaque Pod peut avoir. Désactivez en définissant sur une valeur inférieure à 0.
  • MaxContainers : le nombre maximum de conteneurs inactifs que le cluster peut avoir. Désactivez en définissant sur une valeur inférieure à 0.

En plus de ces variables, le kubelet collecte les conteneurs non identifiés et supprimés, généralement en commençant par les plus anciens.

MaxPerPodContainer et MaxContainers peuvent potentiellement entrer en conflit les uns avec les autres dans des situations où le maintien du nombre maximum de conteneurs par Pod (MaxPerPodContainer) dépasserait le total autorisé de conteneurs inactifs globaux (MaxContainers). Dans cette situation, le kubelet ajuste MaxPerPodContainer pour résoudre le conflit. Le pire des cas serait de réduire MaxPerPodContainer à 1 et d'évacuer les conteneurs les plus anciens. De plus, les conteneurs appartenant à des pods qui ont été supprimés sont supprimés une fois qu'ils sont plus anciens que MinAge.

Configuration de la collecte des déchets

Vous pouvez ajuster la collecte des déchets des ressources en configurant des options spécifiques aux contrôleurs qui gèrent ces ressources. Les pages suivantes vous montrent comment configurer la collecte des déchets :

A suivre

9 - Proxy de version mixte

FEATURE STATE: Kubernetes v1.28 [alpha] (enabled by default: false)

Kubernetes 1.31 inclut une fonctionnalité alpha qui permet à un Serveur API de faire proxy des demandes de ressources vers d'autres serveurs API pairs. Cela est utile lorsqu'il y a plusieurs serveurs API exécutant différentes versions de Kubernetes dans un même cluster (par exemple, pendant un déploiement à long terme vers une nouvelle version de Kubernetes).

Cela permet aux administrateurs de cluster de configurer des clusters hautement disponibles qui peuvent être mis à niveau plus en toute sécurité, en redirigeant les demandes de ressources (effectuées pendant la mise à niveau) vers le kube-apiserver correct. Ce proxy empêche les utilisateurs de voir des erreurs 404 Not Found inattendues qui découlent du processus de mise à niveau.

Ce mécanisme est appelé le Proxy de Version Mixte.

Activation du Proxy de Version Mixte

Assurez-vous que la fonctionnalité UnknownVersionInteroperabilityProxy feature gate est activée lorsque vous démarrez le Serveur API :

kube-apiserver \
--feature-gates=UnknownVersionInteroperabilityProxy=true \
# arguments de ligne de commande requis pour cette fonctionnalité
--peer-ca-file=<chemin vers le certificat CA de kube-apiserver>
--proxy-client-cert-file=<chemin vers le certificat proxy de l'agrégateur>,
--proxy-client-key-file=<chemin vers la clé proxy de l'agrégateur>,
--requestheader-client-ca-file=<chemin vers le certificat CA de l'agrégateur>,
# requestheader-allowed-names peut être laissé vide pour autoriser n'importe quel nom commun
--requestheader-allowed-names=<noms communs valides pour vérifier le certificat client du proxy>,

# indicateurs facultatifs pour cette fonctionnalité
--peer-advertise-ip=`IP de ce kube-apiserver qui doit être utilisée par les pairs pour faire proxy des demandes`
--peer-advertise-port=`port de ce kube-apiserver qui doit être utilisé par les pairs pour faire proxy des demandes`

# ...et d'autres indicateurs comme d'habitude

Transport et authentification du proxy entre les serveurs API

  • Le kube-apiserver source réutilise les indicateurs d'authentification client du serveur API existant --proxy-client-cert-file et --proxy-client-key-file pour présenter son identité qui sera vérifiée par son pair (le kube-apiserver de destination). Le serveur API de destination vérifie cette connexion pair en fonction de la configuration que vous spécifiez en utilisant l'argument de ligne de commande --requestheader-client-ca-file.

  • Pour authentifier les certificats de service du serveur de destination, vous devez configurer un ensemble de certificats d'autorité de certification en spécifiant l'argument de ligne de commande --peer-ca-file au serveur API source.

Configuration pour la connectivité des serveurs API pairs

Pour définir l'emplacement réseau d'un kube-apiserver que les pairs utiliseront pour faire proxy des demandes, utilisez les arguments de ligne de commande --peer-advertise-ip et --peer-advertise-port pour kube-apiserver ou spécifiez ces champs dans le fichier de configuration du serveur API. Si ces indicateurs ne sont pas spécifiés, les pairs utiliseront la valeur de --advertise-address ou --bind-address comme argument de ligne de commande pour le kube-apiserver. Si ceux-ci ne sont pas définis non plus, l'interface par défaut de l'hôte est utilisée.

Proxy de version mixte

Lorsque vous activez le proxy de version mixte, la couche d'agrégation charge un filtre spécial qui effectue les opérations suivantes :

  • Lorsqu'une demande de ressource atteint un serveur API qui ne peut pas servir cette API (soit parce qu'il s'agit d'une version antérieure à l'introduction de l'API, soit parce que l'API est désactivée sur le serveur API), le serveur API tente d'envoyer la demande à un serveur API pair qui peut servir l'API demandée. Il le fait en identifiant les groupes d'API / versions / ressources que le serveur local ne reconnaît pas, et essaie de faire proxy de ces demandes vers un serveur API pair capable de traiter la demande.
  • Si le serveur API pair ne parvient pas à répondre, le serveur API source répond avec une erreur 503 ("Service Unavailable").

Comment cela fonctionne en interne

Lorsqu'un serveur API reçoit une demande de ressource, il vérifie d'abord quels serveurs API peuvent servir la ressource demandée. Cette vérification se fait en utilisant l'API interne StorageVersion.

  • Si la ressource est connue du serveur API qui a reçu la demande (par exemple, GET /api/v1/pods/quelque-pod), la demande est traitée localement.

  • S'il n'y a pas d'objet StorageVersion interne trouvé pour la ressource demandée (par exemple, GET /my-api/v1/my-resource) et que l'APIService configuré spécifie le proxy vers un serveur API d'extension, ce proxy se fait en suivant le flux habituel flow pour les API d'extension.

  • Si un objet StorageVersion interne valide est trouvé pour la ressource demandée (par exemple, GET /batch/v1/jobs) et que le serveur API qui essaie de traiter la demande (le serveur API de traitement) a l'API batch désactivée, alors le serveur API de traitement récupère les serveurs API pairs qui servent le groupe d'API / version / ressource pertinent (api/v1/batch dans ce cas) en utilisant les informations de l'objet StorageVersion récupéré. Le serveur API de traitement fait ensuite proxy de la demande vers l'un des serveurs kube-apiservers pairs correspondants qui sont conscients de la ressource demandée.

    • S'il n'y a aucun pair connu pour ce groupe d'API / version / ressource, le serveur API de traitement transmet la demande à sa propre chaîne de traitement qui devrait finalement renvoyer une réponse 404 ("Not Found").

    • Si le serveur API de traitement a identifié et sélectionné un serveur API pair, mais que ce pair échoue à répondre (pour des raisons telles que des problèmes de connectivité réseau ou une course de données entre la demande étant reçue et un contrôleur enregistrant les informations du pair dans le plan de contrôle), alors le serveur de traitement API répond avec une erreur 503 ("Service Unavailable").