Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

Labels et annotations Kubernetes : kubectl label et annotate

Par mis à jour le

Améliorer cette page

Logo Kubernetes

Un label est une étiquette clé-valeur qui sert à sélectionner des objets ; une annotation est une note qui sert à les documenter. Vous avez déjà croisé les deux sans les nommer : le sélecteur d'un ReplicaSet retrouve ses Pods par leurs labels, et la leçon Rolling Updates et Rollbacks a posé l'annotation kubernetes.io/change-cause. Cette leçon vous apprend à les manipuler avec kubectl label et kubectl annotate, puis à filtrer avec -l. Elle prépare directement la leçon suivante : un Service trouve ses Pods exactement de cette façon.

Prérequis : les leçons Pods, Deployments et ReplicaSets, et un cluster kind avec kubectl configuré.

  • Distinguer un label d'une annotation, et choisir le bon des deux
  • Ajouter, modifier et retirer un label avec kubectl label
  • Filtrer des ressources avec un sélecteur de labels (-l)
  • Comprendre pourquoi un label posé à la main sur un Pod disparaît avec lui
  • Documenter un objet avec kubectl annotate et relire ses annotations

La question qui tranche tient en une ligne : Kubernetes ou un outil devra-t-il sélectionner des objets avec cette information ? Si oui, c'est un label, court et contraint, que les sélecteurs savent lire. Si non, c'est une annotation, du texte libre que personne ne filtre mais que tout le monde peut lire. Les deux vivent au même endroit, dans le bloc metadata de l'objet.

CritèreLabelAnnotation
RôleIdentifier, regrouper, sélectionnerDocumenter, configurer un outil
Lu par un sélecteur (-l, Service, ReplicaSet)OuiNon
Taille de la valeur63 caractères au plusToutes les annotations d'un objet : 256 Kio au total
Caractères de la valeurLettres, chiffres, -, _, .Texte libre
Exempleapp=web, env=productionowner=equipe-web@exemple.fr, une URL de runbook

