Aller au contenu
English
English
Conteneurs & Orchestration medium

Helm v4 : changements, breaking changes et migration depuis Helm v3

50 min de lecture

logo helm

Cette formation vous a appris Helm 4, et vous rencontrerez du Helm 3. La branche 3 reste massivement déployée et reçoit des correctifs de sécurité jusqu'au 10 février 2027 : prendre un poste, c'est presque toujours hériter de releases posées en v3 et de pipelines écrits pour elles. Ce guide vous donne ce qu'il faut pour reprendre cet existant et le faire basculer : tout ce qui change entre les deux versions, les commandes exactes pour adapter des scripts, la façon de tester la bascule en préproduction et une checklist pour la mener sans incident.

  • Identifier les flags renommés et les corriger (--atomic → --rollback-on-failure)
  • Migrer vos post-renderers vers le système de plugins
  • Comprendre le nouveau comportement de --dry-run et --wait
  • Activer Server-Side Apply (SSA) et gérer les conflits
  • Adapter l'authentification OCI et utiliser les digests
  • Planifier votre migration avec une checklist CI/CD

Helm 3 reste supporté, sur un calendrier que les mainteneurs ont prolongé. Deux dates comptent, et elles ne disent pas la même chose :

Ce qui s'arrêteDateCe que cela implique
Corrections de bogues9 septembre 2026La release finale fut Helm v3.22.0 : plus aucune nouveauté ni correction fonctionnelle.
Correctifs de sécurité10 février 2027Passé cette date, une faille dans Helm v3 ne sera plus corrigée.

La date de sécurité initialement prévue par HIP-0012 était novembre 2026, un an après la sortie de Helm v4. Elle a été repoussée de trois mois pour laisser le temps de migrer, ce qui explique que beaucoup de documentations en circulation annoncent encore l'ancienne. C'est la seconde date qui fixe votre échéance réelle : un poste ou une chaîne d'intégration resté en v3 après février 2027 exécute un binaire qui ne recevra plus de correctif.


Avant de lire le détail, voici une checklist des breaking changes à vérifier dans vos scripts :

Ce qui changev3v4Impact
Rollback automatique--atomic--rollback-on-failureScripts CI/CD
Forcer remplacement--force--force-replaceScripts upgrade
Post-renderer--post-renderer ./script--post-renderer plugin-namePipelines avec kustomize
Dry-run--dry-run (booléen)--dry-run=client|serverTests avant déploiement
Wait--wait (booléen)--wait=hookOnly|watcher|legacy, hookOnly par défautAttente pods ready
Server-Side ApplyOpt-ininstall : activé. upgrade : auto, qui reprend la méthode précédenteConflits ownership
OCI loginURL complète acceptéeDomaine uniquementAuth registries

Avant toute chose, mesurez l'ampleur du travail : une seule commande suffit à lister les endroits concernés. Elle cherche les quatre motifs qui changent, dans les fichiers qui portent en général vos chaînes de déploiement.

Fenêtre de terminal
grep -rn --include="*.yml" --include="*.yaml" --include="*.sh" \
-E "(--atomic|--force[^-]|--post-renderer|--dry-run[^=])" .

Notez les deux négations dans l'expression : --force[^-] évite de compter les --force-replace déjà convertis, et --dry-run[^=] ne retient que les emplois sans valeur, précisément ceux que la v4 interprète différemment.


Les ruptures les plus visibles portent sur la ligne de commande, et elles se manifestent de deux façons très différentes. Un drapeau supprimé provoque une erreur immédiate, unknown flag, donc un échec franc. Un drapeau dont le comportement change, comme --dry-run ou --wait, passe au contraire inaperçu et modifie silencieusement ce que fait votre déploiement. Les seconds méritent bien plus d'attention que les premiers.

Trois drapeaux de helm upgrade sont concernés. Le premier reste accepté mais déprécié, le deuxième a changé de nom, le troisième est nouveau et lié à Server-Side Apply.

Le flag --atomic existe toujours mais est déprécié. Utilisez --rollback-on-failure :

Fenêtre de terminal
helm upgrade --install myapp ./chart \
--atomic \
--wait \
--timeout 5m

Comportement : Si le déploiement échoue (pods non Ready dans le timeout), Helm effectue automatiquement un rollback vers la révision précédente.

Un effet de bord mérite d'être connu avant de basculer : quand --rollback-on-failure est actif, --wait passe automatiquement en mode watcher. Le comportement d'attente change donc en même temps que le nom du drapeau, ce qui peut suffire à modifier la durée d'un déploiement sans que personne ait touché à --timeout. La section consacrée à --wait détaille ce que le mode watcher fait différemment.

