Aller au contenu
Conteneurs & Orchestration medium

kubectl label et annotate : organiser et documenter vos ressources Kubernetes

17 min de lecture

logo kubernetes

Labels et annotations sont les deux systèmes de métadonnées de Kubernetes, mais ils ne servent pas du tout à la même chose. Les labels sont des paires clé-valeur que Kubernetes utilise pour sélectionner et router : un Service trouve ses pods via un label selector, un Deployment gère ses réplicas par labels. Les annotations sont du texte libre pour documenter et outiller : référence d'incident, config Ingress, scrape Prometheus. Ce guide vous montre comment les gérer efficacement avec kubectl label et kubectl annotate.

  • La différence entre labels et annotations, et quand utiliser l'un ou l'autre
  • Ajouter, modifier et supprimer des labels et annotations sur n'importe quelle ressource
  • Filtrer des ressources avec les label selectors (-l)
  • Adopter les labels recommandés par Kubernetes (app.kubernetes.io/*)
  • Exploiter les annotations pour le tooling (Ingress, Prometheus, Cert-Manager…)
  • Appliquer en masse des métadonnées sur plusieurs ressources

Avant de taguer quoi que ce soit, posez-vous cette question : Kubernetes ou un autre outil devra-t-il sélectionner des ressources avec cette information ?

CritèreLabelAnnotation
ButIdentifier, sélectionner, grouperDocumenter, configurer des outils
Utilisé par les selectors (-l)✅ Oui❌ Non
Utilisé par les Services/Deployments✅ Oui (routing, réplicas)❌ Non
Longueur valeur63 caractères maxPas de limite pratique
Caractères autorisésAlphanumériques, -, _, .Texte libre
Exemple typiqueenv=prod, app=api, tier=backendowner=equipe-platform, prometheus.io/scrape=true

Les labels sont le mécanisme fondamental de Kubernetes pour lier les ressources entre elles. Un Service trouve ses pods par label selector. Un Deployment identifie ses réplicas par labels. Sans labels, Kubernetes ne peut pas fonctionner.

La commande accepte n'importe quel type de ressource (pod, deploy, node, namespace) et autant de paires clé-valeur que vous voulez sur une seule ligne.

Fenêtre de terminal
kubectl label <type> <nom> <clé>=<valeur> [options]

Les quatre opérations ci-dessous couvrent la quasi-totalité des besoins : ajouter, modifier, supprimer et appliquer en masse. Chacune renvoie une ligne de confirmation qui nomme la ressource touchée, ce qui vous permet de vérifier que la commande a bien visé le bon objet avant d'aller plus loin.

Sans option particulière, kubectl label n'écrit que si la clé est absente de la ressource.

Fenêtre de terminal
kubectl label pod api-server-7d4b8c env=production
pod/api-server-7d4b8c labeled

Par défaut, kubectl refuse d'écraser un label existant. Ajoutez --overwrite :

Fenêtre de terminal
kubectl label pod api-server-7d4b8c env=staging --overwrite

Ajoutez un - (tiret) après le nom de la clé :

Fenêtre de terminal
kubectl label pod api-server-7d4b8c env-
pod/api-server-7d4b8c unlabeled

Trois façons de désigner une cible multiple : plusieurs noms à la suite, le drapeau --all qui prend tout le namespace, ou un sélecteur -l qui ne retient que les ressources déjà porteuses d'un label donné.

Fenêtre de terminal
# Par nom
kubectl label pods api-server-7d4b8c worker-9f2a1e tier=backend
# Tous les pods d'un namespace
kubectl label pods --all env=staging -n dev
# Par sélecteur (tous les pods de l'app api)
kubectl label pods -l app=api version=v2.1 -n prod

Les label selectors sont l'un des outils les plus puissants de kubectl. Ils fonctionnent partout : get, delete, logs, exec

Fenêtre de terminal
# Égalité
kubectl get pods -l env=production
# Inégalité
kubectl get pods -l env!=staging
# Appartenance (in)
kubectl get pods -l 'env in (production, staging)'
# Exclusion (notin)
kubectl get pods -l 'env notin (dev, test)'
# Existence (le label existe, quelle que soit la valeur)
kubectl get pods -l env
# Non-existence
kubectl get pods -l '!env'
# Combinaison (ET logique : toutes les conditions doivent être vraies)
kubectl get pods -l app=api,env=production,tier=backend

Kubernetes définit un ensemble de labels standardisés sous le préfixe app.kubernetes.io/. Les adopter garantit la compatibilité avec les outils de l'écosystème (Helm, ArgoCD, Lens, Prometheus…).

LabelRôleExemple
app.kubernetes.io/nameNom de l'applicationapi-gateway
app.kubernetes.io/versionVersion de l'application2.4.1
app.kubernetes.io/componentComposant dans l'architecturefrontend, backend, database
app.kubernetes.io/part-ofApplication parenteboutique-en-ligne
app.kubernetes.io/managed-byOutil de déploiementhelm, argocd, kubectl
app.kubernetes.io/instanceInstance uniqueapi-gateway-prod

Exemple concret, un Deployment avec labels recommandés :

apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
labels:
app.kubernetes.io/name: api-gateway
app.kubernetes.io/version: "2.4.1"
app.kubernetes.io/component: backend
app.kubernetes.io/part-of: boutique-en-ligne
app.kubernetes.io/managed-by: helm

Les labels ont des règles strictes, les dépasser provoque une erreur :

ContrainteRègle
Clé (sans préfixe)1-63 caractères, alphanumérique, -, _, .
Préfixe (optionnel)Sous-domaine DNS, max 253 caractères, séparé par /
Valeur0-63 caractères, alphanumérique, -, _, ., doit commencer et finir par un alphanumérique
Fenêtre de terminal
# ✅ Valide
kubectl label pod mon-pod app.kubernetes.io/name=api-gateway
# ❌ Invalide : valeur trop longue ou caractères spéciaux
kubectl label pod mon-pod desc="Mon application de production avec beaucoup de détails"
# → error: invalid label value

Les annotations stockent des informations textuelles libres sur une ressource. Kubernetes ne les utilise pas pour la sélection, mais de nombreux outils s'en servent pour leur configuration.

La syntaxe est la copie de celle de kubectl label, à une nuance près : la valeur peut contenir des espaces, des accents et de la ponctuation, à condition de la placer entre guillemets pour le shell.

Fenêtre de terminal
kubectl annotate <type> <nom> <clé>=<valeur> [options]

Les mêmes quatre gestes qu'avec les labels, avec les mêmes drapeaux : --overwrite pour remplacer, le tiret suffixe pour supprimer. La différence apparaît à la lecture : les annotations n'apparaissent pas dans kubectl get, il faut aller les chercher avec describe ou jsonpath.

Une adresse de contact est le cas le plus courant : elle reste attachée aux métadonnées de l'objet et s'affiche dans kubectl describe.

Fenêtre de terminal
kubectl annotate pod api-server-7d4b8c owner="equipe-platform@example.com"
pod/api-server-7d4b8c annotated

Comme pour les labels, l'écrasement d'une clé déjà présente échoue tant que vous n'ajoutez pas --overwrite.

Fenêtre de terminal
kubectl annotate pod api-server-7d4b8c owner="equipe-sre@example.com" --overwrite

Le tiret suffixe derrière la clé retire l'annotation ; l'opération est immédiate et sans confirmation.

Fenêtre de terminal
kubectl annotate pod api-server-7d4b8c owner-

Le drapeau --all combiné à -n couvre tout un namespace en une commande, ce qui est pratique pour poser un motif de changement commun sur une vague de déploiements.

Fenêtre de terminal
# Par nom
kubectl annotate pods api-server-7d4b8c worker-9f2a1e support-team="ops@example.com"
# Tous les deployments d'un namespace
kubectl annotate deploy --all -n prod change-cause="Mise à jour sécurité 2026-02-27"

kubectl get n'affiche pas les annotations, il n'existe pas d'équivalent de --show-labels. Il faut passer par jsonpath, un langage d'extraction intégré à kubectl qui pioche un champ précis dans l'objet JSON renvoyé par l'API.

Fenêtre de terminal
# Toutes les annotations
kubectl get pod api-server-7d4b8c -o jsonpath='{.metadata.annotations}' | python3 -m json.tool
# Une annotation spécifique
kubectl get pod api-server-7d4b8c -o jsonpath='{.metadata.annotations.owner}'

Annotations utilisées par l'écosystème Kubernetes

Section intitulée « Annotations utilisées par l'écosystème Kubernetes »

Contrairement aux labels que vous définissez librement, certaines annotations ont un sens particulier pour des composants Kubernetes ou des outils tiers :

AnnotationOutilRôle
kubernetes.io/change-causekubectl rolloutMotif du changement affiché dans rollout history
nginx.ingress.kubernetes.io/rewrite-targetIngress NGINXRéécriture d'URL
cert-manager.io/cluster-issuerCert-ManagerÉmetteur de certificat TLS
prometheus.io/scrapePrometheusActive le scraping de métriques
prometheus.io/portPrometheusPort à scraper
argocd.argoproj.io/sync-waveArgoCDOrdre de synchronisation

L'annotation kubernetes.io/change-cause permet de documenter pourquoi un Deployment a été modifié. Elle apparaît dans kubectl rollout history :

  1. Annotez le Deployment avec la raison du changement

    Fenêtre de terminal
    kubectl annotate deploy api-gateway -n prod \
    kubernetes.io/change-cause="Mise à jour nginx 1.27, correctif CVE-2026-1234"
  2. Vérifiez dans l'historique

    Fenêtre de terminal
    kubectl rollout history deploy/api-gateway -n prod
    REVISION CHANGE-CAUSE
    1 Déploiement initial
    2 Mise à jour nginx 1.27, correctif CVE-2026-1234

En production, les métadonnées se posent rarement une ressource à la fois. Vous héritez d'un namespace où la moitié des pods n'a pas de label env, ou vous devez renommer une clé sur toute une application. Les recettes ci-dessous combinent kubectl get et kubectl label via un pipe, et s'appliquent immédiatement au cluster. Ajoutez --dry-run=server à la commande de labellisation pour voir le résultat sans rien écrire dans etcd, la base de données du cluster.

Le sélecteur -l '!env' isole les ressources dépourvues de la clé, et xargs rejoue la commande de labellisation sur chaque nom retourné.

Fenêtre de terminal
# Trouver les pods sans label env
kubectl get pods -n prod -l '!env' --no-headers -o custom-columns=":metadata.name" | \
xargs -I{} kubectl label pod {} env=production -n prod

L'opération est irréversible : une fois la clé retirée, sa valeur n'est nulle part, et tout Service dont le selector s'appuyait dessus perd instantanément ses endpoints.

Fenêtre de terminal
kubectl label pods --all -n dev legacy-

Kubernetes ne supporte pas le renommage direct. Il faut copier puis supprimer :

Fenêtre de terminal
# Copier la valeur de l'ancien label vers le nouveau
for pod in $(kubectl get pods -n prod -l app=api -o name); do
val=$(kubectl get "$pod" -n prod -o jsonpath='{.metadata.labels.app}')
kubectl label "$pod" -n prod "app.kubernetes.io/name=$val"
done
# Supprimer l'ancien label
kubectl label pods -l app=api -n prod app-

En cas d'incident, annotez les ressources modifiées pour la post-mortem :

Fenêtre de terminal
kubectl annotate deploy api-gateway -n prod \
incident-ref="INC-2026-0142" \
incident-action="Rollback image vers nginx:1.26" \
incident-by="alice@example.com" \
incident-date="2026-02-27T14:30:00Z"

Un cluster reste lisible tant que les métadonnées suivent une convention écrite. Sans cadre, chaque équipe invente son vocabulaire (env, environment, stage) et les sélecteurs cessent de fonctionner d'un namespace à l'autre. Les trois règles qui suivent tiennent en une page et suffisent à éviter la dérive.

Adoptez une convention dès le départ et documentez-la. Voici un exemple :

LabelValeurs possiblesQui le pose
envdev, staging, prodCI/CD
tierfrontend, backend, database, cacheManifest
app.kubernetes.io/nameNom de l'applicationHelm / manifest
app.kubernetes.io/versionSemverCI/CD
teamplatform, sre, produitManifest

En cas de doute, demandez-vous si un contrôleur doit un jour faire une requête sur cette information.

  • Label = ce qui sert à sélectionner (Services, Deployments, NetworkPolicies, monitoring)
  • Annotation = ce qui sert à documenter ou configurer un outil (Ingress, Cert-Manager, Prometheus)
  • Ne mettez jamais d'information longue ou changeante dans un label (URL, description, timestamp)

Plus il y a de labels, plus les selectors deviennent complexes. 5 à 8 labels par ressource est un maximum raisonnable. Au-delà, regroupez via des annotations ou des ConfigMaps de documentation.

Les erreurs de labels et d'annotations se ressemblent toutes : kubectl refuse d'écrire, ou bien il écrit mais rien ne se passe côté cluster. Le tableau associe chaque message d'erreur exact à sa cause. Retenez surtout les deux dernières lignes : quand une métadonnée disparaît sans explication, le coupable est presque toujours un outil GitOps qui resynchronise l'état depuis Git.

SymptômeCause probableSolution
error: invalid label valueValeur > 63 caractères ou caractères spéciauxRaccourcissez ou utilisez une annotation à la place
error: 'X' already has a valueLe label existe déjà sur la ressourceAjoutez --overwrite
error: 'X' already has a value (annotate)L'annotation existe déjàAjoutez --overwrite
-l ne retourne rienMauvais namespace ou label inexistantVérifiez avec kubectl get <type> --show-labels -n <ns>
Service ne route pas vers les podsLabels du Service selector ≠ labels des podsComparez kubectl get svc <nom> -o jsonpath='{.spec.selector}' avec les labels des pods
invalid label keyPréfixe DNS invalide ou clé trop longueVérifiez : clé max 63 chars, préfixe max 253 chars, format DNS
Annotations perdues après replacekubectl replace remplace l'objet entierUtilisez kubectl annotate ou kubectl apply -f à la place
Labels supprimés par ArgoCD/FluxL'outil GitOps resynchronise depuis GitAjoutez les labels dans le manifest Git, pas via kubectl label
  • Labels = sélection et routage (Services, Deployments, NetworkPolicies les utilisent pour trouver les bons pods).
  • Annotations = documentation et configuration d'outils (Ingress, Prometheus, Cert-Manager, traçabilité).
  • La syntaxe est identique : kubectl label et kubectl annotate avec --overwrite pour modifier, - pour supprimer.
  • Adoptez les labels app.kubernetes.io/*, ils sont le standard de l'écosystème (Helm, ArgoCD, Lens).
  • Les labels ont des contraintes strictes (63 chars, alphanumériques), si ça ne rentre pas, c'est probablement une annotation.
  • Les label selectors (-l) supportent l'égalité, l'inégalité, in, notin et le test d'existence.
  • En prod, documentez vos conventions de labels dans un document partagé par toutes les équipes.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn