Aller au contenu
Conteneurs & Orchestration medium

Gérer les dépréciations d'API Kubernetes

21 min de lecture

logo kubernetes

Les API Kubernetes évoluent : certaines versions sont dépréciées puis supprimées lors des mises à jour. Si vos manifests utilisent une API supprimée, vos déploiements échoueront après la mise à jour du cluster. Ce guide vous explique le cycle de vie des API, comment détecter les versions obsolètes, et comment migrer vos ressources avant qu'il ne soit trop tard.

  • Comprendre le cycle de vie des API Kubernetes (alpha → beta → stable)
  • Distinguer une API dépréciée (avertissement) d'une API supprimée (erreur)
  • Détecter les API obsolètes dans vos fichiers YAML, charts Helm et cluster
  • Migrer vos ressources avec kubectl convert et les outils appropriés
  • Automatiser la détection dans votre pipeline CI/CD

Prérequis : savoir écrire des manifests Kubernetes et comprendre le versioning sémantique.

Kubernetes suit un processus rigoureux pour faire évoluer ses API sans casser brutalement les utilisateurs. Chaque nouvelle fonctionnalité passe par plusieurs phases de maturité avant d'être stabilisée, ou abandonnée.

Une API Kubernetes ne disparaît jamais du jour au lendemain : elle traverse cinq états, et le nom de la version (v1alpha1, v1beta1, v1) suffit à savoir où elle en est. La colonne à surveiller dans le tableau ci-dessous est la durée typique : c'est elle qui vous dit combien de temps vous avez pour migrer une fois l'avertissement apparu. Le piège classique consiste à croire qu'une API beta est sûre parce qu'elle est activée par défaut, alors que sa fenêtre de suppression est deux fois plus courte que celle d'une API stable.

┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────────────┐ ┌─────────┐
│ Alpha │ ──▶ │ Beta │ ──▶ │ Stable │ ──▶ │ Deprecated │ ──▶ │ Removed │
│ v1alpha1│ │ v1beta1 │ │ v1 │ │ v1 │ │ - │
└─────────┘ └─────────┘ └─────────┘ └────────────┘ └─────────┘
Expérimental Pré-stable Stable Obsolète Supprimé
PhaseCaractéristiquesDurée typique
Alpha (v1alpha1)Désactivé par défaut, peut changer ou disparaître sans préavisVariable
Beta (v1beta1)Activé par défaut, testé mais peut encore évoluer9+ mois minimum
Stable (v1)Garanti compatible, pas de changements cassantsIndéfini
DeprecatedToujours fonctionnel mais marqué obsolète, warnings dans les logs12+ mois
RemovedSupprimé, les manifests échouent-

La différence entre dépréciation et suppression se voit à l'exécution. Une API dépréciée applique la ressource et écrit un avertissement que personne ne lit dans les journaux de CI. Une API supprimée renvoie une erreur bloquante, et le message ci-dessous est trompeur : il parle de CRD alors que le vrai problème est un apiVersion que le cluster ne sert plus.

Quand une API est supprimée :

Fenêtre de terminal
kubectl apply -f deployment-old.yaml
error: resource mapping not found for name: "my-app" namespace: ""
from "deployment-old.yaml": no matches for kind "Deployment" in version "extensions/v1beta1"
ensure CRDs are installed first

Votre manifest devient inapplicable. Le cluster ne reconnaît plus cette combinaison apiVersion + kind.

Ces suppressions ont cassé des milliers de déploiements. Apprenez de l'histoire pour ne pas la répéter.

Les API extensions/v1beta1 et apps/v1beta1 ont été supprimées après des années de dépréciation. La migration était mécanique, un simple changement d'apiVersion dans quatre lignes de YAML, mais un détail a piégé beaucoup d'équipes : apps/v1 rend le champ spec.selector obligatoire et immuable, alors que extensions/v1beta1 le déduisait des labels du template. Un kubectl apply sur un Deployment existant échouait donc même après correction de l'apiVersion.