Le flag pour forcer le remplacement des ressources a été renommé :

Fenêtre de terminal
helm upgrade myapp ./chart --force

Quand l'utiliser : Forcer le remplacement complet d'une ressource au lieu d'un patch. Utile quand un champ immutable a changé.

Ce drapeau n'est pas l'équivalent renommé d'une option anodine : il supprime et recrée la ressource. Sur un Deployment, cela signifie une interruption de service, le temps que les nouveaux pods démarrent, là où une mise à jour ordinaire fait un remplacement progressif.

Quand le besoin réel est de forcer un redémarrage des pods, la bonne réponse n'est donc pas --force-replace mais une annotation qui change dans le gabarit du pod, souvent une empreinte de la configuration. Kubernetes détecte la modification et déroule un remplacement progressif, sans coupure.

En v4, un nouveau flag gère les conflits Server-Side Apply :

Fenêtre de terminal
helm upgrade myapp ./chart --force-conflicts

Ce flag force l'application même si un autre controller (ArgoCD, Flux, kubectl) a modifié la ressource.


Un post-renderer est un programme qui reçoit les manifestes générés par Helm et les transforme avant leur envoi au cluster ; c'est le point d'accroche habituel de kustomize. C'est le changement de la v4 qui casse le plus de pipelines, parce qu'il ne se contourne pas : le passage par le système de plugins est obligatoire, et il faut donc empaqueter le script existant avant de migrer.

En Helm v3, vous pouviez passer un binaire externe :

Fenêtre de terminal
# v3 : binaire direct (NE FONCTIONNE PLUS en v4)
helm template myapp ./chart --post-renderer ./kustomize-overlay.sh

En Helm v4, les post-renderers passent obligatoirement par le système de plugins :

Fenêtre de terminal
# v4 : plugin installé
helm template myapp ./chart --post-renderer kustomize

La conversion ne touche pas au script lui-même : il continue de lire sur l'entrée standard et d'écrire sur la sortie standard. Ce qui change, c'est son emballage : un répertoire dans le dossier des plugins et un plugin.yaml qui le déclare avec postRenderer: true.

  1. Convertir votre script en plugin Helm

    Créez la structure de plugin :

    Fenêtre de terminal
    mkdir -p ~/.local/share/helm/plugins/my-postrenderer

    Créez plugin.yaml :

    ~/.local/share/helm/plugins/my-postrenderer/plugin.yaml
    name: "my-postrenderer"
    version: "1.0.0"
    usage: "Post-render manifests with custom logic"
    command: "$HELM_PLUGIN_DIR/render.sh"
    postRenderer: true
  2. Déplacer votre script

    Copiez votre script existant :

    Fenêtre de terminal
    cp ./kustomize-overlay.sh ~/.local/share/helm/plugins/my-postrenderer/render.sh
    chmod +x ~/.local/share/helm/plugins/my-postrenderer/render.sh
  3. Vérifier l'installation

    Fenêtre de terminal
    helm plugin list

    Sortie attendue :

    NAME VERSION DESCRIPTION
    my-postrenderer 1.0.0 Post-render manifests with custom logic
  4. Utiliser le plugin

    Fenêtre de terminal
    helm template myapp ./chart --post-renderer my-postrenderer

Un plugin de post-rendu reçoit souvent des paramètres : le dossier de surcharge, le profil d'environnement, un indicateur de mode. Le drapeau --post-renderer-args les lui transmet, et il se répète autant de fois qu'il y a d'arguments plutôt que d'en accepter une liste, ce qui évite toute ambiguïté sur les espaces et les guillemets.

Utilisez --post-renderer-args :

Fenêtre de terminal
helm upgrade --install myapp ./chart \
--post-renderer kustomize \
--post-renderer-args "--enable-helm" \
--post-renderer-args "--load-restrictor=LoadRestrictionsNone"

Le projet Helm ne publie aucun plugin kustomize sous son organisation : il n'y a rien à installer depuis github.com/helm/. Les plugins qui circulent sont des projets tiers, et l'enjeu dépasse le confort. Un post-renderer voit passer l'intégralité de ce que vous déployez, secrets compris : lui accorder la confiance due à un composant officiel est un défaut de chaîne d'approvisionnement, pas une approximation de vocabulaire.

La voie sûre reste celle des étapes ci-dessus : empaqueter votre propre script. Vous savez ce qu'il contient, il ne dépend de personne, et la conversion se limite à un fichier plugin.yaml de quelques lignes.


