Formation MLOps · Dotika · Bloc 7 · 12 h

L'échelle

Déploiement, orchestration & monitoring — le détecteur doit tenir la charge, sous surveillance. Le gros morceau de la semaine : trois jours, un cluster.

Le fil rouge · où on en est

La chaîne qualité tourne — sur une seule machine

Bloc 6 : chaque commit est testé, validé, versionné — la chaîne qualité est entièrement automatique. Mais regardez la carte : tout ce système vit dans un seul conteneur, sur une seule machine. Une panne, un pic de trafic — et plus personne ne détecte rien.

Mission du bloc 7 : le faire tourner en prod, à l'échelle et sous surveillance.

KubernetesPrometheusGrafana
L'objectif du bloc

À la fin du bloc, le détecteur tourne répliqué sur un cluster : il encaisse les pannes et la charge, se met à jour sans coupure — et une alerte part dès que le modèle dérive

Autrement dit : le système cesse d'être une démo qui tourne sur un laptop, et devient un service — qui survit aux machines, aux pics et aux vendredis soir.

Bloc 7 · 12 h · théo 2h30 / prat 9h30

Cinq chantiers

3h00
Concepts K8s & manifestsPods, deployments, services, configmaps — le vocabulaire, puis les mains dedans.
théo 1h30 · prat 1h30
2h00
Déploiement de l'API + probesLiveness / readiness / startup — le détecteur servi par le cluster, et surveillé par lui.
prat 2h00
3h00
Stratégies & scalingRolling, canary, blue-green — livrer sans couper ; HPA — encaisser la charge.
théo 1h00 · prat 2h00
2h30
Monitoring infra + monitoring du modèlePrometheus, Grafana — puis la partie que tout le monde oublie : la détection de drift.
prat 2h30
1h30
Rollback & observabilité end-to-endLa marche arrière en un geste, et suivre une transaction de l'API au verdict.
prat 1h30
Le bloc s'étale sur trois jours

La carte des trois jours

12 heures, c'est un tiers de la formation. Voici comment elles se répartissent — pour toujours savoir où on en est.

Jour 3 · 1 h
Fin de journée : les concepts. On repart avec le vocabulaire — cluster, pod, deployment, service — et l'idée déclarative en tête.
Jour 4 · 8 h
La grosse journée : manifests au clavier, l'API déployée avec ses probes, les stratégies de livraison, le HPA — et le monitoring jusqu'à la détection de drift.
Jour 5 · 3 h
Le matin : rollback répété à froid et observabilité end-to-end — la marche arrière et les yeux, avant l'assemblage final du bloc 8.
Acte 1

La nuit du
Black Friday

Une histoire vraie, mille fois

2 h du matin, Black Friday. Le trafic est à 50× la normale. Un serveur meurt.
Et personne… n'est réveillé.

Le lendemain matin, l'équipe découvre l'incident en lisant les logs : tout avait déjà été réparé — sans aucun humain.

Ce qui s'est passé cette nuit-là

Personne n'a rien fait.
Et tout a tenu

Un orchestrateur veillait : il a constaté la mort du serveur, redéployé les conteneurs ailleurs en quelques secondes, réparti la charge sur les survivants — et ajouté des réplicas quand le trafic montait. C'est ce système qu'on apprend sur trois jours.

La meilleure astreinte est celle qu'on ne réveille jamais.

02:04 node-3 unreachable
02:04 rescheduling 2 pods → node-1, node-2
02:05 replicas 6/6 healthy
02:31 traffic ×50 → scaling 6 → 10
08:30 un humain lit les logs, café à la main
La chronologie réelle d'un incident… qui n'en est plus un.
Pourquoi un conteneur seul ne suffit pas

Une boîte, trois problèmes entiers

Le bloc 4 a rendu le système portable. Mais une boîte, seule sur une machine, laisse trois questions sans réponse.

La panne
Le conteneur meurt à 2 h du matin : qui le relance ? La machine entière meurt : qui le déplace ailleurs ? Personne — donc coupure.
L'échelle
Black Friday : 50× le trafic. Un conteneur, c'est une capacité fixe. Il en faudrait dix maintenant — puis trois à 4 h du matin.
La mise à jour
Remplacer la v12 par la v13 sans couper le service ? Avec un seul conteneur, stop = coupure. Et un détecteur de fraude coupé, c'est la porte ouverte.