RessourceAncienne API (supprimée)Nouvelle API
Deploymentextensions/v1beta1apps/v1
DaemonSetextensions/v1beta1apps/v1
ReplicaSetextensions/v1beta1apps/v1
StatefulSetapps/v1beta1apps/v1

La vague 1.22 a été plus douloureuse que celle de 1.16 parce qu'elle ne se limitait pas à un changement d'apiVersion. L'Ingress en networking.k8s.io/v1 impose une structure différente pour le backend et un champ pathType obligatoire, ce qui casse les charts Helm dont les templates n'ont pas été adaptés. Notez la double ligne du tableau : les manifests écrits avant 1.14 pointaient sur extensions/v1beta1, ceux écrits ensuite sur networking.k8s.io/v1beta1, et les deux sont tombés dans la même version.

RessourceAncienne API (supprimée)Nouvelle API
Ingressextensions/v1beta1networking.k8s.io/v1
Ingressnetworking.k8s.io/v1beta1networking.k8s.io/v1
CertificateSigningRequestcertificates.k8s.io/v1beta1certificates.k8s.io/v1
ValidatingWebhookConfigurationadmissionregistration.k8s.io/v1beta1admissionregistration.k8s.io/v1

Deux des trois lignes du tableau se traitent par un remplacement d'apiVersion. La troisième, PodSecurityPolicy, n'a pas d'équivalent : c'est le seul cas de cette page où l'outillage automatique ne peut rien pour vous, parce que le modèle de sécurité change complètement. Une organisation qui avait construit une douzaine de PSP finement découpées par équipe a dû choisir entre les trois profils standards des Pod Security Standards et l'écriture de politiques dans un moteur d'admission tiers.

RessourceAncienne API (supprimée)Remplacement
PodSecurityPolicypolicy/v1beta1Pod Security Standards (PSS)
PodDisruptionBudgetpolicy/v1beta1policy/v1
EndpointSlicediscovery.k8s.io/v1beta1discovery.k8s.io/v1

Depuis Kubernetes 1.19, kubectl affiche des warnings pour les API dépréciées :

Fenêtre de terminal
kubectl apply -f old-ingress.yaml
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+;
use networking.k8s.io/v1 Ingress
ingress.extensions/my-ingress created

Limitation : Vous ne voyez le warning qu'au moment de l'apply. Pas pratique pour auditer tous vos manifests.

Listez les versions d'API supportées par votre cluster :

Fenêtre de terminal
# Toutes les API disponibles
kubectl api-versions
# Vérifier si une API existe
kubectl api-versions | grep networking.k8s.io

Pour voir quelle version est préférée pour une ressource :

Fenêtre de terminal
kubectl api-resources | grep -i ingress

Pluto est un outil CLI dédié à la détection des API obsolètes. Contrairement aux deux méthodes précédentes, il travaille sur des fichiers, ce qui permet de l'exécuter avant tout contact avec un cluster, donc dans une pull request. Il embarque sa propre base de versions Kubernetes et sait aussi lire les releases Helm stockées dans le cluster.

  1. Installer Pluto

    Le projet publie un fichier checksums.txt à côté de chaque archive. Vérifiez l'empreinte avant d'extraire le binaire : c'est ce contrôle qui distingue une installation reproductible d'un téléchargement aveugle.

    Fenêtre de terminal
    brew install FairwindsOps/tap/pluto

    La vérification doit afficher pluto_5.24.1_linux_amd64.tar.gz: OK. Toute autre sortie signifie que l'archive est corrompue ou altérée, n'extrayez pas.

  2. Scanner un répertoire de manifests

    Fenêtre de terminal
    pluto detect-files -d ./manifests/

    Sortie :

    NAME KIND VERSION REPLACEMENT REMOVED DEPRECATED REPL AVAIL
    my-ingress Ingress extensions/v1beta1 networking.k8s.io/v1 true true true
    restricted PodSecurityPolicy policy/v1beta1 true true false

    La colonne REPL AVAIL est celle qui décide de votre charge de travail : à true, un remplacement existe et la migration se résume à changer l'apiVersion. À false, comme pour la PodSecurityPolicy ci-dessus, il n'y a pas de ressource équivalente et il faut repenser la configuration.

  3. Scanner les releases Helm déployées

    Les charts installés dans le cluster échappent aux scans de fichiers, puisque le YAML rendu n'existe nulle part sur disque. Pluto va le lire dans les secrets de release Helm.

    Fenêtre de terminal
    pluto detect-helm -owide
  4. Cibler une version Kubernetes spécifique

    Par défaut, Pluto compare aux versions de sa base interne. En fixant la version cible, vous obtenez la liste exacte de ce qui cassera lors de la montée de version prévue, sans bruit sur les API encore valides.

    Fenêtre de terminal
    pluto detect-files -d ./manifests/ --target-versions k8s=v1.29.0

kubent prend le problème par l'autre bout : au lieu de lire vos fichiers, il interroge le cluster et énumère les objets réellement stockés dans etcd. C'est le seul moyen de repérer les ressources créées à la main, par un opérateur ou par un ancien pipeline, dont le YAML n'est plus dans aucun dépôt Git.

Le projet ne publie pas de fichier de sommes de contrôle pour ses archives, mais il fournit une image de conteneur. L'épingler par digest garantit que vous exécutez exactement le binaire vérifié :

Fenêtre de terminal
# kubent 0.7.3, image épinglée par digest
docker run --rm \
-v "$HOME/.kube/config:/.kube/config:ro" \
ghcr.io/doitintl/kube-no-trouble@sha256:33016a690ca145963a0689cbe00a8499e1ba4d33c43629f9140d52e1ba698a2b \
--kubeconfig /.kube/config

Sur un poste où kubent est déjà installé, la commande se réduit à kubent. La sortie regroupe les objets par version de Kubernetes qui les supprimera :

>>> Deprecated APIs removed in 1.25 <<<
-----------------------------------------
KIND NAMESPACE NAME API_VERSION
PodSecurityPolicy <cluster> restricted policy/v1beta1

Le plugin kubectl convert transforme les manifests vers une nouvelle API. Ce n'est pas une sous-commande native de kubectl : c'est un binaire séparé que la documentation Kubernetes distribue à part et que kubectl découvre grâce à son nom kubectl-convert. Le projet publie une empreinte SHA-256 à côté de chaque binaire ; le contrôle ci-dessous prend dix secondes et évite d'exécuter un fichier altéré en transit.

  1. Installer le plugin

    Fenêtre de terminal
    K8S_VERSION="$(curl -sSL https://dl.k8s.io/release/stable.txt)"
    BASE="https://dl.k8s.io/release/${K8S_VERSION}/bin/linux/amd64"
    curl -sSLO "${BASE}/kubectl-convert"
    curl -sSLO "${BASE}/kubectl-convert.sha256"
    echo "$(cat kubectl-convert.sha256) kubectl-convert" | sha256sum --check -
    sudo install -m 0755 kubectl-convert /usr/local/bin/kubectl-convert

    La commande de vérification doit afficher kubectl-convert: OK. Contrôlez ensuite que kubectl reconnaît le plugin avec kubectl convert --help.

  2. Convertir un manifest

    Fenêtre de terminal
    kubectl convert -f old-ingress.yaml --output-version networking.k8s.io/v1 > new-ingress.yaml
  3. Vérifier le résultat

    Le fichier converti peut nécessiter des ajustements manuels. Par exemple, l'Ingress v1 exige le champ pathType :

    # Avant (v1beta1) - pas de pathType
    - path: /api
    # Après (v1) - pathType obligatoire
    - path: /api
    pathType: Prefix # ou Exact, ImplementationSpecific