Une information longue, changeante ou destinée aux humains (adresse de contact, lien, motif d'un changement) est donc une annotation. Un critère de tri (application, environnement, rôle) est un label.

kubectl label <type> <nom> <clé>=<valeur> écrit un label sur n'importe quel objet : Pod, Deployment, nœud. Les exemples de cette leçon tournent sur deux Deployments, web (3 réplicas) et api (2 réplicas), créés avec kubectl create deployment. Leurs Pods portent déjà le label app, que kubectl create deployment écrit dans le modèle de Pod, et un label pod-template-hash, posé par le ReplicaSet.

Sans option, la commande ajoute la clé si elle est absente de l'objet et répond par une ligne qui nomme la ressource touchée. Remplacez le nom du Pod par l'un des vôtres, lu avec kubectl get pods.

Fenêtre de terminal
kubectl label pod web-5c4449bd5f-cg6vq env=production
pod/web-5c4449bd5f-cg6vq labeled

Relancer la commande avec une autre valeur échoue : kubectl refuse d'écraser un label par accident, et le message dit quelle valeur est en place.

Fenêtre de terminal
kubectl label pod web-5c4449bd5f-cg6vq env=staging
error: 'env' already has a value (production), and --overwrite is false

L'option --overwrite lève ce garde-fou. C'est voulu : remplacer une valeur peut faire sortir l'objet d'un sélecteur, donc changer ce que fait le cluster.

Fenêtre de terminal
kubectl label pod web-5c4449bd5f-cg6vq env=staging --overwrite

Un tiret collé derrière la clé retire le label. Ce n'est pas une faute de frappe, c'est la syntaxe de suppression, la même que pour une annotation.

Fenêtre de terminal
kubectl label pod web-5c4449bd5f-cg6vq env-
pod/web-5c4449bd5f-cg6vq unlabeled

Retirer une clé absente n'est pas une erreur : kubectl répond label "env" not found. puis not labeled, et sort en succès. Un script qui retire un label n'a donc pas besoin de vérifier sa présence avant.

La commande accepte plusieurs noms à la suite, le drapeau --all pour toutes les ressources du type dans l'espace de noms courant (le namespace, étudié dans la leçon Namespaces), ou un sélecteur -l qui ne retient que les objets déjà porteurs d'un label.

Fenêtre de terminal
kubectl label pods -l app=web tier=frontend
kubectl label pods -l app=api tier=backend
pod/web-5c4449bd5f-cg6vq labeled
pod/web-5c4449bd5f-mk46g labeled
pod/web-5c4449bd5f-sl8vd labeled
pod/api-7c4f6c8597-t8qf6 labeled
pod/api-7c4f6c8597-tdg7h labeled

Avant une modification en masse, ajoutez --dry-run=server : l'API server valide la demande et kubectl liste les objets visés, suffixés de (server dry run), sans rien modifier.

L'option -l filtre n'importe quelle commande kubectl get, delete ou logs sur les labels des objets. C'est le geste le plus utile de la leçon, parce que c'est exactement ce que fait un Service : il ne connaît pas ses Pods par leur nom, il les retrouve par un sélecteur d'égalité comme app=web. Le ReplicaSet fonctionne de la même façon. Pour cette section, deux des cinq Pods portent un environnement, env=production sur cg6vq et env=staging sur mk46g :

Fenêtre de terminal
kubectl get pods -l app=web,env=production
NAME READY STATUS RESTARTS AGE
web-5c4449bd5f-cg6vq 1/1 Running 0 23s

La virgule se lit « et » : toutes les conditions doivent être vraies. Le tableau donne les autres formes ; mettez entre apostrophes celles qui contiennent des parenthèses, des espaces ou un !, pour que le shell ne les interprète pas.

SélecteurRetient les objets…Résultat mesuré sur nos 5 Pods
-l env=productiondont env vaut production1 Pod
-l env!=stagingdont env ne vaut pas staging, y compris sans env4 Pods
-l 'env in (production, staging)'dont env vaut l'une des valeurs2 Pods
-l 'env notin (staging)'dont env ne vaut aucune de ces valeurs, y compris sans env4 Pods
-l envqui portent la clé env, quelle que soit sa valeur2 Pods
-l '!env'qui ne portent pas la clé env3 Pods

Le piège est dans la deuxième ligne : != retient aussi les objets qui n'ont pas la clé. Les deux Pods api sortent alors qu'ils n'ont aucun label env. Pour ne viser que les objets qui portent la clé, combinez les deux conditions : -l env,env!=staging.

Le sélecteur sert aussi à modifier en masse. Pour poser env=dev sur tous les Pods qui n'ont pas encore d'environnement, une seule commande suffit, sans boucle ni xargs :

Fenêtre de terminal
kubectl label pods -l '!env' env=dev

Par défaut, kubectl get n'affiche aucun label. L'option --show-labels les ajoute tous dans une colonne LABELS ; l'option -L en extrait certains, une colonne par clé, plus lisible dès que les objets en portent beaucoup. Après la commande précédente, chaque Pod a son environnement :

Fenêtre de terminal
kubectl get pods -L env
NAME READY STATUS RESTARTS AGE ENV
api-7c4f6c8597-t8qf6 1/1 Running 0 23s dev
api-7c4f6c8597-tdg7h 1/1 Running 0 23s dev
web-5c4449bd5f-cg6vq 1/1 Running 0 23s production
web-5c4449bd5f-mk46g 1/1 Running 0 23s staging
web-5c4449bd5f-sl8vd 1/1 Running 0 23s dev

Plusieurs clés se séparent par une virgule : -L app,env,tier affiche trois colonnes. Une cellule vide signale un objet qui ne porte pas la clé.

Un label posé avec kubectl label vit sur un objet précis, et disparaît avec lui. Deux expériences sur le cluster le montrent, et elles disent où un label durable doit être écrit.

Première expérience : labelliser le Deployment ne labellise pas ses Pods. Après kubectl label deployment web env=production, kubectl get deploy --show-labels affiche bien app=web,env=production sur le Deployment, mais aucun Pod n'a changé. Les Pods reçoivent les labels du modèle de Pod (spec.template.metadata.labels), pas ceux du Deployment.

Seconde expérience : retirer le label app d'un Pod géré. La sortie ne garde que les Pods web.

Fenêtre de terminal
kubectl label pod web-5c4449bd5f-mk46g app-
kubectl get pods -L app,env
NAME READY STATUS RESTARTS AGE APP ENV
web-5c4449bd5f-cg6vq 1/1 Running 0 28s web production
web-5c4449bd5f-mk46g 1/1 Running 0 28s staging
web-5c4449bd5f-sl8vd 1/1 Running 0 28s web dev
web-5c4449bd5f-zfrb9 1/1 Running 0 5s web

Le Pod mk46g ne correspond plus au sélecteur app=web : le ReplicaSet ne le compte plus et crée zfrb9 pour revenir à trois. Le nouveau Pod n'a pas de label env, ni de tier, puisqu'il sort du modèle. Retenez la règle qui en découle : un label qui doit durer s'écrit dans le manifeste, dans le modèle de Pod, et kubectl label sur un Pod sert à trier ou à diagnostiquer, jamais à configurer. Le Pod sorti du groupe, lui, continue de tourner : supprimez-le avec kubectl delete pod.

Un label mal formé est refusé au moment de l'écriture, avec un message qui cite l'expression régulière attendue. Les règles viennent de la documentation officielle, Labels and Selectors, et s'appliquent à la clé comme à la valeur.

PartieRègle
Nom de la clé63 caractères au plus, lettres, chiffres, -, _, ., commence et finit par une lettre ou un chiffre
Préfixe (facultatif)un nom de domaine DNS de 253 caractères au plus, suivi de / (app.kubernetes.io/name)
Valeur63 caractères au plus (vide autorisé), mêmes caractères, commence et finit par une lettre ou un chiffre

Les préfixes kubernetes.io/ et k8s.io/ sont réservés aux composants de Kubernetes. Deux refus réels, une valeur avec des espaces puis une valeur trop longue :

Fenêtre de terminal
kubectl label pod web-5c4449bd5f-cg6vq "desc=Mon application de production"
kubectl label pod web-5c4449bd5f-cg6vq description=une-valeur-beaucoup-trop-longue-pour-tenir-dans-un-label-kubernetes-valide
error: invalid label value: "desc=Mon application de production": a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (...)
error: invalid label value: "description=une-valeur-beaucoup-trop-longue-pour-tenir-dans-un-label-kubernetes-valide": must be no more than 63 bytes

Si l'information ne tient pas dans ces règles, c'est le signe qu'elle relève d'une annotation.

Kubernetes publie une liste de labels recommandés, tous sous le préfixe app.kubernetes.io/. Les adopter donne un vocabulaire commun à vos équipes et aux outils qui savent les lire, comme Helm ou les tableaux de bord : env, environment et stage cessent de coexister pour dire la même chose.

LabelRôleExemple
app.kubernetes.io/nameNom de l'applicationboutique
app.kubernetes.io/instanceInstance précise de l'applicationboutique-prod
app.kubernetes.io/versionVersion de l'application2.4.1
app.kubernetes.io/componentRôle dans l'architecturefrontend, database
app.kubernetes.io/part-ofApplication d'ensemblesite-marchand
app.kubernetes.io/managed-byOutil qui gère l'objethelm, kubectl

Conformément à la règle établie plus haut, ces labels s'écrivent dans le manifeste, sur le Deployment et dans son modèle de Pod. Notez les guillemets autour de la version : sans eux, YAML lit une valeur comme 1.10 comme un nombre, et kubectl rejette le fichier avec cannot unmarshal number into Go struct field ObjectMeta.metadata.labels of type string.

boutique.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: boutique
labels:
app.kubernetes.io/name: boutique
app.kubernetes.io/version: "2.4.1"
app.kubernetes.io/component: frontend
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: boutique
template:
metadata:
labels:
app.kubernetes.io/name: boutique
app.kubernetes.io/version: "2.4.1"
app.kubernetes.io/component: frontend
spec:
containers:
- name: nginx
image: nginx:1.30@sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb

Après kubectl apply -f boutique.yaml, kubectl get pods -l app.kubernetes.io/name=boutique --show-labels montre les trois labels sur chaque Pod, suivis du pod-template-hash ajouté par le ReplicaSet.

Le sélecteur ne reprend que le nom, pas la version : comme vous l'avez vu dans la leçon ReplicaSets, il est immuable, et une version qui change à chaque livraison ne peut pas en faire partie.

kubectl annotate s'utilise exactement comme kubectl label : mêmes arguments, même --overwrite, même tiret final pour retirer. Seul le contenu change : la valeur est du texte libre, que vous placez entre guillemets dès qu'elle contient des espaces ou des caractères que le shell interpréterait.

Une adresse de contact et un lien vers une procédure d'exploitation (un runbook) sont les cas les plus courants : la personne d'astreinte les trouve directement sur l'objet. Plusieurs paires peuvent suivre sur la même ligne.

Fenêtre de terminal
kubectl annotate deployment web owner="equipe-web@exemple.fr"
kubectl annotate deployment web runbook="https://wiki.exemple.fr/runbooks/web" ticket="INC-2026-0142"
deployment.apps/web annotated
deployment.apps/web annotated

Le refus d'écraser existe aussi, avec un message un peu différent de celui de label. Changer de propriétaire demande donc --overwrite :

Fenêtre de terminal
kubectl annotate deployment web owner="equipe-sre@exemple.fr"
kubectl annotate deployment web owner="equipe-sre@exemple.fr" --overwrite
error: --overwrite is false but found the following declared annotation(s): 'owner' already has a value (equipe-web@exemple.fr)
deployment.apps/web annotated

Une fois l'incident clos, kubectl annotate deployment web ticket- retire l'annotation ticket : le tiret final joue le même rôle qu'avec un label.

kubectl get n'affiche pas les annotations, et il n'existe pas d'équivalent de --show-labels. Deux chemins existent : kubectl describe, qui les liste sous Annotations:, et jsonpath, un langage d'extraction intégré à kubectl qui lit un champ précis de l'objet. Voici l'extrait de describe, relevé avant le retrait de ticket :

Fenêtre de terminal
kubectl describe deployment web
Name: web
(...)
Labels: app=web
env=production
Annotations: deployment.kubernetes.io/revision: 1
owner: equipe-sre@exemple.fr
runbook: https://wiki.exemple.fr/runbooks/web
ticket: INC-2026-0142
Selector: app=web
(...)
Fenêtre de terminal
kubectl get deployment web -o jsonpath='{.metadata.annotations.owner}'
equipe-sre@exemple.fr

Une annotation n'est pas filtrable : kubectl get pods -l owner ne trouve rien, puisque -l ne lit que les labels. C'est aussi pourquoi un Service ne pourra jamais choisir ses Pods par une annotation.

La sortie de describe montre une annotation que vous n'avez pas écrite : deployment.kubernetes.io/revision, le numéro de révision que le contrôleur de Deployment tient à jour et que kubectl rollout history affiche. Les composants de Kubernetes et de nombreux outils se servent ainsi des annotations pour ranger leurs propres informations.

AnnotationQui la poseÀ quoi elle sert
deployment.kubernetes.io/revisionle contrôleur de Deploymentnuméro de la révision courante
kubectl.kubernetes.io/last-applied-configurationkubectl applycopie du dernier manifeste appliqué, pour calculer le prochain changement
kubernetes.io/change-causevousmotif affiché par rollout history, voir Annoter les changements

D'autres outils de l'écosystème, comme cert-manager ou Argo CD, lisent des annotations à leur nom pour régler leur comportement sur un objet. Vous les rencontrerez avec ces outils ; le geste pour les poser reste kubectl annotate ou, mieux, le manifeste.

La taille totale des annotations d'un objet, clés et valeurs comprises, ne peut pas dépasser 256 Kio, soit 262 144 octets. La limite vient de la documentation officielle des annotations, et l'API server l'applique : sur notre cluster 1.37, un objet à 262 144 octets d'annotations est accepté, un octet de plus est refusé.

The ConfigMap "taille" is invalid: metadata.annotations: Too long: may not be more than 262144 bytes

La limite porte sur l'ensemble des annotations, pas sur chacune. Elle laisse une large place à de la documentation, mais pas à des fichiers encodés ni à des journaux : ceux-là appartiennent à un ConfigMap, étudié dans la leçon ConfigMaps, ou à un stockage hors du cluster.

Les erreurs de labels et d'annotations se rangent en deux familles. Dans la première, kubectl refuse d'écrire et le message dit pourquoi. Dans la seconde, l'écriture réussit mais rien ne change dans le cluster, ou le label disparaît : la cause est alors presque toujours un objet recréé depuis un modèle ou un manifeste qui ne le porte pas.

SymptômeCause probableSolution
invalid label valueValeur de plus de 63 caractères, ou espaces et caractères interditsRaccourcir, ou passer en annotation
'env' already has a value (...), and --overwrite is falseLe label existe déjàAjouter --overwrite
--overwrite is false but found the following declared annotation(s)L'annotation existe déjàAjouter --overwrite
-l ne retourne rienLabel absent, faute de frappe, ou objets dans un autre namespaceVérifier avec kubectl get pods --show-labels
Le label posé sur un Pod a disparuLe Pod a été recréé à partir du modèle du DeploymentÉcrire le label dans spec.template.metadata.labels
Un Pod en trop est apparuUn label du sélecteur a été retiré ou modifié sur un PodRemettre le label, ou supprimer le Pod sorti du groupe
kubectl label deployment ne change pas les PodsLes Pods prennent les labels du modèle, pas du DeploymentModifier le modèle de Pod dans le manifeste
  • Un label sert à sélectionner (Service, ReplicaSet, -l) ; une annotation sert à documenter et n'est jamais filtrable.
  • kubectl label et kubectl annotate partagent la syntaxe : --overwrite pour remplacer, tiret final (env-) pour retirer.
  • -l app=web,env=production combine les conditions en « et » ; env!=x retient aussi les objets sans la clé env.
  • --show-labels affiche tous les labels, -L env en fait une colonne ; les annotations se lisent avec describe ou jsonpath.
  • Un label posé à la main sur un Pod disparaît quand le Pod est recréé : un label durable s'écrit dans le modèle de Pod du manifeste.
  • Retirer d'un Pod un label du sélecteur le sort du groupe : le ReplicaSet crée un remplaçant.
  • Valeur de label : 63 caractères au plus ; annotations d'un objet : 256 Kio au total.

Six questions pour vérifier les gestes de la leçon : poser et retirer un label, lire un sélecteur comme le fera un Service, savoir où un label durable doit s'écrire, et choisir entre label et annotation.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

6 questions
5 min.
80% requis

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

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn