Un chart Helm qui fonctionnait très bien à trois valeurs de configuration devient souvent illisible passé la dizaine, quand chaque nouveau cas particulier ajoute une condition imbriquée dans un template déjà dense. Comprendre ce que Helm fait réellement, et où s’arrête ce que le templating peut raisonnablement gérer, évite d’hériter d’un chart que plus personne ne veut toucher.

Un chart, ce sont des templates plus des valeurs

Un chart Helm sépare la structure d’un déploiement (les templates, en Go template, qui produisent du YAML Kubernetes) de sa configuration (le fichier values.yaml, qui fournit les valeurs par défaut, surchargeables à l’installation).

# templates/deployment.yaml (extrait)
spec:
  replicas: {{ .Values.replicaCount }}
  template:
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
# values.yaml (défauts)
replicaCount: 2
image:
  repository: registry.example.com/app
  tag: "1.4.2"
resources:
  requests:
    cpu: 250m
    memory: 512Mi

helm template rend ce mélange en YAML brut sans rien installer, ce qui permet de vérifier exactement ce qui serait appliqué avant tout déploiement réel. C’est souvent la première commande à connaître pour déboguer un chart qui produit un résultat inattendu.

Où le templating devient un problème

Un template Go permet des conditions et des boucles, ce qui pousse naturellement à en ajouter une par cas particulier rencontré : un environnement qui a besoin d’une variable d’environnement en plus, un autre qui désactive une sonde de santé, un troisième avec une annotation spécifique. Chaque ajout est raisonnable pris isolément. Après une dizaine d’itérations, le template mélange la structure Kubernetes qu’il génère avec la logique conditionnelle qui décide de cette structure, et les deux deviennent difficiles à démêler à la lecture.

{{- if and .Values.ingress.enabled (not .Values.ingress.legacy) }}
  {{- if .Values.ingress.tls.enabled }}
    {{- range .Values.ingress.hosts }}
      {{- if ne .name "internal" }}
# ... la logique métier a disparu sous la logique de template
      {{- end }}
    {{- end }}
  {{- end }}
{{- end }}

Le signal à surveiller n’est pas le nombre de lignes du template, mais la profondeur d’imbrication des conditions : au-delà de deux ou trois niveaux, la question à se poser n’est plus « comment ajouter ce cas » mais « est-ce que ce chart essaie de couvrir trop de scénarios distincts avec un seul jeu de templates ».

Kustomize : composer plutôt que conditionner

Kustomize part d’un principe différent : pas de templating, mais une superposition de patches sur des manifests YAML de base. Une configuration de base décrit le cas commun, et des overlays par environnement appliquent uniquement les différences.

# base/deployment.yaml — cas commun, sans condition
# overlays/production/patch.yaml — uniquement ce qui diffère
- op: replace
  path: /spec/replicas
  value: 5

Cette approche évite complètement le problème des conditions imbriquées, parce qu’il n’y a jamais de branche logique à écrire : chaque environnement a son propre overlay, lisible indépendamment des autres. Le compromis inverse : ce qui est facile à exprimer en une condition Helm (« si X alors Y ») demande de dupliquer une structure de patch dans Kustomize quand la variation ne se réduit pas à un remplacement de valeur simple.

Comment choisir entre les deux

Helm convient bien à un chart destiné à être réutilisé par d’autres équipes ou publié publiquement (un chart officiel PostgreSQL ou Redis, par exemple), où la configuration par valeurs est justement le point : l’utilisateur ne voit jamais les templates, seulement les valeurs qu’il ajuste. Kustomize convient mieux à la gestion interne de plusieurs environnements d’une seule application, où la logique reste simple et où la lisibilité de chaque overlay compte plus que la réutilisabilité externe. Les deux outils se combinent d’ailleurs sans conflit : Kustomize sait patcher la sortie d’un chart Helm déjà rendu, pour les cas où un chart tiers ne prévoit pas exactement le paramètre nécessaire.

Où ça se range

Le choix de packaging fait partie du socle posé lors d’une migration Kubernetes : versionné, documenté, reproductible, comme le reste de l’infrastructure. Un chart illisible après six mois n’est pas différent d’un script bash que plus personne n’ose modifier, seulement plus récent.

À retenir

Helm sépare templates et valeurs pour paramétrer un déploiement ; le problème n’est jamais la présence de conditions mais leur accumulation, qui finit par mélanger structure Kubernetes et logique de template au point de devenir illisible. Kustomize évite ce piège par composition de patches plutôt que par conditions, au prix d’une duplication plus importante pour les variations complexes. Le critère de choix est la réutilisabilité externe du chart, pas une préférence d’outil.