Pourquoi orchestrer, architecture en nœuds et plan de contrôle, les cinq objets à maîtriser — pod, deployment, service, ingress, configmap — mise à l'échelle, sondes et déploiement progressif.
Plan de la leçon
- 01Ce que Compose ne sait pas faire
- 02L'architecture, en deux minutes
- 03La seule idée à retenir : la réconciliation
- 04Cinq objets, et pas un de plus
- 05Les sondes : la distinction qui coûte cher
- 06Mise à l'échelle et déploiement progressif
- 07Ce que ce cours ne traite pas
- 08À vous
- 09En travaux pratiques
- 10Ce que la suite en fait
- 11À retenir
Une mise en garde avant de commencer, et elle fait partie du cours.
Kubernetes est le point qui coince de ce semestre. Sa complexité conceptuelle dépasse largement ce qu'un module de huit heures peut absorber, et c'est vrai aussi en entreprise : des équipes entières y consacrent leur métier. Ce chapitre est donc explicitement une découverte — déployer, exposer, mettre à l'échelle, revenir en arrière. Cinq objets maîtrisés valent mieux que vingt survolés.
Une seconde mise en garde, plus rare dans les cours : vous n'en avez peut-être pas besoin. Un service qui tient sur deux machines et se déploie en bleu-vert avec Compose n'a rien à gagner à l'orchestration, et beaucoup à perdre en complexité. Kubernetes se justifie quand on gère beaucoup de services sur beaucoup de machines. En dessous, il ajoute un système à exploiter — et ce système tombe en panne, lui aussi.
Ce que Compose ne sait pas faire
Le chapitre 4 fait tenir plusieurs conteneurs ensemble sur une machine. Quatre besoins le dépassent.
Plusieurs machines. Répartir des conteneurs sur un parc, en tenant compte de la place disponible.
L'auto-réparation. Une machine tombe à trois heures du matin : quelque chose doit redémarrer ses conteneurs ailleurs, sans réveiller personne.
La mise à l'échelle. Passer de trois à vingt exemplaires pour absorber une pointe, puis redescendre.
Les déploiements progressifs sans interruption, avec les stratégies du chapitre 6, intégrés plutôt que scriptés.
Un orchestrateur fait ces quatre choses. Kubernetes est celui qui s'est imposé.
L'architecture, en deux minutes
PLAN DE CONTRÔLE NŒUDS DE TRAVAIL ┌──────────────────────┐ ┌────────────┐ ┌────────────┐ │ serveur d'API │◄───────────┤ kubelet │ │ kubelet │ │ ordonnanceur │ │ ┌────┬───┐ │ │ ┌────┐ │ │ gestionnaire de │ │ │pod │pod│ │ │ │pod │ │ │ contrôleurs │ │ └────┴───┘ │ │ └────┘ │ │ etcd (l'état voulu) │ └────────────┘ └────────────┘ └──────────────────────┘Le serveur d'API est le seul point d'entrée : tout passe par lui, y compris les composants internes. L'ordonnanceur décide sur quel nœud placer un nouveau conteneur. Le gestionnaire de contrôleurs fait tourner les boucles de la section suivante. etcd stocke l'état déclaré — c'est la base de données du cluster, et sa sauvegarde est la seule chose vraiment critique.
Sur chaque nœud de travail, un agent, le kubelet, reçoit ses instructions et fait tourner les conteneurs. C'est tout ce qu'il faut retenir de l'architecture à ce niveau.
La seule idée à retenir : la réconciliation
Si vous ne deviez garder qu'une chose de ce chapitre, ce serait celle-ci.
On ne donne pas d'ordres à Kubernetes. On lui déclare un état, et des contrôleurs passent leur temps à réduire l'écart entre cet état et la réalité.
On n'a écrit aucune commande de démarrage. On a DÉCLARÉ qu'il devait exister trois exemplaires de l'application en version 1.4 — et l'on a laissé le contrôleur trouver comment y parvenir.
Ce modèle explique tout le reste, et notamment des comportements qui paraissent magiques.
L'auto-réparation n'est pas une fonctionnalité ajoutée : c'est la conséquence directe du modèle. Un pod disparaît, l'écart réapparaît, la boucle le comble.
La mise à l'échelle n'est pas une opération : c'est un changement de la valeur déclarée.
Le retour arrière n'est pas un mécanisme spécial : c'est redéclarer l'état précédent.
Et une conséquence moins agréable : modifier quelque chose à la main ne tient pas. Supprimer un pod le fait revenir ; corriger un conteneur en direct disparaît au prochain remplacement. C'est la dérive du chapitre 7, activement combattue — ce qui est une excellente propriété, et une source de perplexité pour qui vient du monde des serveurs.
Cinq objets, et pas un de plus
| Objet | Répond à |
|---|---|
| Pod | l'unité déployée : un ou plusieurs conteneurs qui partagent réseau et stockage |
| Deployment | combien d'exemplaires, quelle version, comment les remplacer |
| Service | une adresse stable devant des pods qui vont et viennent |
| Ingress | comment le trafic extérieur entre dans le cluster |
| ConfigMap / Secret | la configuration et les secrets, séparés de l'image |
Le pod est l'unité de base — et non le conteneur. On ne le crée presque jamais directement : il est jetable, remplacé à chaque déploiement, et son adresse change à chaque fois.
Le deployment est ce qu'on écrit réellement. Il déclare un nombre d'exemplaires et un gabarit de pod, et c'est son contrôleur qui tient la boucle.
apiVersion: apps/v1kind: Deploymentmetadata: name: applispec: replicas: 3 selector: matchLabels: { app: appli } template: metadata: labels: { app: appli } spec: containers: - name: appli image: registre.exemple.net/appli:1.4.2 ports: [{ containerPort: 3000 }] readinessProbe: httpGet: { path: /pret, port: 3000 } livenessProbe: httpGet: { path: /vivant, port: 3000 }Le service résout le problème que les pods jetables créent : leurs adresses changent. Il fournit un nom stable et répartit le trafic sur les pods portant une étiquette donnée — c'est la découverte de service du chapitre 3, à l'échelle du cluster. Et c'est ici que les étiquettes prennent leur sens : rien n'est relié par un identifiant, tout est relié par « tous les objets qui portent telle étiquette ». Une étiquette mal recopiée donne un service qui ne pointe sur rien, sans aucune erreur.
L'ingress fait entrer le trafic extérieur, avec le routage par nom de domaine et la terminaison TLS.
Les ConfigMap et Secret portent ce qui change d'un environnement à l'autre, conformément à la règle du chapitre 6. Un avertissement s'impose : un Secret Kubernetes n'est pas chiffré par défaut, seulement encodé en base64 — c'est-à-dire lisible par quiconque a accès à l'objet ou à etcd. Le chiffrement au repos et le contrôle d'accès s'activent, et c'est le sujet du chapitre 11.
Les sondes : la distinction qui coûte cher
Trois sondes, trois questions différentes, et les confondre produit des pannes spectaculaires.
| Sonde | Question | Si elle échoue |
|---|---|---|
| readiness | ce pod peut-il recevoir du trafic ? | il est retiré du service, sans redémarrage |
| liveness | ce pod est-il encore vivant ? | il est redémarré |
| startup | a-t-il fini de démarrer ? | les deux autres sont suspendues jusque-là |
La faute classique consiste à pointer les deux premières sur la même adresse, laquelle vérifie souvent la base de données.
Déroulons ce qui se passe alors quand la base ralentit. La sonde de disponibilité échoue : les pods sortent du service — comportement correct, ils ne peuvent effectivement pas servir. Mais la sonde de vivacité échoue aussi : Kubernetes redémarre les pods. Ils redémarrent tous en même temps, se reconnectent tous à la base au même instant, et l'achèvent. Une lenteur passagère est devenue une panne totale, causée par l'orchestrateur.
La règle qui l'évite : la sonde de vivacité ne teste que le processus lui-même — répond-il encore ? — et ne doit jamais dépendre d'un service extérieur. La sonde de disponibilité, elle, peut légitimement en dépendre : c'est son rôle de dire « je ne peux pas servir en ce moment ».
Quant à la sonde de démarrage, elle évite qu'une application lente à s'initialiser soit tuée
avant d'avoir fini — c'est le start_period du chapitre 4, avec les mêmes conséquences si on
l'oublie.
Mise à l'échelle et déploiement progressif
La mise à l'échelle manuelle est un changement de valeur. La mise à l'échelle automatique ajoute une boucle de plus : un contrôleur observe une métrique — l'usage processeur, par exemple — et ajuste le nombre d'exemplaires entre deux bornes. Deux mises en garde : la métrique doit refléter la charge réelle, et il faut des bornes, faute de quoi une boucle de rétroaction mal réglée peut multiplier les exemplaires jusqu'à épuiser le cluster.
Le déploiement progressif est le comportement par défaut d'un deployment : changer l'image déclenche un remplacement pod par pod, sous deux contraintes réglables — combien d'exemplaires peuvent manquer, et combien peuvent être créés en plus temporairement.
C'est ici que la sonde de disponibilité prend toute son importance. Un nouveau pod n'entre dans le service que lorsqu'elle réussit : si la nouvelle version est défaillante, elle ne reçoit jamais de trafic, et le déploiement s'arrête de lui-même avec l'ancienne version toujours en place. Sans cette sonde, Kubernetes remplace joyeusement des pods sains par des pods cassés, puisque rien ne lui dit qu'ils le sont.
Le retour arrière, enfin, tient en une commande d'annulation : le deployment garde ses révisions précédentes, et redéclarer l'ancienne relance la même boucle.
Ce que ce cours ne traite pas
Trois sujets sont volontairement laissés de côté, et il vaut mieux savoir qu'ils existent.
Les opérateurs étendent Kubernetes avec des contrôleurs sur mesure, pour gérer des objets métier — une base de données répliquée, par exemple. C'est la suite logique du modèle, et c'est un métier.
Le maillage de services ajoute une couche réseau pour le chiffrement, l'observation et le routage fin entre services. Puissant, et d'une complexité qui dépasse largement ce module.
Le stockage persistant avancé — volumes répliqués, classes de stockage, sauvegardes. Le sujet est vaste, et l'usage courant reste de confier les données à un service géré hors du cluster, ce qui est souvent le bon choix.
Un cluster local — k3s, kind, minikube — suffit à tout ce chapitre, sans un centime d'hébergement.
Un pod est supprimé à la main avec kubectl delete pod. Il réapparaît quelques secondes plus tard. Pourquoi ?
Les sondes de vivacité et de disponibilité pointent toutes deux sur une adresse qui vérifie la base de données. La base ralentit. Que se passe-t-il ?
À vous
L'exercice fait tourner la boucle de réconciliation, et c'est le seul moyen de se convaincre qu'elle explique tout le reste.
Vous écrirez le contrôleur : comparer le nombre voulu au nombre réel, agir, recommencer. Puis vous lui enverrez des événements — une panne de nœud, une mise à l'échelle, une modification d'image — et vous constaterez qu'aucun n'a demandé de code supplémentaire.
La seconde partie porte sur le déploiement progressif avec une sonde de disponibilité qui échoue : le déploiement doit s'arrêter de lui-même, l'ancienne version restant majoritaire. Vous relancerez ensuite le même scénario sans sonde, et vous compterez les requêtes perdues.
La troisième reproduit la cascade du second quiz : sondes mal configurées, base qui ralentit, et le nombre de redémarrages que l'orchestrateur provoque. Vous corrigerez la configuration et relancerez le même incident.
Écrivez la boucle de réconciliation, éprouvez un déploiement progressif sans sonde, puis provoquez la cascade de redémarrages.
// ── L'état déclaré, et le monde réel ────────────────────────────────────── const desire = { replicas: 3, image: "appli:1.4" }; let pods = []; // le réel let horloge = 0; let prochainId = 1; const nouveauPod = (image) => ({ id: "pod-" + (prochainId++), image, pret: false, ne: horloge, redemarrages: 0, }); // ── La boucle du contrôleur ─────────────────────────────────────────────── function reconcilier(journal) { const vivants = pods.filter((p) => p.image === desire.image); const ecart = desire.replicas - vivants.length; // ← à écrire : créer si l'écart est positif, supprimer s'il est négatif, // et ne RIEN faire s'il est nul. C'est toute la boucle. return "aucune action"; } // Les pods deviennent prêts quelques instants après leur création. function avancer(secondes, sondePret) { horloge += secondes; for (const p of pods) { if (!p.pret && horloge - p.ne >= 2) p.pret = sondePret(p); } } function etat() { const prets = pods.filter((p) => p.pret).length; return "réel " + pods.length + " (" + prets + " prêts) | désiré " + desire.replicas + " | images " + [...new Set(pods.map((p) => p.image))].join(", "); } // ── À VOUS ──────────────────────────────────────────────────────────────── // 1. Écrivez reconcilier(). Envoyez-lui quatre événements : démarrage, // panne d'un nœud, mise à l'échelle, changement d'image. Combien de // lignes de code chaque événement a-t-il demandées ? // 2. Déploiement progressif avec une sonde qui ÉCHOUE sur la nouvelle // version : le déploiement doit s'arrêter. Relancez sans sonde et // comptez les requêtes perdues. // 3. Reproduisez la cascade : vivacité et disponibilité pointant toutes // deux sur la base. La base ralentit — combien de redémarrages ? console.log(reconcilier([]));
En travaux pratiques
Déployer, exposer, mettre à l'échelle — et rien de plus
Manipuler les cinq objets du chapitre sur un cluster local, jusqu'à voir la boucle de réconciliation réparer, déployer et refuser d'elle-même.
- Un cluster local : k3s, kind ou minikube — aucun hébergement payant
- kubectl configuré, et kubectl get nodes qui répond
- L'image du TP 3 chargée dans le cluster
- 1. Un premier déploiement
Écrivez un Deployment de trois exemplaires de l'application. Appliquez-le, puis listez les pods et notez leurs noms.
- 2. Éprouver la réconciliation
Supprimez un pod à la main. Relistez immédiatement, puis dix secondes plus tard. Expliquez ce que vous observez, puis dites comment retirer RÉELLEMENT un exemplaire.
- 3. Exposer
Ajoutez un Service devant les pods, puis un Ingress pour y accéder depuis votre machine. Vérifiez que le trafic se répartit sur les trois exemplaires.
- 4. Sortir la configuration de l'image
Déplacez l'adresse de la base dans un ConfigMap et le mot de passe dans un Secret, puis injectez-les dans le conteneur. Affichez ensuite le contenu du Secret et commentez.
- 5. Mettre à l'échelle
Passez à dix exemplaires, puis redescendez à deux. Chronométrez chaque opération et observez où les pods sont placés.
- 6. Déployer une nouvelle version
Changez l'étiquette d'image et suivez le remplacement en direct. Combien d'exemplaires sont indisponibles au pire moment ?
- 7. Déployer une version cassée, AVEC sonde
Ajoutez une sonde de disponibilité, puis déployez une version dont cette sonde échoue. Que fait le déploiement ? Combien de requêtes sont perdues ?
- 8. Recommencer SANS sonde
Retirez la sonde et refaites l'essai. Comparez, puis exécutez un retour arrière.
- 9. Provoquer la cascade
Faites pointer la sonde de vivacité sur une adresse qui vérifie la base, puis arrêtez la base. Comptez les redémarrages. Corrigez et refaites l'essai.
- Un pod supprimé revient seul, et vous savez expliquer pourquoi
- Le déploiement de la version cassée s'arrête TOUT SEUL, sans requête perdue
- Vous savez dire ce que le Secret protège réellement
- La correction des sondes fait tomber le nombre de redémarrages à zéro
Ce que la suite en fait
Le bloc VI ajoute ce sans quoi tout ce qui précède est aveugle. Kubernetes redémarre des pods, retire du trafic, arrête des déploiements — et rien de tout cela ne se voit sans métriques ni journaux centralisés. Le chapitre 10 fournit les trois piliers, et rend enfin possible la décision automatique du canari du chapitre 6.
Le chapitre 11, lui, reprendra le Secret encodé en base64, les images tirées de registres publics et les droits d'accès au cluster — trois sujets que ce chapitre n'a fait qu'effleurer.
À retenir
Vous avez parcouru les 11 sections.
Marquez-la terminée pour faire avancer votre parcours, ou revenez sur un point avant de passer à la suite.