--dry-run est le drapeau le plus dangereux de cette migration, car il ne provoque aucune erreur : la commande continue de fonctionner, mais pas forcément comme avant. En v3 c'était un booléen ; en v4 il accepte une valeur qui détermine si Helm contacte ou non le cluster. Un pipeline qui croyait valider contre le serveur peut se retrouver à ne valider que localement.

En v3, --dry-run était un booléen. En v4, c'est une option à valeurs :

ValeurComportementConnexion cluster
--dry-run=noneExécution normale (défaut si omis)Oui
--dry-run=clientSimulation côté client uniquementNon
--dry-run=serverSimulation côté serveurOui
--dry-run (sans valeur)Équivalent à --dry-run=clientNon

Recommandation : Utilisez toujours la forme explicite pour éviter les ambiguïtés.

Fenêtre de terminal
# Validation sans cluster (rapide, offline)
helm upgrade --install myapp ./chart --dry-run=client
# Validation avec le cluster (vérifie schémas, RBAC, quotas)
helm upgrade --install myapp ./chart --dry-run=server

Le flag --hide-secret masque les valeurs des Secrets dans la sortie :

Fenêtre de terminal
helm template myapp ./chart --dry-run=client --hide-secret

Le Server-Side Apply est un mécanisme de Kubernetes où c'est l'API server, et non le client, qui fusionne la ressource souhaitée avec celle déjà en place. Chaque champ garde la trace du propriétaire qui l'a défini, ce qui permet au cluster de refuser une modification venant d'un autre gestionnaire. Ce changement est celui qui produit les erreurs les plus déroutantes en migration, surtout si un outil GitOps gère déjà les mêmes ressources.

En v3 : Client-Side Apply, la fusion se fait côté client.

En v4, la réponse dépend de la commande, et c'est le piège de cette migration :

CommandeType du drapeauValeur par défautCe qui se passe
helm installbooléentrueSSA activé : toute nouvelle release passe par le serveur
helm upgradechaîne true|false|autoautoHelm reprend la méthode de la release précédente

Une release créée sous Helm v3 reste donc en client-side après un helm upgrade en v4. C'est exactement le cas de celui qui migre : il lit « SSA par défaut », suppose que sa chaîne bascule, et rien ne change. Le basculement ne se produit qu'à la création d'une nouvelle release, ou s'il le demande explicitement avec --server-side=true.

SSA délègue la logique de merge au serveur Kubernetes, ce qui apporte :

  • Meilleure gestion des conflits : détection si un autre controller a modifié la ressource
  • Ownership tracking : Kubernetes sait qui a créé chaque champ
  • Dry-run serveur : validation plus précise

Si un autre outil (ArgoCD, kubectl, opérateur) a modifié une ressource, vous verrez :

Error: UPGRADE FAILED: cannot patch "myapp" with kind Deployment:
Apply failed with 1 conflict: conflict with "argocd-application-controller"

Solutions :

  1. Forcer l'ownership (si Helm doit prendre le contrôle) :

    Fenêtre de terminal
    helm upgrade myapp ./chart --force-conflicts
  2. Désactiver SSA (temporairement, pour debug) :

    Fenêtre de terminal
    helm upgrade myapp ./chart --server-side=false

Helm n'annonce pas dans sa sortie s'il a appliqué côté client ou côté serveur. La réponse est dans le cluster, portée par les managedFields que Kubernetes attache à chaque ressource : chaque gestionnaire y laisse son nom et le type d'opération effectuée.

Fenêtre de terminal
kubectl get deployment myapp \
-o jsonpath='{range .metadata.managedFields[*]}{.manager}{" "}{.operation}{"\n"}{end}'

La lecture tient en un mot, celui de la colonne opération :

SortieCe que cela signifie
helm ApplyServer-Side Apply : c'est l'API server qui a fusionné
helm UpdateClient-Side Apply : la fusion a eu lieu dans votre terminal

Sur une release installée avec Helm v4, la sortie mesurée est helm Apply, aux côtés de kube-controller-manager Update qui gère les champs que le contrôleur renseigne lui-même. Une release héritée de Helm v3 et reprise par un upgrade en mode auto affichera helm Update : c'est le signal qu'elle n'a pas basculé.


--wait décide si helm upgrade rend la main immédiatement ou attend que les ressources soient prêtes. En v4, ce n'est plus un interrupteur mais un choix de stratégie de surveillance, et la valeur par défaut n'attend que les hooks. Un pipeline qui comptait sur --wait pour bloquer jusqu'au démarrage effectif des pods doit donc être adapté, sous peine de déclarer réussi un déploiement qui ne l'est pas.

