L'autoscaler de Kapsule a mis 175 secondes à livrer les nœuds manquants, puis il s'est arrêté net à son maximum en laissant deux pods bloqués pour toujours. Cette leçon crée un pool autoscalé, y soumet une charge calibrée pour ne pas tenir, et mesure chaque étape. Vous lirez la séquence complète des messages du planificateur, qui raconte la montée bien mieux qu'une capture finale, et vous reconnaîtrez le blocage à max-size : il ne produit aucune erreur, aucune alerte, et ne ressemble donc pas à une panne. C'est ce qui le rend dangereux.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Créer un pool autoscalé et relire sa configuration réelle à l'API.
- Mesurer le délai entre un pod
Pendinget un nœud utilisable. - Lire ce que le planificateur dit pendant la montée en charge.
- Reconnaître le blocage à
max-size, qui n'a l'air de rien.
Prérequis
Section intitulée « Prérequis »- Un cluster Kapsule existant : voir créer un cluster Kapsule.
- La CLI
scw2.62.0 ou plus récente, sur un profil isolé, etkubectlconfiguré. jq, pour lire les sorties JSON.
Pourquoi séparer les charges en plusieurs pools ?
Section intitulée « Pourquoi séparer les charges en plusieurs pools ? »Un pool est une flotte homogène, et c'est l'unité de décision de Kapsule. Tout ce qui distingue des machines, le type, la zone, le volume système, l'autoscaling, se règle au niveau du pool et jamais du nœud.
| Besoin | Pool dédié ? | Pourquoi |
|---|---|---|
| Charge stable et prévisible | un pool fixe, sans autoscaling | on paie une capacité connue, sans délai de montée |
| Pics ponctuels, traitements par lots | un pool autoscalé | on ne paie les nœuds que pendant les pics |
| Charges qui ne doivent pas cohabiter | un pool par charge, avec des taints | un taint repousse tout pod qui ne le tolère pas |
| Machines plus grosses pour certains travaux | un pool par type | le type de nœud est une propriété du pool |
Le schéma à deux pools est celui qui rend service le plus souvent : un socle fixe et petit, qui accueille ce qui doit toujours tourner, et un pool autoscalé pour le reste. Le socle garantit que le cluster ne descend jamais à zéro nœud, ce qui éviterait à vos composants système de se retrouver sans place ; le pool élastique absorbe les pics sans les payer en permanence.
Comment créer un pool autoscalé ?
Section intitulée « Comment créer un pool autoscalé ? »Quatre arguments suffisent, et min-size comme max-size n'ont d'effet que si autoscaling=true. L'aide de la commande le dit explicitement, et c'est une source d'erreur classique : des bornes posées sans activer l'autoscaling sont simplement ignorées.
-
Retrouver l'identifiant du cluster, puisque toutes les commandes de pool le réclament.
Fenêtre de terminal CLUSTER_ID=$(scw k8s cluster list region=fr-par -o json \| jq -r '.[] | select(.name == "demo-kapsule") | .id')echo "cluster : ${CLUSTER_ID}"La sortie doit afficher un identifiant UUID. Remplacez
demo-kapsulepar le nom de votre cluster. -
Créer le pool, avec ses bornes et l'autoréparation.
Fenêtre de terminal POOL_ID=$(scw k8s pool create \cluster-id="${CLUSTER_ID}" \region=fr-par \name=eleveur \node-type=DEV1-M \zone=fr-par-1 \size=1 \autoscaling=true \min-size=1 \max-size=3 \autohealing=true \-o json | jq -r '.id')echo "pool : ${POOL_ID}"La sortie doit afficher un identifiant UUID.
-
Relire la configuration réelle, plutôt que de supposer qu'elle a été prise en compte.
Fenêtre de terminal scw k8s pool get "${POOL_ID}" region=fr-par -o json \| jq -r '"pool \(.name) : autoscaling=\(.autoscaling) min=\(.min_size) max=\(.max_size) autohealing=\(.autohealing)"'La sortie doit afficher
autoscaling=true min=1 max=3 autohealing=true. Siautoscalingvautfalse, vos bornes ne servent à rien, et rien ne vous le signalera.C'est le cas de tout pool créé sans le demander. Relevé le 2026-09-12 sur un pool issu de
cluster create pools.0.*:autoscaling=false autohealing=false. Les deux automatismes sont désactivés par défaut. -
Attendre le premier nœud du pool.
Fenêtre de terminal until [ "$(kubectl get nodes --no-headers 2>/dev/null | awk '$2=="Ready"' | wc -l)" -ge 2 ]; doprintf '.'; sleep 10donekubectl get nodesLa sortie doit afficher au moins deux nœuds
Ready. Mesuré le 2026-09-12 : 111 secondes.
Combien de temps l'autoscaler met-il à fournir un nœud ?
Section intitulée « Combien de temps l'autoscaler met-il à fournir un nœud ? »175 secondes entre la soumission de la charge et le retour à un cluster capable de l'accueillir, mesuré le 2026-09-12. Provoquez la situation vous-même avec une charge calibrée pour ne pas tenir.
kubectl create deployment gourmand --image=nginx:1.29.1@sha256:8adbdcb969e2676478ee2c7ad333956f0c8e0e4c5a7463f4611d7a2e7a7ff5dc --replicas=6kubectl set resources deployment gourmand --requests=cpu=2Chaque DEV1-M offre 3 vCPU, dont une partie est déjà consommée par les composants système. Six pods qui réclament 2 vCPU chacun ne peuvent donc pas tenir sur les deux nœuds en place : le planificateur bloque, l'autoscaler réagit.
Observez les deux faces de l'événement en même temps :
kubectl get pods -l app=gourmandkubectl get events --field-selector reason=FailedScheduling \ -o custom-columns=MESSAGE:.message --no-headers | tail -3La première sortie doit afficher des pods Pending, la seconde le motif exact du refus.
Que dit le planificateur pendant la montée en charge ?
Section intitulée « Que dit le planificateur pendant la montée en charge ? »Le message change à chaque nœud livré, et cette séquence est plus instructive que l'état final. Capturée telle quelle le 2026-09-12 :
0/2 nodes are available: 2 Insufficient cpu.0/3 nodes are available: 3 Insufficient cpu.0/4 nodes are available: 1 node(s) had untolerated taint(s), 3 Insufficient cpu.Trois choses s'y lisent. D'abord, le dénominateur augmente : 2 nœuds, puis 3, puis 4. L'autoscaler travaille, et le planificateur le raconte sans qu'on ait à consulter le moindre journal Scaleway. Ensuite, Insufficient cpu reste la cause dominante : ce sont bien les requêtes de CPU, et non l'usage réel, qui décident du placement. Enfin, un nœud sur quatre apparaît avec un taint non toléré.
Que se passe-t-il quand l'autoscaler atteint son maximum ?
Section intitulée « Que se passe-t-il quand l'autoscaler atteint son maximum ? »Rien. Et c'est exactement le problème. Le pool est monté à 3 nœuds, son max-size, puis s'est arrêté. Deux pods sont restés Pending indéfiniment.
kubectl get pods -l app=gourmand --no-headers | awk '{print $3}' | sort | uniq -cLa sortie affichait, mesure faite :
1 ContainerCreating 2 Pending 5 RunningNi le pool ni l'autoscaler ne signalent de panne. Kubernetes, lui, continue d'émettre des événements FailedScheduling sur les pods qui ne trouvent pas de place : l'information existe, elle est simplement au mauvais endroit pour qui surveille l'autoscaler. Le déploiement ne se déclare jamais prêt, kubectl rollout status attend jusqu'à son délai, et le pool affiche size=3 max=3 comme si tout allait bien.
Un tableau de bord qui surveille les pods en échec ne verra rien non plus : un pod Pending n'est pas en échec, il attend.
C'est le piège le plus coûteux de ce volet, parce qu'il ne ressemble pas à une panne et qu'il se déclenche au pire moment. Un max-size posé par prudence budgétaire, six mois plus tôt, sur un pool qui n'a jamais eu besoin de le franchir, devient soudain le plafond exact où votre charge s'arrête de croître, un jour de pic. Le service ne tombe pas : il cesse de grandir, ce qui produit des latences et des files d'attente plutôt qu'une alerte franche. Le seul signal fiable est la conjonction de deux faits que rien ne rapproche automatiquement : des pods Pending d'un côté, un pool à size == max_size de l'autre. Surveillez cette conjonction explicitement, car aucune des deux métriques prise isolément ne justifie une alerte.
scw k8s pool get "${POOL_ID}" region=fr-par -o json \ | jq -r 'if .size == .max_size then "SATURÉ : \(.size)/\(.max_size) nœuds" else "marge : \(.size)/\(.max_size)" end'La sortie doit afficher SATURÉ : 3/3 nœuds après cette manipulation.
Les réglages de pool qu'il faut connaître avant d'en avoir besoin
Section intitulée « Les réglages de pool qu'il faut connaître avant d'en avoir besoin »Trois arguments de scw k8s pool create changent le comportement du cluster, et aucun n'est évident.
| Argument | Ce qu'il fait | Ce qu'il faut savoir |
|---|---|---|
max-termination-grace-period | délai avant que l'API force le drain et la suppression d'un nœud | 15 minutes par défaut, 1 heure au maximum, et il écrase votre PodDisruptionBudget et vos terminationGracePeriodSeconds |
placement-group-id | répartit les nœuds sur des hyperviseurs distincts | limité à 20 instances par groupe |
kubelet-args | passe des arguments au kubelet du pool | marqué expérimental dans l'aide de la commande |
Le premier mérite qu'on s'y arrête. Un PodDisruptionBudget protège votre application contre les évictions volontaires, et l'on en déduit souvent qu'il est inviolable. Ce n'est pas le cas ici : passé le délai de grâce du pool, l'API force la suppression du nœud, budget ou pas. Votre protection a donc une date d'expiration, et elle vaut quinze minutes par défaut.
Comment faire redescendre le pool ?
Section intitulée « Comment faire redescendre le pool ? »Supprimez la charge, l'autoscaler retire les nœuds devenus inutiles. La descente n'est pas immédiate, l'autoscaler attendant qu'un nœud reste inoccupé un certain temps avant de le rendre.
kubectl delete deployment gourmandscw k8s pool get "${POOL_ID}" region=fr-par -o json | jq -r '"\(.size) nœuds, min \(.min_size)"'La sortie affichera encore 3 nœuds juste après la suppression : c'est normal. Ne comptez pas sur cette descente pour arrêter la facturation à la fin d'une session de travail. Si vous en avez fini, détruisez plutôt que d'attendre.
Pour forcer un retour immédiat à la taille basse, désactivez temporairement l'autoscaling :
scw k8s pool update "${POOL_ID}" region=fr-par autoscaling=false size=1 -o json \ | jq -r '"pool ramené à \(.size) nœud(s)"'La sortie doit afficher pool ramené à 1 nœud(s).
Nettoyer
Section intitulée « Nettoyer »Le pool se supprime indépendamment du cluster, et c'est utile quand seul le pool est de trop.
kubectl delete deployment gourmand --ignore-not-found=true
scw k8s pool delete "${POOL_ID}" region=fr-par -o json | jq -r '.status'
until ! scw k8s pool get "${POOL_ID}" region=fr-par > /dev/null 2>&1; do printf '.'; sleep 10doneecho " pool disparu"La première sortie doit afficher deleting, la dernière pool disparu. Attendez la disparition effective : tant que le pool est listé, ses nœuds sont facturés.
Vérifiez enfin ce qui reste :
scw k8s pool list cluster-id="${CLUSTER_ID}" region=fr-par -o json \ | jq -r '.[] | "\(.name) : \(.size) nœud(s)"'La sortie ne doit plus mentionner que votre pool de base. Pour détruire le cluster entier, reportez-vous à la section de nettoyage de créer un cluster Kapsule.
Limites, quotas et plafonds
Section intitulée « Limites, quotas et plafonds »| Plafond | Valeur | Source |
|---|---|---|
| Nœuds par cluster, control plane mutualisé | 150 | refus de l'API, 2026-09-12 |
| Instances par groupe de placement | 20 | aide de scw k8s pool create |
| Délai de grâce avant drain forcé | 15 min par défaut, 1 h au maximum | aide de scw k8s pool create |
| vCPU utiles d'un DEV1-M | 3, moins les composants système | scw instance server-type list, 2026-09-12 |
| Prix d'un nœud DEV1-M | 0,020196 €/h | scw instance server-type list, 2026-09-12 |
Dépannage
Section intitulée « Dépannage »Les trois premiers symptômes portent le message exact renvoyé par kubectl.
| Symptôme | Cause | Solution |
|---|---|---|
0/N nodes are available: N Insufficient cpu et rien ne bouge | le pool est à max-size, l'autoscaler ne peut plus rien | relever max-size, ou réduire les requests des pods |
N node(s) had untolerated taint(s) sur un nœud récent | le nœud est en cours d'initialisation | attendre ; le taint disparaît de lui-même |
Pods Pending alors que les nœuds semblent peu chargés | le placement se décide sur les requests, pas sur l'usage réel | ajuster resources.requests au besoin réel |
Les bornes min-size et max-size sont ignorées | autoscaling est resté à false | relire la configuration avec scw k8s pool get |
Antipatterns à éviter
Section intitulée « Antipatterns à éviter »Ces quatre erreurs supposent que l'élasticité est automatique et illimitée. Elle est bornée, et vous avez posé la borne.
| Antipattern | Conséquence | Discipline |
|---|---|---|
Poser max-size « au cas où » et l'oublier | la charge s'arrête de croître un jour de pic, sans alerte | alerter sur size == max_size, pas seulement sur les pods en échec |
| Compter sur la descente automatique pour arrêter les frais | les nœuds restent plusieurs minutes après la fin de la charge | détruire en fin de session, ne pas attendre |
Croire un PodDisruptionBudget inviolable | l'API force le drain après le délai de grâce du pool | connaître max-termination-grace-period, 15 minutes par défaut |
Dimensionner les requests au pifomètre | des pods Pending sur un cluster qui paraît vide | mesurer l'usage réel, puis ajuster les requests |
L'autoscaling sous l'angle Well-Architected
Section intitulée « L'autoscaling sous l'angle Well-Architected »Fiabilité
Section intitulée « Fiabilité »Que se passe-t-il quand la demande dépasse max-size ? Le cluster ne tombe pas, il cesse de croître, ce qui produit des latences plutôt qu'une alerte.
Discipline : surveiller la conjonction « pods Pending » et « pool saturé », et non chacun des deux signaux isolément, car aucun ne justifie une alerte à lui seul.
Excellence opérationnelle
Section intitulée « Excellence opérationnelle »Vos mesures de délai décrivent-elles votre plateforme ou le moment où vous les avez prises ? Deux sessions du même jour ont donné un control plane prêt en 106 puis 81 secondes, et un premier nœud en 109 puis 152 secondes.
Discipline : annoncer des ordres de grandeur, refaire la mesure avant d'en tirer un seuil d'alerte, et dater toute valeur publiée.
Optimisation des coûts
Section intitulée « Optimisation des coûts »Qui paie les nœuds ajoutés pendant un pic ? Vous, à la seconde près, au prix des Instances. Un pool autoscalé bien borné est moins cher qu'une flotte fixe dimensionnée pour le pic.
Discipline : garder un socle fixe minimal, confier l'élasticité à un pool séparé, et ne jamais laisser un max-size généreux sans alerte budgétaire en face.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À retenir
Section intitulée « À retenir »- Aucun automatisme n'est actif par défaut : un pool créé par
cluster createsort enautoscaling=false autohealing=false, etmin-sizecommemax-sizen'ont d'effet qu'une fois l'autoscaling activé. - L'autoscaler a mis 175 secondes à livrer les nœuds manquants, mesuré le 2026-09-12.
- Le message du planificateur raconte la montée : le dénominateur de
0/N nodes are availableaugmente à chaque nœud livré. - Un nœud fraîchement créé porte un taint transitoire qui disparaît seul.
- À
max-size, ni le pool ni l'autoscaler ne signalent de panne : seuls des événementsFailedSchedulingsubsistent, sur des podsPendingqui ne sont pas comptés comme en échec. - Le seul signal fiable est la conjonction de pods
Pendinget d'un pool àsize == max_size. max-termination-grace-periodécrase votrePodDisruptionBudgetaprès 15 minutes par défaut.- Un groupe de placement est limité à 20 instances.
- Le placement se décide sur les
requests, jamais sur l'usage réel. - La descente du pool n'est pas immédiate : détruisez en fin de session plutôt que d'attendre.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Ingress ou Service LoadBalancer : Expose les applications que ces pools font tourner, au meilleur coût.
- Volumes persistants : Montre pourquoi un pod avec état ne profite pas de l'élasticité des pools.
- Monter un cluster de version : Mesure ce que devient un pool quand ses nœuds sont tous remplacés.
Ressources externes
Section intitulée « Ressources externes »- Gérer les pools de nœuds : la procédure officielle de création, de redimensionnement et de suppression d'un pool.
- Autoréparation de Kapsule : ce que
autohealingdétecte réellement, et ce qu'il ne détecte pas. - FAQ Kubernetes Scaleway : la facturation en présence d'autoscaling, et le volume système recommandé par nœud.
- Autoscaler Kubernetes, documentation amont : les critères exacts de décision de montée et de descente, communs à tous les fournisseurs.