Ces trois problèmes ont une seule réponse : l'orchestration. Et elle repose sur une idée d'une élégance rare.

L'idée clé · façon Feynman

Décrire l'état,
pas donner d'ordres

On ne dit pas « démarre un conteneur ici, puis un autre là ». On écrit un souhait : « je veux 3 réplicas en bonne santé, derrière cette adresse ». Le chef d'orchestre compare en permanence le réel au souhait — et corrige l'écart, tout seul, pour toujours.

Vous décrivez le monde tel qu'il devrait être. Kubernetes se charge du reste.

# vous déclarez :
replicas: 3

# le cluster constate :
running: 2  # ← écart !

# il agit, sans vous demander :
starting 1 pod… → running: 3
La boucle de réconciliation : constat → écart → action. En continu.
Acte 2 · théo 1h30

Le vocabulaire
du cluster

Concept 1 / 5

Le cluster :
des machines, un cerveau

Les nodes sont des machines banales : elles font le travail, elles peuvent mourir. Le control plane est le cerveau : il garde en tête l'état désiré, place les conteneurs, constate les écarts, corrige. C'est lui, le chef d'orchestre de la nuit du Black Friday.

Vous ne parlez jamais aux machines. Vous parlez au cerveau — il s'occupe des machines.

control plane l'état désiré vit ici node-1 node-2 node-3 les nodes travaillent — le control plane décide
Un cluster = des bras + un cerveau.
Concept 2 / 5

Le pod : la plus petite unité

Un pod, c'est votre conteneur habillé pour le cluster — avec une adresse IP, des ressources allouées et un cycle de vie surveillé.

En pratique : presque toujours un conteneur par pod. Et surtout, les pods sont éphémères par conception : ils meurent, renaissent ailleurs, changent d'adresse. Ne vous attachez jamais à un pod — c'est prévu pour.

kubectl get podsdetector-7d4b9-x2vq8 · Runningle nom change à chaque renaissance
Concept 3 / 5

Le deployment : le contrat de réplicas

« Je veux 3 réplicas de l'image v12, en bonne santé, en permanence. » Le deployment, c'est ce contrat — signé et surveillé.

Un pod meurt ? Il en recrée un. Vous changez l'image ? Il orchestre le remplacement, un pod à la fois. C'est le deployment qui matérialise l'idée déclarative — et c'est à lui qu'on parlera toute la semaine.

replicas: 3image: detector:v12le contrat vit dans Git
Concept 4 / 5 · le standard téléphonique

Le service :
l'adresse stable

Les pods naissent et meurent, leurs adresses changent sans arrêt. Le service est le numéro du standard : une adresse fixe, connue de tous, qui route chaque appel vers les pods vivants à cet instant — et répartit la charge entre eux.

On n'appelle jamais un pod. On appelle le standard — lui sait qui est de garde.

service adresse stable pod A pod B pod C † retiré
Le pod C meurt : le service cesse de l'appeler. Personne ne s'en aperçoit.
Concept 5 / 5

La config hors de l'image

Rappel des blocs 3 et 4 : la même image doit tourner partout. Ce qui change entre dev et prod — seuils, URLs, mots de passe — vit à côté.

Config dans l'image
Tout est figé dans la boîte
  • Changer le seuil d'alerte = reconstruire l'image
  • Les mots de passe traînent dans le code et le registry
ConfigMap & Secret
La config injectée au démarrage
  • ConfigMap : seuils, URLs — versionnés, modifiables sans rebuild
  • Secret : credentials à part, jamais dans l'image ni dans Git

Une seule image, portée par des configs différentes selon l'environnement — le principe build once, run anywhere tenu jusqu'au bout.

L'état désiré, écrit noir sur blanc

Le manifest : un souhait en YAML

Tout ce qu'on vient de voir s'écrit dans des fichiers texte — les manifests. Voici l'essentiel d'un deployment, débarrassé du cérémonial :

kind: Deployment  # le contrat
metadata: { name: detector }
spec:
  replicas: 3  # l'état désiré
  template:
    spec:
      containers:
      - image: registry/detector:v12  # la boîte du bloc 4

