Contactez-nous

Fonctionnement du Scheduler Kubernetes

Découvrez le processus interne du Scheduler Kubernetes : comment il sélectionne le meilleur noeud pour chaque Pod via les phases de filtrage et de scoring.

Le chef d'orchestre du placement : Introduction au Scheduler

Au coeur du control plane de Kubernetes se trouve un composant essentiel appelé le Scheduler (implémenté par le binaire `kube-scheduler`). Sa responsabilité unique et cruciale est d'assigner les Pods nouvellement créés (ou ceux qui n'ont pas encore été assignés) à des noeuds spécifiques du cluster pour qu'ils puissent y être exécutés par le Kubelet.

Le Scheduler surveille en permanence l'API Server à la recherche de Pods dont le champ spec.nodeName n'est pas encore défini. Pour chaque Pod trouvé dans cet état 'Pending' (en attente d'assignation), le Scheduler lance un processus décisionnel complexe pour identifier le noeud le plus approprié pour l'accueillir.

Ce processus vise à satisfaire un ensemble de contraintes (les besoins en ressources du Pod, les exigences d'affinité/anti-affinité, les taints/tolerations, etc.) tout en optimisant certains critères (répartition équilibrée de la charge, minimisation des ressources utilisées, etc.). Comprendre ce processus est fondamental avant d'aborder les techniques d'ordonnancement avancé qui permettent de l'influencer.

Le cycle de décision : Filtrage et Scoring

Le processus décisionnel du Scheduler pour un Pod donné se déroule typiquement en deux phases principales :

  1. Filtrage (Filtering / Predicates) : Dans cette première phase, le Scheduler applique une série de tests (appelés prédicats) à l'ensemble des noeuds disponibles dans le cluster. L'objectif est d'éliminer les noeuds qui ne sont pas capables d'accueillir le Pod. Un noeud doit satisfaire tous les prédicats pertinents pour être considéré comme 'faisable' (feasible).
  2. Scoring (Priorities) : Une fois la liste des noeuds faisables établie, la deuxième phase consiste à attribuer un score à chacun de ces noeuds. Le Scheduler utilise un ensemble de fonctions de priorité pour évaluer à quel point chaque noeud est 'souhaitable' pour le Pod. Les scores attribués par chaque fonction de priorité sont additionnés pour obtenir un score final pour chaque noeud.

Le noeud faisable ayant obtenu le score le plus élevé est alors choisi comme destination pour le Pod.

Phase 1 : Filtrage (Predicates) - Trouver les noeuds faisables

Les prédicats sont des fonctions booléennes qui vérifient si un noeud peut ou non exécuter le Pod. Si un seul prédicat échoue pour un noeud, ce dernier est écarté de la liste des candidats potentiels. Voici quelques exemples courants de prédicats appliqués :

  • PodFitsResources : Vérifie si le noeud dispose de suffisamment de ressources non allouées (CPU, mémoire, ressources étendues comme les GPU, stockage éphémère) pour satisfaire les requests du Pod.
  • PodSelectorMatches / NodeAffinity : Vérifie si les labels du noeud correspondent aux nodeSelector ou aux règles d'affinité de noeud requises (requiredDuringSchedulingIgnoredDuringExecution) spécifiées dans le Pod.
  • PodToleratesNodeTaints : Vérifie si le Pod possède les tolérances nécessaires pour tous les taints présents sur le noeud avec les effets NoSchedule ou NoExecute.
  • CheckVolumeBinding : Vérifie si les volumes demandés par le Pod (PersistentVolumeClaims) peuvent être satisfaits sur ce noeud (ex: contraintes de zone pour les volumes, disponibilité des PVs pré-provisionnés avec affinité de noeud).
  • PodFitsHostPorts : Vérifie si les ports hôtes (hostPort) demandés par les conteneurs du Pod sont déjà utilisés sur le noeud.
  • MatchInterPodAffinity : Vérifie si les règles d'affinité et d'anti-affinité de Pods (requiredDuringSchedulingIgnoredDuringExecution) peuvent être satisfaites sur ce noeud en considérant les autres Pods déjà présents.
  • NodeCondition : Filtre les noeuds qui ont certaines conditions problématiques (ex: MemoryPressure, DiskPressure, PIDPressure, NetworkUnavailable, ou qui ne sont pas Ready).

Si, à l'issue de cette phase, aucun noeud n'est jugé faisable, le Pod reste à l'état 'Pending' et le Scheduler réessaiera ultérieurement (par exemple, si de nouvelles ressources deviennent disponibles ou si la configuration du cluster change).

Phase 2 : Scoring (Priorities) - Choisir le meilleur noeud

Une fois la liste des noeuds faisables obtenue, le Scheduler évalue chacun d'eux à l'aide de fonctions de priorité. Chaque fonction attribue un score (généralement entre 0 et 10, configurable via des poids) au noeud en fonction d'un critère spécifique. Les scores de toutes les fonctions de priorité sont ensuite sommés pour chaque noeud.

Voici quelques exemples courants de fonctions de priorité :

  • LeastRequestedPriority : Favorise les noeuds qui ont le moins de ressources (CPU et mémoire) déjà demandées par d'autres Pods. Le but est de répartir la charge le plus uniformément possible.
  • BalancedResourceAllocation : Favorise les noeuds où l'utilisation des ressources (CPU et mémoire) serait la plus équilibrée après le placement du Pod. Cela évite de saturer une seule ressource sur un noeud.
  • ImageLocalityPriority : Favorise les noeuds qui ont déjà téléchargé et mis en cache les images conteneurs nécessaires au Pod. Cela accélère le démarrage du Pod.
  • NodeAffinityPriority : Attribue des scores plus élevés aux noeuds qui correspondent aux préférences d'affinité de noeud (preferredDuringSchedulingIgnoredDuringExecution) du Pod.
  • PodAffinityPriority : Attribue des scores plus élevés aux noeuds qui satisfont les préférences d'affinité/anti-affinité de Pods (preferredDuringSchedulingIgnoredDuringExecution).
  • TaintTolerationPriority : Peut être utilisée pour favoriser (ou défavoriser) les noeuds en fonction des taints qu'ils possèdent et des tolérances du Pod.
  • SelectorSpreadPriority : Tente de répartir les Pods appartenant à un même Service, ReplicaSet ou StatefulSet sur différents noeuds (ou différentes zones topologiques) pour améliorer la disponibilité.

L'administrateur du cluster peut configurer quels prédicats et quelles fonctions de priorité (et avec quels poids) le Scheduler doit utiliser, permettant ainsi d'adapter le comportement de l'ordonnancement aux besoins spécifiques du cluster.

Phase 3 : Binding - Lier le Pod au noeud choisi

Une fois que le noeud avec le score le plus élevé a été identifié, le Scheduler effectue l'opération finale : le binding. Il notifie l'API Server que le Pod doit être assigné à ce noeud spécifique.

Cette notification consiste essentiellement à mettre à jour l'objet Pod dans etcd en définissant son champ spec.nodeName avec le nom du noeud choisi. C'est cette mise à jour qui est ensuite détectée par le Kubelet s'exécutant sur le noeud désigné. Le Kubelet prend alors le relais : il télécharge les images nécessaires, configure les volumes, crée les conteneurs et démarre le Pod sur ce noeud.

Il est important de noter que le Scheduler lui-même ne lance pas les Pods ; il se contente de prendre la décision de placement et de la communiquer via l'API Server. Le travail effectif d'exécution est délégué au Kubelet du noeud sélectionné.

En résumé, le Scheduler Kubernetes est un composant sophistiqué qui applique un processus rigoureux de filtrage et de scoring pour prendre des décisions de placement intelligentes, assurant que les contraintes des Pods sont respectées tout en cherchant à optimiser l'utilisation globale des ressources du cluster.