kubectl apply et les manifestes YAML & etcd, le magasin de l'état désiré
Comment l'état désiré entre dans le cluster (manifestes YAML, kubectl apply) et où il est conservé (etcd) — sans prérequis, avec YAML et kubectl.
kubectl apply et les manifestes YAML
L’idée en une phrase
Un manifeste est un fichier YAML qui décrit un objet Kubernetes — donc un fragment d’état désiré ; kubectl apply le transmet à l’API server, qui le valide et l’enregistre. L’apply ne déclenche aucune action sur les machines : il met à jour la déclaration, et la boucle de réconciliation (chapitre 1-2) se charge ensuite, en continu, de faire converger l’état réel.
Analogie : Considérons le dépôt d’un formulaire au guichet d’une administration. Le guichet contrôle que le formulaire est complet et conforme, l’enregistre au registre officiel, puis délivre un récépissé. Le traitement effectif est réalisé plus tard, par d’autres services, sur la seule base du registre. Le formulaire est le manifeste, le guichet l’API server, et le récépissé la réponse
created.
Points clés
- Tout manifeste comporte quatre champs racine : apiVersion (le groupe et la version de l’API qui définissent l’objet), kind (le type d’objet), metadata (l’identité : nom, namespace, labels) et spec (l’état désiré proprement dit).
kubectl apply -fenvoie le manifeste à l’API server par une requête HTTPS. kubectl ne dialogue jamais directement avec les nœuds ni avec la base de données : l’API server est le guichet unique du cluster.- L’apply est idempotent, comme vu au chapitre 1-2 : la réponse vaut
created(l’objet n’existait pas),configured(la déclaration enregistrée différait) ouunchanged(aucun écart, aucune écriture). - L’apply effectue une fusion à trois sources (three-way merge) : la dernière configuration appliquée, l’état enregistré dans le cluster et le nouveau fichier. Il ne touche qu’aux champs que le fichier gère — les champs écrits par d’autres acteurs sont préservés.
kubectl diff -fcalcule l’écart entre le fichier et la déclaration enregistrée sans rien modifier ;--dry-run=serversoumet le manifeste à toutes les validations de l’API server sans l’enregistrer.
Exemple concret
Un fichier deployment.yaml déclare 3 replicas de nginx:1.27. À l’exécution de kubectl apply -f deployment.yaml, l’API server valide le manifeste (schéma, droits d’accès), l’enregistre, puis répond created en quelques dizaines de millisecondes. À cet instant précis, aucun pod n’existe encore : seul l’état désiré a changé. Les boucles de contrôle constatent l’écart (désiré 3, réel 0) et créent les pods dans les secondes qui suivent. Une semaine plus tard, l’image est mise à jour vers nginx:1.28 dans le fichier ; le même apply répond configured, et la convergence reprend — même commande, même mécanique.
Les verbes kubectl face à l’état désiré
| Commande | Style | Rejouable sans effet de bord | Usage typique |
|---|---|---|---|
kubectl create -f | Déclaratif ponctuel | Non — erreur AlreadyExists | Création initiale, scripts simples |
kubectl apply -f | Déclaratif | Oui — répond unchanged | Gestion continue de l’état désiré |
kubectl replace -f | Déclaratif destructif | Non — remplace l’objet entier | Cas particuliers |
kubectl edit, kubectl scale | Impératif | Non — modifie l’objet en place | Expérimentation, urgence |
Code YAML — l’anatomie d’un manifeste
# deployment.yaml — un manifeste : la déclaration complète d'un objet
apiVersion: apps/v1 # le groupe/version d'API qui définit l'objet
kind: Deployment # le type d'objet déclaré
metadata:
name: hello # l'identité : nom, namespace, labels…
spec: # l'état désiré — le contrat (chapitre 1-2)
replicas: 3
selector:
matchLabels:
app: hello
template: # le modèle des pods à créer
metadata:
labels:
app: hello
spec:
containers:
- name: web
image: nginx:1.27
Code kubectl — le cycle de vie d’un apply
# Enregistrer l'état désiré pour la première fois
kubectl apply -f deployment.yaml
# deployment.apps/hello created
# Après modification du fichier (replicas: 3 → 4) :
# mesurer l'écart AVANT d'enregistrer — rien n'est modifié
kubectl diff -f deployment.yaml
# - replicas: 3
# + replicas: 4
# Valider sans enregistrer : toutes les vérifications, aucune écriture
kubectl apply -f deployment.yaml --dry-run=server
# deployment.apps/hello configured (server dry run)
# Enregistrer la nouvelle déclaration
kubectl apply -f deployment.yaml
# deployment.apps/hello configured ← l'état désiré a changé, la boucle converge
Piège courant : «
kubectl applyremplace l’objet entier par le contenu du fichier » est inexact — l’apply fusionne. Si un autre acteur (un autoscaler, par exemple) gère le champreplicas, un fichier qui ne mentionne pas ce champ ne l’écrasera pas. C’estkubectl replacequi substitue l’objet entier ; confondre les deux conduit à perdre des réglages gérés par d’autres boucles.
etcd, le magasin de l’état désiré
L’idée en une phrase
etcd est la base de données clé-valeur distribuée où l’API server persiste tous les objets du cluster : c’est la source de vérité de l’état désiré. Toute la réconciliation s’y rapporte — les boucles comparent l’état réel à ce qui est écrit dans etcd, jamais l’inverse — mais aucun composant n’y accède directement : seul l’API server lit et écrit dans etcd.
Analogie : Considérons un cadastre. Sur le terrain, les clôtures peuvent être déplacées ou tomber ; en cas de litige, c’est le registre qui fait foi, pas la clôture. Toute mutation passe par un acte enregistré auprès d’un office unique, et les géomètres travaillent à partir du registre. etcd est le cadastre du cluster, l’API server l’office d’enregistrement, et l’état réel le terrain.
Points clés
- etcd est un magasin clé-valeur : chaque objet du cluster est sérialisé sous une clé de la forme
/registry/deployments/default/hello. Pas de tables ni de requêtes relationnelles — des clés, des valeurs, et des observations de changements. - etcd est distribué : un cluster de 3 ou 5 membres s’accorde par le protocole de consensus Raft. Une écriture n’est validée qu’une fois répliquée sur la majorité (le quorum) ; un cluster de 3 membres tolère donc la panne d’1 membre.
- Seul l’API server accède à etcd. Les contrôleurs, le scheduler et les kubelets passent tous par l’API : ce point de passage unique applique l’authentification, la validation et le contrôle d’admission.
- Chaque objet persisté porte un resourceVersion, compteur monotone issu d’etcd. Il permet de détecter les modifications concurrentes et alimente le mécanisme de watch (chapitre 13-14), par lequel les boucles observent l’état sans interroger en permanence.
- Perdre etcd, c’est perdre l’accès à l’état désiré : les conteneurs en cours d’exécution continuent de tourner (et le kubelet les redémarre localement si besoin), mais plus aucune création ni réconciliation n’est possible. D’où la sauvegarde régulière par instantané (
etcdctl snapshot save).
Exemple concret
Un cluster etcd compte 3 membres. À 14 h 02, le membre 3 tombe : le quorum (2 sur 3) est conservé, les lectures et écritures continuent. À 14 h 03, un kubectl apply est validé après réplication de l’écriture sur les membres 1 et 2. À 14 h 10, le membre 3 revient et rattrape l’historique Raft manquant.
Variante : les membres 2 et 3 tombent. Le quorum est perdu : l’API server ne peut plus écrire — les apply sont refusés, les pods supprimés ne sont plus remplacés. L’état réel, lui, persiste : les conteneurs déjà lancés continuent de servir le trafic. Le cluster ne s’effondre pas ; il cesse de converger.
Dimensionner un cluster etcd
| Membres | Quorum | Pannes tolérées | Usage |
|---|---|---|---|
| 1 | 1 | 0 | Poste de travail, lab (minikube, kind) |
| 3 | 2 | 1 | Production standard |
| 5 | 3 | 2 | Production critique |
Code kubectl et etcdctl — observer le magasin
# Chaque objet persisté porte un resourceVersion issu d'etcd
kubectl get deployment hello -o yaml | grep resourceVersion
# resourceVersion: "4821" ← compteur monotone, base des watches (chapitre 13-14)
# Vue interne, depuis un membre etcd : les objets vivent sous /registry
etcdctl get /registry/deployments/default/hello --keys-only
# /registry/deployments/default/hello
# Sauvegarder l'état désiré du cluster entier — un seul fichier
etcdctl snapshot save /backup/etcd-2026-06-07.db
# Snapshot saved at /backup/etcd-2026-06-07.db
Piège courant : « etcd ne stocke que l’état désiré » est inexact — etcd persiste les objets entiers,
specetstatuscompris. La distinction entre contrat et constat est logique, pas physique : laspecfait foi parce que les boucles convergent vers elle, tandis que lestatusn’est qu’un constat consigné, réécrit au fil des observations. Qualifier etcd de « magasin de l’état désiré » décrit son rôle dans la réconciliation, pas le découpage de son contenu.