Ces fichiers vivent dans Git : l'infrastructure se relit, se revoit en PR, se versionne comme du code. Toute la discipline du bloc 6 s'applique aussi à elle.

L'outil de dialogue

kubectl : cinq commandes pour la semaine

On ne mémorise pas 200 commandes. Cinq suffisent pour tout le bloc — les mêmes que sur un cluster de production.

kubectl apply -f deploy.yaml  # déclarer l'état désiré
kubectl get pods  # constater l'état réel
kubectl describe pod detector-x2vq8  # enquêter
kubectl logs detector-x2vq8  # lire ce qu'il raconte
kubectl rollout undo deploy/detector  # reculer — acte 6

Déclarer, constater, enquêter, lire, reculer. Tout le reste est de la variation.

Acte 3

Déployer
le détecteur

Notre terrain d'entraînement

Un vrai cluster, sur votre machine

Pas besoin d'un datacenter pour apprendre : kind fait tourner un cluster Kubernetes complet… dans Docker.

Complet
Control plane, nodes, API : tout y est. Ce n'est pas un simulateur — c'est Kubernetes, le vrai.
Identique
Les manifests écrits ici s'appliquent tels quels sur un cluster cloud. On apprend une seule fois.
Jetable
Cassé quelque chose ? On détruit, on recrée, deux minutes. Le meilleur terrain de jeu pour expérimenter sans peur.
kind create clusterkubectl get nodes2 minutes chrono
Le détecteur entre en scène

Votre API,
version cluster

L'image, c'est celle que la CI du bloc 6 a poussée au registry — on ne reconstruit rien. On y ajoute ce que le cluster doit savoir : combien de réplicas, et combien de mémoire — car votre modèle vit en RAM.

Le manifest dit au cluster tout ce qu'un ops aurait dû savoir par cœur.

replicas: 3
containers:
- image: ghcr.io/…/detector:v12  # poussée par la CI
  resources:
    requests: { memory: 2Gi }  # le modèle vit en RAM
  envFrom:
  - configMapRef: { name: detector-config }  # le seuil
Toute la chaîne des blocs 3 à 6 converge dans ces huit lignes.
Une histoire de prod

Le process tourne. Le port répond.
Et l'application est morte.

Le pod zombie : vivant pour le système, mort pour vos clients. Kubernetes ne peut pas le deviner — sauf si vous lui donnez des yeux. Ces yeux s'appellent des probes.

Les yeux du cluster sur vos pods

Trois questions, posées en boucle

Une probe est une question que le cluster pose à votre pod, toutes les quelques secondes. Trois questions, trois réactions différentes.

Liveness · « es-tu vivant ? »
Échecs répétés → le pod est tué et remplacé. Le remède au zombie : plutôt renaître que ramper.
Readiness · « es-tu prêt ? »
Échec → le service cesse de lui envoyer du trafic, sans le tuer. Surchargé ou en train de charger ? On le laisse souffler.
Startup · « as-tu fini de démarrer ? »
Tant qu'elle n'a pas réussi, les deux autres attendent. La période de grâce du démarrage.

Bien réglées, elles font du cluster une astreinte automatique. Mal réglées… c'est la slide suivante.

Le détail qui tue · spécifique ML

Nos modèles sont
longs à charger

Au démarrage, l'API charge des centaines de Mo de modèle en mémoire : 30, 60, 90 secondes. Sans startup probe, la liveness s'impatiente et tue le pod avant la fin du chargement. Il redémarre, recharge, se fait retuer — la boucle de crash infinie, le grand classique du déploiement ML.

Le pod n'était pas malade. On ne lui laissait juste pas le temps de se réveiller.

startupProbe:  # la période de grâce
  httpGet: { path: /health }
  failureThreshold: 30  # 30 × 10 s pour charger
readinessProbe:
  httpGet: { path: /health }  # modèle chargé ?
livenessProbe:
  httpGet: { path: /health }  # process sain ?
/health ne répond OK que si le modèle est en mémoire — votre API du bloc 3 sait déjà le dire.
Acte 4 · théo 1h00

Livrer
sans couper

Stratégie 1 / 3 · le défaut

Rolling update :
un par un

La v13 arrive : Kubernetes démarre un pod v13, attend qu'il soit ready (merci les probes), éteint un v12, et recommence — jusqu'à remplacement complet. À aucun moment le service ne descend sous l'effectif.