En v3, --wait attendait que les ressources soient "Ready" selon une logique interne. En v4, vous choisissez la stratégie :

ValeurComportement
--wait=hookOnlyAttend seulement les hooks (défaut)
--wait=watcherUtilise kstatus pour surveiller l'état réel
--wait=legacyComportement v3 (rétrocompatibilité)

Le mode watcher utilise kstatus qui comprend mieux l'état des ressources Kubernetes :

  • Détecte les CRDs avec des conditions personnalisées
  • Comprend les états intermédiaires (Progressing, Degraded)
  • Gère les ressources non-standard (Argo Rollouts, Knative, etc.)
Fenêtre de terminal
helm upgrade --install myapp ./chart \
--wait=watcher \
--timeout 5m

Le flag --wait-for-jobs reste disponible en v4 et garde son sens : attendre qu'un Job atteigne la complétion, et pas seulement que ses pods soient créés. Il complète --wait plutôt qu'il ne le remplace, l'attente ordinaire ne sachant rien dire d'un Job encore en cours.

Fenêtre de terminal
helm upgrade --install myapp ./chart \
--wait=watcher \
--wait-for-jobs \
--timeout 10m

Helm publie et récupère les charts depuis des registres OCI, les mêmes qui hébergent vos images de conteneurs. Deux points changent en v4 : la commande de connexion devient plus stricte, et l'installation peut viser un digest plutôt qu'un tag. Le premier casse les scripts existants, le second améliore la reproductibilité.

En v4, helm registry login attend uniquement le domaine, pas une URL complète :

Fenêtre de terminal
# Fonctionnait en v3
helm registry login oci://ghcr.io/myorg/charts

Pattern CI/CD recommandé :

Fenêtre de terminal
echo "$REGISTRY_TOKEN" | helm registry login ghcr.io -u "$REGISTRY_USER" --password-stdin

Helm v4 supporte l'installation par digest SHA256 pour des déploiements reproductibles :

Fenêtre de terminal
# Par tag (peut changer si le tag est réécrit)
helm install myapp oci://ghcr.io/myorg/charts/myapp --version 1.2.3
# Par digest (immuable, recommandé pour prod)
helm install myapp oci://ghcr.io/myorg/charts/myapp@sha256:abc123...

Obtenir le digest d'un chart :

Fenêtre de terminal
helm pull oci://ghcr.io/myorg/charts/myapp --version 1.2.3 2>&1 | grep Digest

En production, épinglez par digest. Un tag OCI peut être redéplacé sur un autre contenu sans que sa référence change : deux déploiements successifs du même 1.2.3 peuvent donc installer deux charts différents. Le digest, lui, est une empreinte du contenu et ne peut désigner autre chose. C'est le même raisonnement que pour l'épinglage des images de conteneurs.


La migration se fait sans désinstaller Helm v3 : les deux binaires cohabitent sous des noms différents, ce qui permet de comparer les manifestes générés avant de basculer quoi que ce soit. L'ordre des étapes compte, car l'audit des scripts détermine l'ampleur du travail restant, à commencer par la présence d'un post-renderer à convertir.

  1. Auditer vos scripts

    Cherchez les patterns à mettre à jour :

    Fenêtre de terminal
    # Dans vos repos CI/CD
    grep -rn --include="*.yml" --include="*.yaml" --include="*.sh" \
    -E "(--atomic|--force[^-]|--post-renderer [^-]|--dry-run[^=])" .
  2. Installer Helm v4 en parallèle

    Testez sans remplacer v3. Téléchargez l'archive et le fichier de sommes officiel publié à côté d'elle, vérifiez l'empreinte, et n'extrayez qu'ensuite :

    Fenêtre de terminal
    HELM_VERSION="4.1.0"
    curl -fsSLO "https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz"
    curl -fsSLO "https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz.sha256sum"
    sha256sum --check "helm-v${HELM_VERSION}-linux-amd64.tar.gz.sha256sum"
    # helm-v4.1.0-linux-amd64.tar.gz: OK

    Tant que la vérification ne répond pas OK, n'installez rien. Une archive dépliée directement depuis le réseau ne laisse aucune chance de détecter une substitution :

    Fenêtre de terminal
    tar -xzf "helm-v${HELM_VERSION}-linux-amd64.tar.gz"
    sudo install -m 0755 linux-amd64/helm /usr/local/bin/helm4
    # Tester
    helm4 version
  3. Tester en environnement de dev

    Fenêtre de terminal
    # Comparer les manifests générés
    helm3 template myapp ./chart -f values.yaml > v3-manifests.yaml
    helm4 template myapp ./chart -f values.yaml > v4-manifests.yaml
    diff v3-manifests.yaml v4-manifests.yaml
  4. Migrer les post-renderers

    Si vous utilisez --post-renderer, convertissez en plugin (voir section dédiée).

  5. Adapter les flags dans CI/CD

    Mettez à jour vos pipelines :

    .gitlab-ci.yml
    deploy:
    script:
    # Avant (v3)
    # - helm upgrade --install myapp ./chart --atomic --wait
    # Après (v4)
    - helm upgrade --install myapp ./chart --rollback-on-failure --wait=watcher
  6. Déployer en staging

    Testez le cycle complet :

    • Install → Upgrade → Rollback → Uninstall
  7. Basculer en production

    Une fois validé en staging, mettez à jour Helm et les scripts en production.


