Un chart Helm mal configuré peut générer des manifestes Kubernetes invalides, des déploiements qui échouent silencieusement, ou des failles de sécurité. Ce guide vous montre comment détecter ces problèmes avant qu’ils n’atteignent la production, en mettant en place une chaîne de validation automatisée.
Concrètement, vous allez apprendre à :
- Valider les values fournies par les utilisateurs (types, limites, valeurs autorisées)
- Générer automatiquement la documentation de votre chart
- Vérifier que les manifestes générés sont conformes aux standards Kubernetes
- Détecter les mauvaises pratiques de sécurité (containers root, absence de limits…)
Pré-requis
Section intitulée « Pré-requis »Avant de commencer, assurez-vous d’avoir :
- Un chart Helm existant (ou
helm create mon-chart) - Helm v3.8+ installé
- Les outils de qualité installés :
# Avec mise (recommandé)mise use helm-docs kubeconform kube-linter helm-ctpipx install yamale # Requis par ct
# Vérificationhelm-docs --version # v1.14.2kubeconform -v # v0.7.0kube-linter version # 0.8.1ct version # v3.14.0Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »| Section | Concept | Durée |
|---|---|---|
| values.schema.json | Validation JSON Schema native | 10 min |
| helm-docs | Génération automatique du README | 8 min |
| helm lint | Validation syntaxique de base | 5 min |
| kubeconform | Validation des manifestes K8s | 8 min |
| kube-linter | Bonnes pratiques sécurité | 8 min |
| ct lint | Validation complète CI/CD | 10 min |
| Conventions | Labels, nommage, versioning | 6 min |
Valider les values avec values.schema.json
Section intitulée « Valider les values avec values.schema.json »Helm supporte nativement la validation des values via un fichier JSON Schema. Quand ce fichier existe, Helm refuse tout install, upgrade ou template si les values ne respectent pas le schema.
Créer le schema
Section intitulée « Créer le schema »Placez values.schema.json à la racine du chart :
{ "\$schema": "https://json-schema.org/draft-07/schema#", "type": "object", "required": ["replicaCount", "image"], "properties": { "replicaCount": { "type": "integer", "minimum": 1, "maximum": 10, "description": "Nombre de réplicas (1-10)" }, "image": { "type": "object", "required": ["repository"], "properties": { "repository": { "type": "string", "description": "Image Docker à déployer" }, "tag": { "type": "string", "default": "latest", "description": "Tag de l'image" }, "pullPolicy": { "type": "string", "enum": ["Always", "IfNotPresent", "Never"], "default": "IfNotPresent" } } }, "service": { "type": "object", "properties": { "type": { "type": "string", "enum": ["ClusterIP", "NodePort", "LoadBalancer"], "default": "ClusterIP" }, "port": { "type": "integer", "minimum": 1, "maximum": 65535, "default": 80 } } } }}Tester la validation
Section intitulée « Tester la validation »# Values valides → succèshelm template test mon-chart/# replicaCount hors limites → erreurhelm template test mon-chart/ --set replicaCount=15Error: values don't meet the specifications of the schema(s) in the following chart(s):mon-chart:- at '/replicaCount': maximum: got 15, want 10# Valeur enum invalide → erreurhelm template test mon-chart/ --set service.type=InvalidError: values don't meet the specifications of the schema(s) in the following chart(s):mon-chart:- at '/service/type': value must be one of 'ClusterIP', 'NodePort', 'LoadBalancer'Types JSON Schema utiles
Section intitulée « Types JSON Schema utiles »| Type | Usage | Exemple |
|---|---|---|
string | Texte | "nginx" |
integer | Nombre entier | 3 |
number | Nombre décimal | 0.5 |
boolean | Vrai/faux | true |
array | Liste | ["a", "b"] |
object | Objet imbriqué | {"key": "value"} |
Contraintes utiles
Section intitulée « Contraintes utiles »{ "replicaCount": { "type": "integer", "minimum": 1, // Valeur minimale "maximum": 100 // Valeur maximale }, "environment": { "type": "string", "enum": ["dev", "staging", "prod"] // Liste de valeurs autorisées }, "image": { "type": "string", "pattern": "^[a-z0-9.-]+/[a-z0-9.-]+:[a-z0-9.-]+$" // Regex }, "resources": { "type": "object", "additionalProperties": false // Interdit les clés non déclarées }}Documenter un chart avec helm-docs
Section intitulée « Documenter un chart avec helm-docs »helm-docs génère automatiquement un README.md à partir des commentaires dans values.yaml et du Chart.yaml.
Ajouter des commentaires helm-docs
Section intitulée « Ajouter des commentaires helm-docs »Les commentaires commençant par # -- sont extraits pour la documentation :
# -- Nombre de réplicas du deploymentreplicaCount: 1
image: # -- Repository de l'image Docker repository: nginx # -- Tag de l'image (défaut: appVersion du Chart) tag: "" # -- Politique de téléchargement de l'image # @default -- IfNotPresent pullPolicy: IfNotPresent
service: # -- Type de service Kubernetes type: ClusterIP # -- Port exposé par le service port: 80
# -- Configuration des resources (requests/limits)# @default -- Voir values.yamlresources: {}
# -- Activation de l'autoscaling HPAautoscaling: # -- Activer/désactiver l'autoscaling enabled: false # -- Nombre minimum de réplicas minReplicas: 1 # -- Nombre maximum de réplicas maxReplicas: 100Générer le README
Section intitulée « Générer le README »cd mon-chart/helm-docsINFO[2026-02-01T19:27:33+01:00] Found Chart directories [.]INFO[2026-02-01T19:27:33+01:00] Generating README Documentation for chart .Résultat généré
Section intitulée « Résultat généré »# mon-chart

A Helm chart for Kubernetes
## Values
| Key | Type | Default | Description ||-----|------|---------|-------------|| replicaCount | int | `1` | Nombre de réplicas du deployment || image.repository | string | `"nginx"` | Repository de l'image Docker || image.tag | string | `""` | Tag de l'image (défaut: appVersion du Chart) || image.pullPolicy | string | `"IfNotPresent"` | Politique de téléchargement de l'image || service.type | string | `"ClusterIP"` | Type de service Kubernetes || service.port | int | `80` | Port exposé par le service || resources | object | Voir values.yaml | Configuration des resources (requests/limits) || autoscaling.enabled | bool | `false` | Activer/désactiver l'autoscaling |Template personnalisé
Section intitulée « Template personnalisé »Créez un fichier README.md.gotmpl pour personnaliser le format :
# {{ .Name }}
{{ .Description }}
## Installation
\\`\\`\\`bashhelm install {{ .Name }} ./{{ .Name }}\\`\\`\\`
## Configuration
{{ template "chart.valuesTable" . }}
## Maintainers
{{ template "chart.maintainersTable" . }}helm lint : validation de base
Section intitulée « helm lint : validation de base »helm lint est la première ligne de défense : il vérifie la syntaxe YAML, les templates Go, et le Chart.yaml.
helm lint mon-chart/==> Linting mon-chart/[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, 0 chart(s) failedMode strict
Section intitulée « Mode strict »Le flag --strict fait échouer le lint sur les warnings :
helm lint mon-chart/ --strictLint avec values spécifiques
Section intitulée « Lint avec values spécifiques »helm lint mon-chart/ -f production-values.yamlkubeconform : validation des manifestes
Section intitulée « kubeconform : validation des manifestes »kubeconform valide que les manifestes générés sont conformes aux schemas Kubernetes.
helm template test mon-chart/ | kubeconform -strict -summarySummary: 4 resources found parsing stdin - Valid: 4, Invalid: 0, Errors: 0, Skipped: 0Détecter les erreurs de schema
Section intitulée « Détecter les erreurs de schema »Si un champ est mal nommé ou a le mauvais type :
# Manifest avec erreurhelm template test mon-chart/ --set service.ports=80 | kubeconform -strictstdin - Service test-mon-chart is invalid: problem validating schema: port in body is requiredValider pour une version K8s spécifique
Section intitulée « Valider pour une version K8s spécifique »helm template test mon-chart/ | kubeconform -kubernetes-version 1.29.0 -strict -summaryOptions utiles
Section intitulée « Options utiles »| Option | Description |
|---|---|
-strict | Échoue sur les propriétés inconnues |
-summary | Affiche un résumé à la fin |
-output json | Sortie JSON pour la CI |
-kubernetes-version X.Y.Z | Valide pour une version K8s spécifique |
-skip Kind1,Kind2 | Ignore certains types de ressources |
kube-linter : bonnes pratiques sécurité
Section intitulée « kube-linter : bonnes pratiques sécurité »kube-linter analyse les manifestes pour détecter les problèmes de sécurité et les mauvaises pratiques.
helm template test mon-chart/ | kube-linter lint -KubeLinter 0.8.1
<stdin>: (object: <no namespace>/test-mon-chart apps/v1, Kind=Deployment) container "mon-chart" does not have a read-only root file system (check: no-read-only-root-fs, remediation: Set readOnlyRootFilesystem to true in the container securityContext.)
<stdin>: (object: <no namespace>/test-mon-chart apps/v1, Kind=Deployment) container "mon-chart" is not set to runAsNonRoot (check: run-as-non-root, remediation: Set runAsUser to a non-zero number and runAsNonRoot to true in your pod or container securityContext.)
<stdin>: (object: <no namespace>/test-mon-chart apps/v1, Kind=Deployment) container "mon-chart" has cpu request 0 (check: unset-cpu-requirements, remediation: Set CPU requests for your container based on its requirements.)
Error: found 9 lint errorsChecks courants
Section intitulée « Checks courants »| Check | Description | Remediation |
|---|---|---|
no-read-only-root-fs | Filesystem root accessible en écriture | Ajouter readOnlyRootFilesystem: true |
run-as-non-root | Container s’exécute en root | Ajouter runAsNonRoot: true |
unset-cpu-requirements | Pas de requests/limits CPU | Définir resources.requests.cpu |
unset-memory-requirements | Pas de requests/limits memory | Définir resources.limits.memory |
latest-tag | Image utilise le tag latest | Utiliser un tag spécifique |
privilege-escalation-container | allowPrivilegeEscalation non défini | Ajouter allowPrivilegeEscalation: false |
Configuration personnalisée
Section intitulée « Configuration personnalisée »Créez un fichier .kube-linter.yaml pour ajuster les règles :
checks: # Désactiver certaines règles exclude: - "unset-cpu-requirements" - "no-read-only-root-fs"
# Ou activer uniquement certaines règles # include: # - "run-as-non-root" # - "latest-tag"helm template test mon-chart/ | kube-linter lint --config .kube-linter.yaml -ct lint : validation complète
Section intitulée « ct lint : validation complète »chart-testing (ct) est l’outil officiel pour valider les charts avant merge. Il combine helm lint, yamale (validation YAML), et vérifie les conventions.
Configuration
Section intitulée « Configuration »Créez un fichier ct.yaml à la racine du repo :
# Désactive la vérification des maintainersvalidate-maintainers: false# Désactive la vérification d'incrément de versioncheck-version-increment: false# Chemin vers les chartschart-dirs: - chartsTéléchargez les schemas officiels :
curl -sSL https://raw.githubusercontent.com/helm/chart-testing/main/etc/chart_schema.yaml -o chart_schema.yamlcurl -sSL https://raw.githubusercontent.com/helm/chart-testing/main/etc/lintconf.yaml -o lintconf.yamlLancer ct lint
Section intitulée « Lancer ct lint »ct lint --config ct.yaml --chart-yaml-schema chart_schema.yaml --lint-conf lintconf.yaml --charts mon-chart/Linting charts...
------------------------------------------------------------------------------------------------------------------------ Charts to be processed:------------------------------------------------------------------------------------------------------------------------ mon-chart => (version: "0.1.0", path: "mon-chart")------------------------------------------------------------------------------------------------------------------------
Linting chart "mon-chart => (version: \"0.1.0\", path: \"mon-chart\")"Validating mon-chart/Chart.yaml...Validation success! 👍==> Linting mon-chart[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, 0 chart(s) failed
------------------------------------------------------------------------------------------------------------------------ ✔︎ mon-chart => (version: "0.1.0", path: "mon-chart")------------------------------------------------------------------------------------------------------------------------All charts linted successfullyct lint dans un dépôt Git
Section intitulée « ct lint dans un dépôt Git »ct lint peut détecter automatiquement les charts modifiés :
# Lint uniquement les charts modifiés par rapport à mainct lint --target-branch main --config ct.yamlConventions de nommage et labels
Section intitulée « Conventions de nommage et labels »Labels Kubernetes recommandés
Section intitulée « Labels Kubernetes recommandés »Utilisez les labels standards définis par Kubernetes :
{{- define "mychart.labels" -}}helm.sh/chart: {{ include "mychart.chart" . }}app.kubernetes.io/name: {{ include "mychart.name" . }}app.kubernetes.io/instance: {{ .Release.Name }}app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}app.kubernetes.io/managed-by: {{ .Release.Service }}{{- end }}
{{- define "mychart.selectorLabels" -}}app.kubernetes.io/name: {{ include "mychart.name" . }}app.kubernetes.io/instance: {{ .Release.Name }}{{- end }}| Label | Description | Exemple |
|---|---|---|
app.kubernetes.io/name | Nom de l’application | nginx |
app.kubernetes.io/instance | Instance unique | nginx-prod |
app.kubernetes.io/version | Version de l’application | 1.25.0 |
app.kubernetes.io/component | Composant dans l’application | frontend |
app.kubernetes.io/part-of | Application parente | wordpress |
app.kubernetes.io/managed-by | Outil de gestion | Helm |
helm.sh/chart | Nom et version du chart | nginx-1.0.0 |
Nommage des ressources
Section intitulée « Nommage des ressources »Pattern recommandé : {{ .Release.Name }}-{{ .Chart.Name }}
{{- define "mychart.fullname" -}}{{- if .Values.fullnameOverride }}{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}{{- else }}{{- \$name := default .Chart.Name .Values.nameOverride }}{{- printf "%s-%s" .Release.Name \$name | trunc 63 | trimSuffix "-" }}{{- end }}{{- end }}Versioning : chart vs appVersion
Section intitulée « Versioning : chart vs appVersion »| Champ | Ce qu’il représente | Quand l’incrémenter |
|---|---|---|
version | Version du chart Helm | Modification des templates, values, schema |
appVersion | Version de l’application | Mise à jour de l’image Docker |
apiVersion: v2name: mon-appversion: 1.2.0 # Chart modifié → +1 minor ou patchappVersion: "3.5.1" # Nouvelle version de l'app → mettre à jourLab B4 — Chaîne qualité complète
Section intitulée « Lab B4 — Chaîne qualité complète »-
Créer un chart avec schema :
Fenêtre de terminal helm create quality-demo -
Ajouter un values.schema.json avec au moins :
replicaCount: integer, min 1, max 10service.type: enum ClusterIP/NodePort/LoadBalancerimage.repository: required
-
Documenter avec helm-docs :
- Ajouter les commentaires
# --dans values.yaml - Générer le README
- Ajouter les commentaires
-
Valider avec kubeconform et kube-linter :
Fenêtre de terminal helm template test quality-demo/ | kubeconform -strict -summaryhelm template test quality-demo/ | kube-linter lint - -
Corriger les erreurs kube-linter dans les templates
Critères de réussite :
- Schema valide rejette
replicaCount=15 - README.md généré automatiquement avec tableau des values
- kubeconform : 0 invalid
- kube-linter : < 3 erreurs (après corrections)
À retenir
Section intitulée « À retenir »| Outil | Valide | Quand l’utiliser |
|---|---|---|
values.schema.json | Values utilisateur | Toujours (natif Helm) |
helm lint | Syntaxe chart | Développement |
helm-docs | Documentation | Avant commit |
kubeconform | Manifestes K8s | CI/CD |
kube-linter | Sécurité, bonnes pratiques | CI/CD |
ct lint | Chart complet | CI/CD, avant merge |