La relève se fait poste par poste — la garde ne quitte jamais le mur.

t0 v12 v12 v12 t1 v13 v12 v12 t2 v13 v13 v12 3 en service 3 en service 3 en service
Zéro coupure — tant que la v13 passe ses probes.
Stratégie 2 / 3 · la reine pour les modèles

Le canari :
5 % d'abord

La v13 ne remplace personne : elle reçoit 5 % du trafic réel, à côté de la v12. On surveille tout — latence, erreurs, et surtout les métriques du modèle : distribution des scores, taux d'alerte. Ça tient ? 25 %, 50 %, 100 %. Ça dérive ? Retour à 0 % — presque personne n'a rien vu.

Un modèle peut passer tous les tests offline et échouer en prod. La seule vérité est le trafic réel — le canari le goûte en premier.

trafic v12 · 95 % le champion v13 · 5 % le canari métriques OK ? → 25 % → 50 % → 100 % · sinon → 0 %
Le nom vient des mines : le canari respirait le danger avant les mineurs.
Stratégie 3 / 3

Blue-green : deux mondes, un aiguillage

Blue · en service
La v12, 100 % du trafic
  • L'environnement complet qui sert la prod, intouché
  • Reste prêt à reprendre la main d'un coup d'aiguillage
Green · en attente
La v13, complète, à 0 %
  • Déployée entièrement à côté, testée à froid
  • La bascule est un seul geste — le retour aussi
Bascule et retour instantanés — au prix de deux environnements complets qui tournent en même temps. Le luxe des moments critiques.
Le comparatif

Quelle stratégie, quand ?

Rolling — la routine
Changement à faible risque, confiance dans les probes. Le défaut de Kubernetes, et le bon choix 80 % du temps.
Canary — le nouveau modèle
Comportement incertain, envie de voir du trafic réel avant de s'engager. Le choix ML par excellence.
Blue-green — le critique
Retour instantané exigé, budget double accepté. Migrations lourdes, moments à très fort enjeu.

Pour la v13 du détecteur, le verdict est sans appel : canary. Un modèle ne se juge qu'au contact du monde réel — et on préfère qu'il le rencontre à 5 %.

Et la charge ? · autoscaling

HPA :
l'élastique

Le HorizontalPodAutoscaler observe une métrique — CPU, requêtes par seconde — et ajuste le nombre de réplicas entre un min et un max. Black Friday : 3 → 10 pods, tout seul. 4 h du matin : retour à 3. C'est lui, le héros silencieux de l'acte 1.

On ne dimensionne plus pour le pic. On dimensionne pour l'instant.

kind: HorizontalPodAutoscaler
spec:
  minReplicas: 3  # jamais moins
  maxReplicas: 10  # jamais plus (le budget)
  metrics: cpu > 70 % → ajouter des pods
Encore du déclaratif : on décrit les bornes, il tient la promesse.
Acte 5

Les yeux

Monitoring 1 / 2 · l'infrastructure

Prometheus collecte,
Grafana montre

Chaque pod expose ses chiffres sur /metrics ; Prometheus passe les aspirer toutes les 15 secondes ; Grafana en fait des tableaux de bord. Trois courbes répondent à 90 % des questions : latence, taux d'erreurs, saturation.

Un service sans métriques n'est pas en production. Il est en liberté surveillée — sans le surveillé.

latence p95 erreurs / s CPU · saturation
Le dashboard infra : la santé de la machine. Mais pas celle du modèle…
Monitoring 2 / 2 · ce que 90 % des équipes oublient

Votre API peut être parfaitement verte
et votre modèle parfaitement faux.

200 OK, 40 ms, zéro erreur… et un détecteur qui laisse tout passer. Souvenez-vous des douleurs 3 et 4 du bloc 1 : le monde change, le modèle vieillit — sans jamais faire sonner une seule alarme infra.

Les capteurs côté modèle

Trois capteurs sur le modèle

Le modèle ne lève jamais d'exception quand il se trompe. Il faut instrumenter ses opinions — pas seulement son process.