Les messages ci-dessous se répartissent en deux familles. Les avertissements de dépréciation sont bénins : la commande s'exécute quand même, et la correction est mécanique. Les conflits Server-Side Apply et les problèmes de détection d'état demandent une décision, car ils révèlent qu'un autre acteur gère les mêmes ressources, ou que l'attente ne portait pas sur ce que vous croyiez.

Ne guettez pas un unknown flag sur les deux premiers : mesuré sur Helm v4.3.0, --atomic et --force restent acceptés. Le seul signe est une ligne d'avertissement, facile à manquer au milieu des journaux d'un agent d'intégration.

SymptômeCauseSolution
Flag --atomic has been deprecatedAncien nom, toujours acceptéRemplacer par --rollback-on-failure
Flag --force has been deprecatedAncien nom, toujours acceptéRemplacer par --force-replace
Apply failed with conflictSSA détecte une modification externeUtiliser --force-conflicts ou coordonner l'ownership
post-renderer plugin not foundPost-renderer non migréConvertir en plugin Helm
Error: login requires exactly one argumentURL au lieu du domaineUtiliser seulement le domaine (ghcr.io)
--dry-run flag needs an argumentSyntaxe v3Utiliser --dry-run=client ou --dry-run=server
Pods non détectés comme ReadyMode wait legacyUtiliser --wait=watcher

Premier réflexe avant tout diagnostic : la sortie indique aussi la version du client Kubernetes embarquée, qui conditionne la compatibilité avec votre cluster.

Fenêtre de terminal
helm version

Sortie attendue (v4) :

version.BuildInfo{Version:"v4.1.0", GitCommit:"...", GoVersion:"go1.25.6", KubeClientVersion:"v1.35"}

Si vous devez rester compatible temporairement :

Fenêtre de terminal
helm upgrade --install myapp ./chart \
--server-side=false \
--wait=legacy

ChangementAction requise
--atomic → --rollback-on-failureRechercher/remplacer dans tous les scripts
--force → --force-replaceRechercher/remplacer
Post-renderer binaire → pluginCréer un plugin Helm
--dry-run → --dry-run=client|serverSpécifier explicitement la valeur
SSA activé par défautGérer les conflits ownership
--wait → --wait=watcherUtiliser pour meilleure détection Ready
OCI login : domaine seulAdapter les scripts de login

L'ordre de ces six étapes n'est pas décoratif : chacune conditionne la suivante. L'audit dit l'ampleur du travail, la comparaison des rendus révèle ce que l'audit n'a pas vu, et la bascule de production ne vient qu'une fois un cycle complet rejoué ailleurs.

  1. Chercher --atomic, --force, --post-renderer et --dry-run dans tous les scripts.
  2. Comparer le helm template rendu par la v3 et par la v4, et lire le diff : c'est là qu'apparaissent les écarts que nul drapeau n'annonce.
  3. Convertir les post-renderers en plugins, seul changement réellement bloquant.
  4. Adapter l'authentification OCI au domaine seul.
  5. Rejouer un cycle complet en préproduction, upgrade et rollback compris.
  6. Basculer la production, une chaîne à la fois, jamais toutes d'un coup.

Six questions sur les ruptures de Helm v4 : le défaut de --server-side qui diffère entre install et upgrade, la stratégie appliquée sans --wait, et les vraies dates de fin de support de Helm 3.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

5 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 site vous est utile ?

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

Je maintiens ce site gratuitement, sans publicité, sans profilage et sans compte à créer. 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