Dès qu'un champ change de forme, comme le backend d'un Ingress qui passe d'une paire de clés plates à un objet imbriqué, la conversion automatique atteint ses limites. Le processus ci-dessous ajoute deux garde-fous que kubectl convert n'offre pas : une sauvegarde de l'objet vivant avant modification, et une lecture du guide de migration officiel, qui documente les champs sans équivalent.

  1. Sauvegarder la ressource actuelle

    Fenêtre de terminal
    kubectl get ingress my-ingress -o yaml > backup-ingress.yaml
  2. Consulter la documentation de migration

    Kubernetes publie des guides de migration pour chaque version majeure :

  3. Adapter le manifest

    Exemple pour Ingress v1beta1 → v1 :

    # Avant
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
    name: my-ingress
    spec:
    rules:
    - host: example.com
    http:
    paths:
    - path: /api
    backend:
    serviceName: api-service
    servicePort: 80
    # Après
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: my-ingress
    spec:
    rules:
    - host: example.com
    http:
    paths:
    - path: /api
    pathType: Prefix # NOUVEAU: obligatoire
    backend:
    service: # NOUVEAU: structure imbriquée
    name: api-service
    port:
    number: 80
  4. Appliquer et valider

    Fenêtre de terminal
    kubectl apply -f new-ingress.yaml
    kubectl describe ingress my-ingress

Le déclencheur pull_request filtré sur manifests/** et charts/** évite de faire tourner le scan à chaque commit de documentation. Deux points de ce workflow méritent attention : la version de Pluto est figée avec vérification d'empreinte, pour qu'une mise à jour amont ne change pas silencieusement le verdict de la CI, et --target-versions désigne la version de cluster que vous visez, pas celle que vous exécutez aujourd'hui.

.github/workflows/api-deprecation.yaml
name: Check Kubernetes API deprecations
on:
pull_request:
paths:
- 'manifests/**'
- 'charts/**'
permissions: {}
jobs:
pluto:
runs-on: ubuntu-24.04
permissions:
contents: read
env:
PLUTO_VERSION: "5.24.1"
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- name: Install Pluto
run: |
base="https://github.com/FairwindsOps/pluto/releases/download/v${PLUTO_VERSION}"
curl -sSLO "${base}/pluto_${PLUTO_VERSION}_linux_amd64.tar.gz"
curl -sSLO "${base}/checksums.txt"
grep "pluto_${PLUTO_VERSION}_linux_amd64.tar.gz" checksums.txt | sha256sum --check -
tar xzf "pluto_${PLUTO_VERSION}_linux_amd64.tar.gz" pluto
sudo install -m 0755 pluto /usr/local/bin/pluto
- name: Check manifests
run: pluto detect-files -d ./manifests/ --target-versions k8s=v1.30.0
- name: Check Helm charts
run: |
for chart in ./charts/*/; do
helm template test "$chart" | pluto detect -
done

Pluto ne se contente pas d'afficher un rapport, il traduit la gravité dans son code de sortie. C'est ce qui permet de bloquer une pull request sans analyser la sortie texte. Un quatrième code existe en plus des trois du tableau : 4 signifie qu'une API supprimée n'a aucun remplacement disponible, le cas de la PodSecurityPolicy. Les options --ignore-deprecations, --ignore-removals et --ignore-unavailable-replacements neutralisent chacune le code correspondant.

CodeSignificationAction CI/CD
0Aucune API obsolèteContinuer
2API dépréciées trouvéesAvertir (optionnel)
3API supprimées trouvéesBloquer le merge

Le piège, dans une étape GitHub Actions, est que le shell tourne avec set -e : si Pluto sort en 3, l'étape s'arrête avant même d'atteindre la ligne qui lit $?. Il faut donc capturer le code dans la même commande.

- name: Check and fail on removed APIs
run: |
exit_code=0
pluto detect-files -d ./manifests/ --target-versions k8s=v1.30.0 || exit_code=$?
if [ "$exit_code" -ge 3 ]; then
echo "::error::API supprimées détectées, migration requise."
exit 1
fi
if [ "$exit_code" -eq 2 ]; then
echo "::warning::API dépréciées détectées."
fi