La distribution des scores
Hier centrée sur 0,1 — aujourd'hui sur 0,4 ? Quelque chose a changé. Pas dans le code : dans le monde.
Le taux d'alerte
0,2 % d'alertes en temps normal. Ce matin : 0 % — ou 3 %. Le modèle dort, ou crie au loup. Les deux coûtent cher.
Le drift des features
Montants, heures, V1…V28 : leurs distributions n'ont plus la tête de l'entraînement. Le signal d'alarme le plus précoce.

Ces trois capteurs sont des métriques comme les autres — exposées par votre API, aspirées par Prometheus, tracées dans Grafana. Même tuyau, nouveau regard.

La détection de drift, en pratique

Comparer la prod
à l'entraînement

On garde les distributions du train comme référence. Chaque jour, feature par feature, on les compare à celles de la prod — test statistique ou simple distance. L'écart franchit le seuil sur assez de features ? Alerte.

Le modèle n'a pas changé d'avis. C'est le monde qui a changé de visage.

entraînement prod, aujourd'hui feature « montant » — l'écart entre les deux courbes, c'est le drift
La distribution a glissé : le modèle score un monde qu'il n'a jamais vu.
Le moment important

L'alerte qui referme la boucle

Drift détecté → alerte → réentraînement sur données fraîches → v4 au registry → canary → prod. La boucle du MLOps se ferme ici.

Souvenez-vous du cycle de vie dessiné au bloc 1 : ce n'était qu'un schéma. Cette alerte le rend vivant — le système sait désormais dire lui-même « je vieillis, réentraînez-moi ». C'est exactement ça, le MLOps : la boucle complète, fermée, automatique.

rappel bloc 1 · cycle de vierappel bloc 5 · registryla v4 attend son canari
Acte 6

Quand ça
tourne mal

La marche arrière

Reculer, en un geste — aux deux niveaux

Niveau app · Kubernetes
Le deployment garde l'historique des versions. Une commande, et les pods v12 remplacent les v13 — probes à l'appui.
kubectl rollout undo quelques secondes
Niveau modèle · registry
Rappel du bloc 5 : dans le registry MLflow, on repointe l'alias Production de la v4 vers la v3. Le champion déchu redevient challenger.
v13 → v12 un changement d'alias
Un incident ML a toujours deux suspects : le code et le modèle. Préparez la marche arrière des deux — et répétez-la à froid.
Les trois signaux

Suivre une transaction,
de bout en bout

Logs : ce qui s'est dit. Métriques : combien, en moyenne. Traces : où le temps est passé, pour une requête précise. Avec un identifiant de corrélation, on suit UNE transaction de l'API au verdict — et « pourquoi celle-ci a été bloquée ? » se répond en minutes, pas en jours.

Trois signaux, une histoire : chaque requête doit pouvoir raconter la sienne.

trace 8f3a · POST /predict
├ api · validation      2 ms
├ model · scoring     38 ms  # v13 · seuil 0.31
└ verdict · fraud=0.91 → bloquée

# le même id 8f3a dans les logs, les métriques, la trace
L'audit trail du bloc 6 + les traces du bloc 7 : la transparence complète.
La culture qui va avec

Le post-mortem sans blâme

On ne cherche pas qui a cassé. On cherche ce qui a laissé la casse se produire.

Chronologie, impact, causes, actions — un document court, écrit à froid, versionné avec le code. Les meilleures équipes ne sont pas celles qui ne tombent jamais : ce sont celles qui transforment chaque chute en garde-fou. Vous en écrirez un, en vrai, à la mission 5.

chronologieimpactcausesactionszéro nom, zéro blâme
Démo live · à vous de jouer

Le cluster, entre vos mains

chargeBlack Friday
Pods en service / désirés
Charge
Monitoring du modèle
Avant les labs · l'essentiel

Cinq réflexes à emporter

Réflexe 1
Déclarer, ne pas commander
L'état désiré dans un YAML versionné — le cluster corrige l'écart, en continu.
Réflexe 2
Des probes pensées ML
Startup généreuse (le modèle charge), readiness honnête, liveness prudente. Sinon : boucle de crash.
Réflexe 3
Canary pour tout nouveau modèle
La seule vérité est le trafic réel — 5 % d'abord, les métriques décident de la suite.
Réflexe 4
Monitorer le modèle, pas seulement l'API
Scores, taux d'alerte, drift des features. Une API verte ne prouve rien sur le modèle.

