Débutant Chapitre 5-6 / 6

Spec et status : l'anatomie d'un objet Kubernetes & La boucle de contrôle, l'idée fondatrice

L'anatomie d'un objet Kubernetes (apiVersion, metadata, spec, status) et la boucle de contrôle qui fait converger l'état réel vers l'état désiré — sans prérequis, avec YAML et kubectl.

Spec et status : l’anatomie d’un objet Kubernetes

L’idée en une phrase

Tout objet Kubernetes se divise en deux sections complémentaires : la spec, qui décrit l’état désiré (ce qui est voulu), et le status, qui consigne l’état réel observé (ce qui est constaté). La réconciliation est précisément le travail qui rapproche le second du premier : un contrôleur lit la spec, observe le status, et agit pour combler l’écart.

Analogie : Considérons un bon de livraison et son suivi de colis. L’expéditeur remplit le bon — « livrer 3 colis à telle adresse » : c’est la commande, fixée, l’équivalent de la spec. Le transporteur, lui, ne modifie jamais la commande ; il met à jour la page de suivi — « 2 colis livrés, 1 en transit » : c’est le constat, l’équivalent du status. Deux sections, deux rédacteurs distincts ; le client n’inscrit jamais « livré » à la place du transporteur.

Points clés

  • Tout objet se compose de quatre parties : un en-tête (apiVersion, kind, vus au chapitre 3-4), metadata (l’identité : nom, namespace, labels), spec (l’état désiré) et status (l’état réel observé).
  • La spec est rédigée par l’auteur de l’objet — un humain via un manifeste, ou un contrôleur de niveau supérieur. Elle exprime une intention, jamais un ordre immédiat.
  • Le status est rédigé exclusivement par le contrôleur responsable de l’objet. On ne renseigne jamais le status dans un manifeste : kubectl apply n’écrit que la spec.
  • L’écart entre spec et status est le moteur de la réconciliation : tant que le status diffère de la spec, une boucle a du travail. Quand les deux coïncident, l’objet est dit convergé.
  • Le status n’est pas la spec recopiée : il porte des champs propres au constat — availableReplicas (nombre de pods réellement disponibles), conditions (état de santé synthétique) ou observedGeneration (la version de la spec déjà traitée) — sans équivalent dans la spec.

Exemple concret

Un Deployment déclare spec.replicas: 3. Juste après l’enregistrement, son status indique availableReplicas: 0 : l’écart est maximal. Le contrôleur de Deployment crée les pods ; à mesure qu’ils démarrent, il réécrit le status — 1, puis 2, puis 3. À availableReplicas: 3, status et spec coïncident : la boucle n’a plus rien à faire. Si un pod est supprimé à 14 h 02, le status retombe à 2 ; l’écart réapparaît, le contrôleur recrée un pod, et le status remonte à 3. La spec, elle, n’a pas changé une seule fois.

spec et status — deux sections, deux rôles

Critèrespecstatus
DécritL’état désiré (le « quoi »)L’état réel observé (le constat)
Rédigé parL’auteur de l’objet (humain ou contrôleur)Le contrôleur responsable, exclusivement
Écrit par kubectl applyOuiNon
Rôle dans la boucleLa cible vers laquelle convergerLe point de départ mesuré

Code YAML — on ne rédige que la spec

# deployment.yaml — le manifeste ne contient QUE la spec (l'état désiré)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello              # metadata : l'identité de l'objet
spec:                      # spec : l'état désiré, le contrat
  replicas: 3             # l'intention : "je veux 3 pods disponibles"
  selector:
    matchLabels:
      app: hello
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
        - name: web
          image: nginx:1.27
# status : ABSENT du manifeste — c'est le contrôleur qui le remplira

Code kubectl — lire le status renseigné par le contrôleur

# Après apply, l'objet enregistré porte un status, écrit par le contrôleur
kubectl get deployment hello -o yaml
# spec:
#   replicas: 3                 ← l'état désiré, tel que déclaré
# status:
#   observedGeneration: 1       ← quelle version de la spec le contrôleur a traitée
#   replicas: 3
#   readyReplicas: 3
#   availableReplicas: 3        ← l'état réel : 3 pods disponibles → convergé

# Vue condensée du même écart (ici : nul)
kubectl get deployment hello
# NAME    READY   UP-TO-DATE   AVAILABLE   AGE
# hello   3/3     3            3           20s   ← READY 3/3 : status == spec

Piège courant : « Modifier le status corrige l’état du cluster » est inexact — le status n’est qu’un constat. Le forcer à la main (via la sous-ressource status, chapitre 21-22) ne crée ni ne supprime aucun pod : au tick suivant, le contrôleur ré-observe l’état réel et réécrit la valeur exacte, effaçant la retouche. Pour changer ce que fait le cluster, on modifie la spec, jamais le status.


La boucle de contrôle, l’idée fondatrice

L’idée en une phrase

