Le 8 septembre 2026, l'équipe SIG Scheduling a publié le billet de version de la fonctionnalité qui manquait le plus aux plateformes d'entraînement et d'inférence distribuée : avec Kubernetes v1.37, le gang scheduling natif passe en bêta. Les API Workload et PodGroup, la préemption consciente des workloads et le partage de ResourceClaims DRA au niveau d'un groupe de pods quittent l'alpha. Une nouvelle API CompositePodGroup ajoute la hiérarchie, et le contrôleur Job standard apprend enfin à demander un placement « tout ou rien ».
Pour une équipe qui fait tourner des jobs PyTorch multi-nœuds, du serving désagrégé ou des pipelines batch sur GPU, ce n'est pas une fonctionnalité de plus. C'est la fin d'une dépendance à des ordonnanceurs tiers pour un besoin que Kubernetes ignorait depuis dix ans : ne jamais démarrer la moitié d'un job.
Le contexte
Kubernetes ordonnance des pods un par un. Pour une application web, c'est parfait : chaque réplica est indépendant. Pour un entraînement distribué, c'est un piège. Un job de 8 workers qui n'obtient que 5 GPU démarre 5 pods, qui attendent les 3 autres en consommant des ressources coûteuses, pendant qu'un autre job dans la même situation bloque les GPU dont le premier a besoin. C'est l'interblocage classique du partage de cluster, et la raison d'être de projets comme Volcano ou Kueue, qui ont dû réimplémenter par-dessus le scheduler un gang scheduling (placer tous les pods d'un groupe ou aucun) et une préemption de groupe.
Depuis v1.36, le projet Kubernetes a lancé le chantier Workload-Aware Scheduling (WAS) pour faire entrer ces notions dans le cœur : un objet Workload décrit le gabarit du job, un PodGroup en porte l'état d'exécution, et le scheduler les traite comme une unité. La v1.37, détaillée dans le billet officiel, franchit le cap de la bêta et ajoute les briques qui manquaient pour les workloads composés.
Ce qui passe en bêta : Workload, PodGroup et préemption
Les API Workload et PodGroup sont promues en scheduling.k8s.io/v1beta1, « à un pas de la GA » selon les auteurs. Le gang scheduling qu'elles portent est activé par la feature gate GenericWorkload, qui absorbe désormais aussi la préemption consciente des workloads (l'ancienne gate WorkloadAwarePreemption disparaît). Trois changements comptent pour qui a déjà testé l'alpha.
Le PodGroup devient une unité de file d'attente
Jusqu'ici, même membres d'un groupe, les pods étaient mis en file individuellement. En v1.37, seul l'objet PodGroup de tête est mis en file : tous ses pods partagent le même comportement de queue. C'est un détail d'implémentation, mais c'est celui qui permettra des stratégies de file par groupe (priorités, équité) dans les prochaines versions.
minCount devient mutable
Le champ minCount, qui fixe le nombre minimal de pods à placer ensemble, était immuable. Il ne l'est plus : un contrôleur peut réduire ou augmenter la taille minimale d'un gang à chaud, sans toucher aux pods déjà placés. Pour un entraînement élastique qui tolère de perdre deux workers, ou un serving qui absorbe un pic, c'est la différence entre « dégrader proprement » et « tout relancer ».
Une préemption qui respecte enfin les groupes
En v1.36, la préemption par défaut d'un pod isolé ignorait les PodGroup : elle pouvait éjecter un seul pod d'un groupe déclaré indissociable. La v1.37 corrige ce trou. Le champ disruptionMode est renommé pour être partagé entre groupes simples et composés : all (on évince tout le groupe ou rien) et single (chaque pod peut être évincé séparément). Un champ preemptionPolicy apparaît au niveau du PodGroup derrière la gate PodGroupPreemptionPolicy, et l'algorithme de préemption ne relance plus la simulation de placement pour chaque victime candidate : une seule passe, puis des vérifications de réintégration, ce qui réduit le coût sur les gros clusters.
CompositePodGroup : la hiérarchie pour JobSet et LeaderWorkerSet
Un groupe plat ne suffit pas pour les workloads réels. Un job d'entraînement a un pilote et des workers ; un serving désagrégé façon LeaderWorkerSet a des leaders et des groupes de workers ; un JobSet enchaîne plusieurs jobs. La nouvelle API CompositePodGroup (scheduling.k8s.io/v1alpha3, alpha, gate CompositePodGroup) organise ces groupes en arbre : chaque nœud composé porte une politique de gang exprimée en minGroupCount (nombre minimal de sous-groupes à placer), chaque feuille PodGroup garde son minCount.
Le scheduler évalue l'arbre entier comme une seule unité, de la racine aux feuilles, et ne lie les pods que si toute la hiérarchie est satisfaite. L'exemple du billet est parlant : un Workload avec un template composé workload-root (minGroupCount: 2) et deux templates enfants, workers (minCount: 4) et driver (minCount: 1). Soit les 5 pods démarrent, soit aucun.
La préemption suit la même logique : un CompositePodGroup peut préempter pour se faire de la place, et peut être victime, avec un disruptionMode à all pour évincer toute la hiérarchie ensemble ou single pour laisser tomber un sous-groupe isolément.
Topologie multi-niveaux
C'est l'autre apport de la hiérarchie : on peut contraindre la racine à une zone de disponibilité (topology.kubernetes.io/zone) et chaque sous-groupe à un rack (topology.example.com/rack) à l'intérieur de cette zone. La résolution est descendante : les domaines candidats d'un enfant sont confinés au domaine choisi pour le parent. Pour un entraînement où la bande passante inter-rack est le goulot, c'est exactement la contrainte que l'on écrivait jusqu'ici à la main avec des affinités fragiles. La topologie multi-niveaux est alpha (gate TopologyAwareWorkloadScheduling), et la v1.37 accélère au passage l'évaluation du placement pour la topologie à un seul niveau introduite en v1.36.
Le Job standard apprend le gang scheduling
C'est la nouveauté la plus utilisable dès maintenant. Le Job de batch/v1 reçoit un champ explicite .spec.scheduling, derrière la gate alpha WorkloadWithJob, composé de quatre briques : schedulingPolicy (basic ou gang), schedulingConstraints (la topologie de co-localisation), disruptionMode (single ou all) et resourceClaims (les claims DRA partagées par tous les pods). Un job d'entraînement à 8 workers se déclare ainsi :
apiVersion: batch/v1
kind: Job
metadata:
name: distributed-training-job
spec:
parallelism: 8
completions: 8
scheduling:
schedulingPolicy:
gang: {} # minCount omis : vaut parallelism (8)
schedulingConstraints:
topology:
- key: topology.kubernetes.io/zone
disruptionMode:
all: {}
template:
spec:
containers:
...
Le contrôleur compile cette déclaration en un Workload et un PodGroup possédés par le job, et pose .spec.schedulingGroup.podGroupName sur chaque pod. Omettre .spec.scheduling conserve le comportement historique. Le champ est immuable une fois créé, à une exception près : schedulingPolicy.gang.minCount, pour redimensionner un gang en cours d'exécution.
Ce contrôleur s'appuie sur des API d'intégration génériques et sur la bibliothèque Go workloadbuilder (dans kubernetes/component-helpers, sans feature gate). Un contrôleur tiers décrit son workload comme un arbre de WorkloadItem, Validate() renvoie les erreurs au chemin exact de son propre schéma, BuildWorkload() produit le Workload, NewPodGroup() et NewCompositePodGroup() instancient les objets d'exécution. La validation est fermée par défaut : un contrôleur liste explicitement les politiques et modes de disruption qu'il accepte. C'est la voie tracée pour Kubeflow Trainer, JobSet, LWS et les opérateurs maison.
DRA : une ResourceClaim pour tout le groupe
Le partage de ResourceClaims au niveau d'un PodGroup, introduit en v1.36, passe en bêta (gate DRAWorkloadResourceClaims). Un PodGroup déclare ses claims via un ResourceClaimTemplate, et chaque pod membre les référence : la claim est répliquée et réservée pour le groupe entier au lieu d'être créée pod par pod. La v1.37 corrige un comportement piégeux : gate désactivée, un pod dont la claim correspondait à celle de son groupe se voyait auparavant créer une claim individuelle, ce qui pouvait inonder le cluster de ResourceClaims et épuiser les ressources DRA. Désormais, aucune claim n'est créée dans ce cas.
Pour les GPU, les accélérateurs réseau et les partitions MIG exposés par DRA, c'est ce qui rend le gang scheduling réellement atomique : le groupe obtient ses ressources ensemble, ou pas du tout. Les autres évolutions DRA de cette version sont détaillées dans le billet dédié aux mises à jour DRA de v1.37.
Ce que ça change pour les équipes IA
Le gang scheduling natif change l'architecture des plateformes ML. Concrètement :
- Le cluster partagé redevient possible sans ordonnanceur parallèle. Volcano ou Kueue restent utiles pour les files, les quotas et le fair-share, mais la brique « tout ou rien » et la préemption de groupe entrent dans kube-scheduler. La feuille de route v1.38 annonce d'ailleurs une intégration où Kueue s'appuierait sur WAS comme moteur sous-jacent. Une plateforme qui démarre aujourd'hui a intérêt à viser les API
scheduling.k8s.io/v1beta1plutôt qu'une CRD tierce. - Le job d'entraînement se décrit en quatre lignes.
gang: {}+ une contrainte de zone +disruptionMode: allremplacent des affinités, despodAntiAffinityet des scripts de vérification. La contrainte de rack viaCompositePodGroupest alpha : à tester, pas à mettre en production. - L'élasticité devient un paramètre, pas une réarchitecture.
minCountmutable permet de concevoir des entraînements qui dégradent gracieusement, à condition que le framework (PyTorch elastic, Ray) sache réagir. - Attention aux versions.
v1alpha2est supprimé, remplacé parv1alpha3avec des ruptures autour dedisruptionMode(PodGroupdevientall,Poddevientsingle). Un cluster d'alpha-testeurs doit migrer ses manifestes avant l'upgrade. - Tout est désactivé par défaut.
GenericWorkload(bêta) sur apiserver, controller-manager et scheduler ;DRAWorkloadResourceClaims(bêta) sur les mêmes plus le kubelet ;TopologyAwareWorkloadScheduling,CompositePodGroup,WorkloadWithJobetPodGroupPreemptionPolicy(alpha). Sur un cluster managé, cela veut dire attendre que le fournisseur expose ces gates, ou piloter un cluster de test soi-même. - La préemption de groupe est une arme à double tranchant. Un
disruptionMode: allprotège un entraînement de 200 GPU d'une éviction partielle, mais rend l'éviction totale d'un seul coup. Les classes de priorité et les budgets de disruption doivent être repensés au niveau du groupe.
La bonne nouvelle pour les équipes DevOps est que la sémantique a été pensée pour être consommée par des contrôleurs, pas seulement par des humains : workloadbuilder et les briques WorkloadPodGroup* sont la voie pour que vos opérateurs internes parlent le même langage de gang scheduling Kubernetes que le Job natif.
En bref
- Kubernetes v1.37 fait passer en bêta les API
WorkloadetPodGroup, le gang scheduling, la préemption consciente des workloads et le partage DRA par groupe. CompositePodGroup(alpha) ajoute des hiérarchies de groupes avecminGroupCountet une topologie multi-niveaux zone → rack.- Le
Jobstandard reçoit.spec.scheduling(gang, topologie, disruption, claims), derrière la gate alphaWorkloadWithJob. minCountdevient mutable, la préemption respecte les groupes,v1alpha2disparaît au profit dev1alpha3.- v1.38 vise la GA des API cœur, la bêta de la topologie et de
CompositePodGroup, et une intégration Kueue.
Vous industrialisez vos agents IA ? SeedVision propose des audits IA en 3-5 jours et des forfaits de mise en production de 15 à 30 jours. Voir les packages ou réserver un appel de 30 min.
Photo de couverture : Photo by Domaintechnik on Unsplash.