Et le cinquième : répéter le rollback avant d'en avoir besoin. La marche arrière se prépare à froid — jamais à 2 h du matin.

Acte 7 · lab

À vous :
9h30 au clavier

Mission 1 / 5 · 1h30 · pratique

Votre premier cluster

Créer le cluster de poche avec kind, puis écrire vos premiers manifests : un deployment 3 réplicas, son service, une configmap — et vérifier l'idée déclarative en vrai : tuez un pod à la main, regardez-le renaître.

Livrable : un dossier k8s/ commité (deployment + service + configmap), et la capture du pod qui renaît tout seul.

kind create clusterkubectl apply -fkubectl get pods -wkubectl delete pod

Binômes : un qui tape, un qui prédit ce que le cluster va faire — puis on échange.

Mission 2 / 5 · 2h00 · pratique

Déployer le détecteur — avec ses probes

Déployer VOTRE API — l'image que votre CI du bloc 6 a poussée au registry — avec configmap pour le seuil et les trois probes réglées pour le chargement du modèle. Test de vérité : tuer un pod pendant qu'un script envoie du trafic.

Livrable : l'API servie par le cluster, et `kubectl delete pod` en pleine charge sans une seule requête perdue.

startupProbereadinessProbelivenessProberesources: memory/health du bloc 3

Piège volontaire : la config fournie tue le pod pendant le chargement. À vous de comprendre pourquoi — et de régler la startup probe.

Mission 3 / 5 · 2h00 · pratique

Livrer sans couper, encaisser la charge

Rolling update v12 → v13 sous trafic, puis un canary manuel : deux deployments derrière le même service, 5 % puis 25 % puis 100 %. Enfin le HPA : injecter de la charge, regarder les pods se multiplier — puis redescendre.

Livrable : votre tableau des trois stratégies (quand, pourquoi, comment revenir) + le HPA observé en montée ET en descente.

rollout statuscanary 5 %HPAhey / locustkubectl get hpa -w

La question à se poser à chaque bascule : « et si les métriques plongent, je reviens comment ? »

Mission 4 / 5 · 2h30 · pratique

Ouvrir les yeux — infra ET modèle

Installer Prometheus + Grafana (manifests fournis), câbler le dashboard infra — latence, erreurs, saturation. Puis instrumenter VOTRE API : score moyen, taux d'alerte en métriques. Enfin, le script de drift : comparer les distributions de prod (données déviées fournies) à la référence d'entraînement, et déclencher l'alerte.

Livrable : un dashboard à deux étages — infra en haut, modèle en bas — et une alerte de drift qui part vraiment.

PrometheusGrafana/metricsscore moyen · taux d'alertedrift par feature

C'est la mission la plus longue du bloc — parce que c'est celle que 90 % des équipes ne font jamais.

Mission 5 / 5 · 1h30 · pratique

L'incident, en conditions réelles

On vous livre une v13 volontairement cassée. Déployez-la en canary, voyez les métriques plonger, puis reculez aux deux niveaux : `kubectl rollout undo` côté app, repointage du registry côté modèle. Suivez ensuite une transaction précise dans les logs grâce à son identifiant — et écrivez le post-mortem.

Livrable : l'incident résolu en moins de dix minutes, et un post-mortem d'une page — chronologie, impact, causes, actions.

rollout undoregistry v4 → v3correlation idpost-mortem sans blâme

Le chrono tourne — mais rappelez-vous : le canari n'a exposé que 5 % du trafic. Vous avez le temps de bien faire.

Le fil rouge · fin du bloc 7

Le système vit — et il se surveille

Regardez la carte : le conteneur s'est multiplié en réplicas derrière un load balancer, les capteurs du monitoring sont allumés, et la flèche du réentraînement referme la boucle sur le registry. Le détecteur tourne en prod, à l'échelle, sous surveillance.

Il ne reste qu'une chose : tout assembler, de bout en bout — et le prouver, devant les autres.

répliqué ✓sans coupure ✓drift surveillé ✓
La suite

Assembler,
et prouver

Bloc 8 — Assemblage final & présentations : commit → CI/CD → canary K8s → modèle servi depuis MLflow → monitoring. Toute la chaîne, en une démo — la vôtre.

Pas à pas ↗