Une boucle de contrôle (control loop) est un processus qui répète sans fin trois actions — observer l’état réel, calculer l’écart (diff) avec l’état désiré, agir pour le réduire. C’est l’idée fondatrice de Kubernetes : le cluster n’exécute pas une suite d’ordres, il fait tourner en permanence des boucles qui convergent vers la spec.

Analogie : Considérons un GPS de navigation. La destination saisie est l’état désiré ; la position mesurée par le satellite est l’état réel ; à chaque instant, l’appareil compare les deux et recalcule l’itinéraire. Un virage manqué ne provoque pas d’erreur : la boucle observe la nouvelle position, recalcule l’écart, propose une correction. Le GPS ne suppose jamais que ses instructions ont été suivies — il vérifie, encore et encore.

Points clés

  • Une boucle de contrôle est continue, pas ponctuelle : elle ne s’exécute pas une fois après l’apply, elle tourne indéfiniment. C’est ce qui permet l’auto-réparation (self-healing) sans intervention.
  • Le composant qui héberge une boucle est un contrôleur (controller). Le kube-controller-manager en regroupe plusieurs — Deployment, ReplicaSet, Node… — chacun responsable d’un type d’objet (anatomie détaillée au chapitre 11-12).
  • Une boucle ne pilote jamais directement les machines : elle lit et écrit des objets via l’API server (chapitre 3-4). Agir, pour un contrôleur, c’est le plus souvent créer ou modifier d’autres objets, non lancer un conteneur soi-même.
  • La boucle est idempotente : si l’état réel correspond déjà à l’état désiré, le tick ne fait rien. Réexécuter une boucle sur un état convergé est sans effet — propriété centrale, approfondie au chapitre 23-24.
  • Plusieurs boucles coopèrent sans se coordonner explicitement : chacune observe l’état et réagit pour son objet. Cette indépendance est ce qui rend le système robuste (architecture vue au chapitre 7-8).

Exemple concret

Un ReplicaSet déclare 3 pods. Sa boucle s’exécute à chaque changement observé, et périodiquement par sécurité. À t₀, état réel 3, désiré 3 : l’écart est nul, le tick ne fait rien. À 14 h 02, un nœud tombe et emporte un pod. Au tick suivant, la boucle observe 2 pods, calcule l’écart (3 − 2 = 1) et crée un pod. Ce pod met quelques secondes à devenir prêt ; pendant ce délai, un nouveau tick peut observer encore 2 pods disponibles — mais comme un pod est déjà en création, une boucle correctement écrite n’en crée pas un second. Une fois le pod prêt, l’état réel revient à 3 : les ticks suivants ne font plus rien.

Une exécution unique vs une boucle de contrôle

CritèreScript lancé une foisBoucle de contrôle
DéclenchementUne fois, à la demandeEn continu, sans fin
Après une panneAucune correction automatiqueÉcart ré-observé, puis comblé
Hypothèse sur le résultatSuppose le succèsNe suppose rien — vérifie
Si l’état est déjà correctRéapplique aveuglémentNe fait rien (idempotent)

Code — la boucle, en pseudo-code

boucle infinie:
    désiré = lire la spec de l'objet            # observer (1/2)
    réel   = observer l'état réel du cluster     # observer (2/2)
    écart  = comparer(désiré, réel)              # diff
    si écart non nul:
        agir pour réduire l'écart                # agir : créer / modifier / supprimer
    attendre (un événement, ou la prochaine échéance)

Code kubectl — observer l’auto-réparation

# État convergé : 3 pods désirés, 3 réels
kubectl get pods -l app=hello
# NAME                  READY   STATUS    RESTARTS   AGE
# hello-7d4b9c-aaa11    1/1     Running   0          5m
# hello-7d4b9c-bbb22    1/1     Running   0          5m
# hello-7d4b9c-ccc33    1/1     Running   0          5m

# Supprimer un pod À LA MAIN : on crée volontairement un écart
kubectl delete pod hello-7d4b9c-aaa11
# pod "hello-7d4b9c-aaa11" deleted

# Sans aucune autre commande, la boucle a déjà comblé l'écart
kubectl get pods -l app=hello
# NAME                  READY   STATUS    RESTARTS   AGE
# hello-7d4b9c-bbb22    1/1     Running   0          5m
# hello-7d4b9c-ccc33    1/1     Running   0          5m
# hello-7d4b9c-ddd44    1/1     Running   0          3s    ← recréé par la boucle

Piège courant : « La boucle ne se déclenche que lorsqu’on lance une commande » est inexact — elle tourne en permanence, indépendamment de toute action de l’opérateur. Supprimer un pod géré par un contrôleur ne le retire donc pas durablement : la boucle observe l’écart et recrée un pod équivalent (au nom différent). Pour retirer réellement un pod, on modifie l’état désiré — réduire replicas, supprimer le Deployment —, jamais l’état réel directement.


Quiz — validation des acquis
Débutant 7 questions Objectif : 5/7 minimum
0/7
bonnes reponses
Objectif non atteint (minimum 5/7 requis).
Relire la fiche memo ci-dessus en pretant attention aux points manques, puis cliquer sur « Recommencer » pour retenter.