La logique est la même côté GitLab, avec une différence utile : le format de sortie markdown produit un rapport lisible que vous conservez en artefact. Le when: always est indispensable, sans lui l'artefact disparaît précisément dans le cas qui vous intéresse, celui où le job échoue parce que des API supprimées ont été trouvées.

.gitlab-ci.yml
api-deprecation-check:
stage: validate
image: alpine:3.22
variables:
PLUTO_VERSION: "5.24.1"
before_script:
- apk add --no-cache curl tar
- base="https://github.com/FairwindsOps/pluto/releases/download/v${PLUTO_VERSION}"
- curl -sSLO "${base}/pluto_${PLUTO_VERSION}_linux_amd64.tar.gz"
- curl -sSLO "${base}/checksums.txt"
- grep "pluto_${PLUTO_VERSION}_linux_amd64.tar.gz" checksums.txt | sha256sum -c -
- tar xzf "pluto_${PLUTO_VERSION}_linux_amd64.tar.gz" pluto
- install -m 0755 pluto /usr/local/bin/pluto
script:
- pluto detect-files -d ./manifests/ --target-versions k8s=v1.30.0 -o markdown > deprecation-report.md
artifacts:
paths:
- deprecation-report.md
when: always
allow_failure: false

L'ordre de ces cinq étapes n'est pas négociable, et c'est le point que les équipes inversent le plus souvent : on met à jour le cluster, puis on découvre les manifests cassés. La migration doit précéder la montée de version, parce qu'un manifest écrit dans la nouvelle apiVersion fonctionne déjà sur l'ancien cluster, alors que l'inverse est faux.

  1. Scanner tous les manifests avec Pluto ou kubent
  2. Cibler la version cible : --target-versions k8s=v1.X.0
  3. Migrer et tester en environnement staging
  4. Mettre à jour les charts Helm si vous en utilisez
  5. Mettre à jour le cluster seulement après migration

Scanner uniquement au moment de l'upgrade transforme la montée de version en chantier. Le rythme ci-dessous répartit l'effort : le contrôle en pull request empêche l'arrivée de nouvelles dettes, et le scan mensuel ciblant la version actuelle plus deux vous donne l'avance nécessaire pour migrer sans urgence, puisque Kubernetes publie environ trois versions mineures par an.

FréquenceAction
À chaque PRScanner les manifests modifiés
MensuelScanner tout le repo avec la version K8s actuelle + 2
Avant upgradeRapport complet sur la version cible

Les outils embarquent une base de versions figée au moment de leur compilation : sur une version de Kubernetes récente, ils peuvent ignorer une dépréciation annoncée après leur dernière release. Les trois pages ci-dessous font autorité. La première explique les règles du jeu, la deuxième donne le tableau exhaustif API par API, et la troisième précise l'écart de version toléré entre kubectl, le plan de contrôle et les kubelets.

  • Les API Kubernetes suivent un cycle : alpha → beta → stable → deprecated → removed
  • Une API dépréciée fonctionne encore (avec warnings), une API supprimée casse vos déploiements
  • Kubernetes garantit 12 mois minimum entre dépréciation et suppression pour les API stables
  • Utilisez Pluto ou kubent pour détecter les API obsolètes dans vos manifests et votre cluster
  • kubectl convert migre les manifests simples, mais les changements structurels nécessitent une réécriture manuelle
  • Automatisez la détection dans votre CI/CD pour bloquer les PR avec des API supprimées
  • Scannez avant chaque upgrade de cluster avec la version cible

Dix questions pour vérifier que vous distinguez bien une API dépréciée d'une API supprimée, et que vous savez quel outil sortir selon que la ressource vit dans un fichier ou dans le cluster.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

10 questions
8 min.
70% 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 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