Helm et Kustomize sont deux outils complémentaires pour gérer le déploiement d'applications dans Kubernetes. Ils répondent au besoin de simplifier et standardiser le packaging et le déploiement d'applications complexes, tout en permettant la personnalisation pour différents environnements.
Pourquoi utiliser ces outils ?
Helm est un gestionnaire de paquets pour Kubernetes, souvent appelé "le apt/yum de Kubernetes". Il permet de définir, installer et mettre à jour des applications Kubernetes complexes via des charts.
Helm 3 a simplifié l'architecture en supprimant Tiller (le composant serveur). Il communique directement avec l'API Kubernetes via kubeconfig.
Composants :
# Télécharger et installer Helm 3
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Vérifier l'installation
helm version
Version recommandée pour CKA : Helm 3.x (généralement pré-installé dans l'examen)
# Ajouter un repository officiel
helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami
# Mettre à jour les repositories
helm repo update
# Lister les repositories configurés
helm repo list
# Rechercher un chart
helm search repo nginx
# Installer un chart (crée une release)
helm install my-nginx bitnami/nginx
# Installer avec un namespace spécifique
helm install my-nginx bitnami/nginx --namespace production --create-namespace
# Installer avec des valeurs personnalisées
helm install my-nginx bitnami/nginx --set service.type=LoadBalancer
# Installer avec un fichier de values
helm install my-nginx bitnami/nginx -f custom-values.yaml
# Lister toutes les releases
helm list
helm list --all-namespaces
# Obtenir le statut d'une release
helm status my-nginx
# Afficher les valeurs utilisées pour une release
helm get values my-nginx
# Mettre à jour une release existante
helm upgrade my-nginx bitnami/nginx --set replicaCount=3
# Mettre à jour avec un nouveau fichier de values
helm upgrade my-nginx bitnami/nginx -f new-values.yaml
# Historique des déploiements
helm history my-nginx
# Rollback vers une version précédente
helm rollback my-nginx 1
# Rollback vers la version précédente immédiate
helm rollback my-nginx
# Désinstaller une release
helm uninstall my-nginx
# Désinstaller en gardant l'historique
helm uninstall my-nginx --keep-history
# Simuler une installation (dry-run)
helm install my-nginx bitnami/nginx --dry-run --debug
# Générer les manifestes sans installer
helm template my-nginx bitnami/nginx > manifests.yaml
# Tester un chart
helm test my-nginx
nginx-chart/
├── Chart.yaml # Métadonnées du chart (nom, version, description)
├── values.yaml # Valeurs par défaut pour les templates
├── charts/ # Charts dépendants (optionnel)
├── templates/ # Templates Kubernetes (Go templates)
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── _helpers.tpl # Fonctions helpers réutilisables
│ └── NOTES.txt # Instructions post-installation
└── .helmignore # Fichiers à ignorer lors du packaging
Créons un chart Helm simple pour déployer Nginx.
helm create nginx-chart
cd nginx-chart
apiVersion: v2
name: nginx-chart
description: A simple Nginx Helm chart
type: application
version: 0.1.0
appVersion: "1.29"
# Valeurs par défaut du chart
replicaCount: 2
image:
repository: nginx
tag: "1.29"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi
autoscaling:
enabled: false
minReplicas: 2
maxReplicas: 5
targetCPUUtilizationPercentage: 80
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "nginx-chart.fullname" . }}
labels:
{{- include "nginx-chart.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "nginx-chart.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "nginx-chart.selectorLabels" . | nindent 8 }}
spec:
containers:
- name: nginx
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
resources:
{{- toYaml .Values.resources | nindent 10 }}
apiVersion: v1
kind: Service
metadata:
name: {{ include "nginx-chart.fullname" . }}
labels:
{{- include "nginx-chart.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "nginx-chart.selectorLabels" . | nindent 4 }}
{{/*
Nom complet de la release
*/}}
{{- define "nginx-chart.fullname" -}}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Labels communs
*/}}
{{- define "nginx-chart.labels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "nginx-chart.selectorLabels" -}}
app.kubernetes.io/name: {{ .Chart.Name }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
# Valider la chart
helm lint ./
# Tester la génération (dry-run)
helm install test-nginx ./ --dry-run --debug
# Installer la chart
helm install my-nginx ./
# Installer avec des valeurs personnalisées
helm install my-nginx ./ --set replicaCount=5
# Créer un fichier de valeurs pour production
cat > prod-values.yaml <<EOF
replicaCount: 3
service:
type: LoadBalancer
resources:
limits:
cpu: 200m
memory: 256Mi
EOF
# Installer avec le fichier de valeurs
helm install prod-nginx ./ -f prod-values.yaml
# Mettre à jour
helm upgrade prod-nginx ./ --set image.tag="1.29.5"
# Vérifier le déploiement
helm status prod-nginx
kubectl get pods
# Packager la chart
helm package ./
# Résultat : nginx-chart-0.1.0.tgz
# Installer depuis le package
helm install my-nginx ./nginx-chart-0.1.0.tgz
Helm utilise les templates Go pour générer dynamiquement les manifestes :
# Conditions
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
# ...
{{- end }}
# Boucles
{{- range .Values.extraEnvVars }}
- name: {{ .name }}
value: {{ .value }}
{{- end }}
# Fonctions
{{ .Values.name | upper | quote }}
Les hooks permettent d'exécuter des actions à des moments spécifiques du cycle de vie :
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Release.Name }}-migration
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "0"
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
spec:
containers:
- name: migration
image: myapp/migration:latest
restartPolicy: Never
Types de hooks : pre-install, post-install, pre-delete, post-delete, pre-upgrade, post-upgrade, pre-rollback, post-rollback.
Kustomize est un outil de personnalisation des configurations Kubernetes sans templates. Il permet de créer des variantes de manifestes pour différents environnements en utilisant un système de base et overlays.
Kustomize est intégré nativement dans kubectl depuis la version 1.14 :
# Vérifier la version
kubectl version --client
# Kustomize est accessible via kubectl
kubectl kustomize --help
Pour installer la version standalone (optionnel) :
curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash
# Générer les manifestes sans les appliquer
kubectl kustomize <directory>
# Appliquer directement une configuration kustomize
kubectl apply -k <directory>
# Supprimer les ressources
kubectl delete -k <directory>
# Afficher les différences
kubectl diff -k <directory>
k8s/
├── base/ # Configuration commune
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/ # Variantes par environnement
├── dev/
│ ├── kustomization.yaml # Raccourcis uniquement (simple)
│ └── namespace.yaml # Création du namespace
├── staging/
│ ├── kustomization.yaml
│ ├── namespace.yaml # Création du namespace
│ ├── patch-replicas.yaml # Fichiers de patch (intermédiaire)
│ └── patch-resources.yaml
└── prod/
├── kustomization.yaml
├── namespace.yaml # Création du namespace
├── patch-replicas.yaml # Fichiers de patch (complexe)
├── patch-service.yaml
├── patch-resources.yaml
└── hpa.yaml # Ressource additionnelle
mkdir -p k8s/base
base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.29
ports:
- containerPort: 80
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 100m
memory: 128Mi
base/service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: nginx
base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# Ressources de base
resources:
- deployment.yaml
- service.yaml
# Labels communs appliqués à toutes les ressources
labels:
- pairs:
app: nginx
managed-by: kustomize
# Annotations communes
commonAnnotations:
description: "Nginx application managed with Kustomize"
mkdir -p k8s/overlays/dev
overlays/dev/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: development
labels:
environment: dev
managed-by: kustomize
overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# Référence à la base
resources:
- ../../base
- namespace.yaml # Créer le namespace en premier
# Préfixe pour toutes les ressources
namePrefix: dev-
# Namespace
namespace: development
# Labels spécifiques à dev
labels:
- pairs:
environment: dev
# Personnalisation des images
images:
- name: nginx
newTag: "1.29-alpine"
# Replicas pour dev (1 seule instance)
replicas:
- name: nginx
count: 1
mkdir -p k8s/overlays/staging
overlays/staging/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: staging
labels:
environment: staging
managed-by: kustomize
overlays/staging/patch-replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 2
overlays/staging/patch-resources.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi
overlays/staging/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
- namespace.yaml # Créer le namespace en premier
namePrefix: staging-
namespace: staging
labels:
- pairs:
environment: staging
# Appliquer les patches (structure cohérente avec production)
patchesStrategicMerge:
- patch-replicas.yaml
- patch-resources.yaml
# ConfigMap generator pour configuration staging
configMapGenerator:
- name: nginx-config
literals:
- ENVIRONMENT=staging
- LOG_LEVEL=info
mkdir -p k8s/overlays/prod
overlays/prod/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
environment: production
managed-by: kustomize
annotations:
description: "Production environment - handle with care"
overlays/prod/patch-replicas.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 5
overlays/prod/patch-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: LoadBalancer
overlays/prod/patch-resources.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
- namespace.yaml # Créer le namespace en premier
- hpa.yaml
namePrefix: prod-
namespace: production
labels:
- pairs:
environment: production
# Tag d'image pour production
images:
- name: nginx
newTag: "1.29.5"
# Patches pour production
patchesStrategicMerge:
- patch-replicas.yaml
- patch-service.yaml
- patch-resources.yaml
# ConfigMap pour production
configMapGenerator:
- name: nginx-config
literals:
- ENVIRONMENT=production
- LOG_LEVEL=warning
- MAX_CONNECTIONS=1000
overlays/prod/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
minReplicas: 5
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
# Visualiser la configuration générée pour dev
kubectl kustomize k8s/overlays/dev
# Visualiser pour staging
kubectl kustomize k8s/overlays/staging
# Visualiser pour production
kubectl kustomize k8s/overlays/prod
# Déployer sur dev
kubectl apply -k k8s/overlays/dev
# Déployer sur staging
kubectl apply -k k8s/overlays/staging
# Déployer sur production
kubectl apply -k k8s/overlays/prod
# Vérifier les ressources par namespace
kubectl get all -n development
kubectl get all -n staging
kubectl get all -n production
# Supprimer l'environnement dev
kubectl delete -k k8s/overlays/dev
Génération automatique de ConfigMaps avec hash dans le nom (pour déclencher le redémarrage des pods) :
# kustomization.yaml
configMapGenerator:
- name: app-config
files:
- config.properties
- database.conf
literals:
- API_URL=https://api.example.com
- TIMEOUT=30
secretGenerator:
- name: app-secrets
files:
- credentials.txt
literals:
- DB_PASSWORD=secretpass123
Résultat : Les ressources seront créées avec un hash, par exemple app-config-d2t54gkm98.
Pour des modifications précises :
# kustomization.yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: nginx
patch: |-
- op: replace
path: /spec/replicas
value: 3
- op: add
path: /spec/template/spec/containers/0/env
value:
- name: DEBUG
value: "true"
# kustomization.yaml
vars:
- name: SERVICE_NAME
objref:
kind: Service
name: nginx
apiVersion: v1
fieldref:
fieldpath: metadata.name
configurations:
- varreference.yaml
| Critère | Helm | Kustomize |
|---|---|---|
| Approche | Templating avec Go templates | Transformation de YAML natif |
| Complexité | Plus complexe (courbe d'apprentissage) | Plus simple (YAML standard) |
| Versioning | Gestion complète des versions (releases) | Pas de versioning intégré |
| Rollback | Support natif (helm rollback) |
Nécessite une solution externe (Git) |
| Réutilisabilité | Excellente (charts publics, repositories) | Bonne (composition de bases) |
| Packaging | Oui (.tgz, distribution via repositories) |
Non (gestion via Git généralement) |
| Intégration kubectl | Non (CLI séparé) | Oui (natif dans kubectl) |
| Logique conditionnelle | Oui (templates Go) | Limitée (patches) |
| Installation | Nécessite Helm CLI | Inclus dans kubectl |
| Écosystème | Large (Artifact Hub, nombreux charts) | Croissant (intégration GitOps) |
| Cas d'usage | Applications complexes, réutilisation | Personnalisation multi-environnements |
Choisir Helm quand vous avez besoin de :
Exemples de cas d'usage :
Choisir Kustomize quand vous avez besoin de :
Exemples de cas d'usage :
Oui ! Il est possible d'utiliser les deux ensemble :
Exemple de workflow combiné :
# Utiliser Helm pour installer une application tierce
helm install prometheus prometheus-community/prometheus
# Utiliser Kustomize pour déployer votre application
kubectl apply -k k8s/overlays/prod
# Ou générer des manifestes Helm puis les personnaliser avec Kustomize
helm template my-app ./chart > base/app.yaml
kubectl kustomize overlays/prod > final-manifests.yaml
--set en productionhelm lint avant packaginghelm install --dry-run --debugvalues.yamlkubectl kustomize avant applyhelm install/upgrade/rollback/uninstallkubectl apply -k directoryhelm template, kubectl kustomize# Helm
helm repo add <name> <url> # Ajouter un repository
helm repo update # Mettre à jour les repos
helm search repo <keyword> # Rechercher un chart
helm install <name> <chart> # Installer
helm upgrade <name> <chart> # Mettre à jour
helm rollback <name> <revision> # Rollback
helm list # Lister les releases
helm uninstall <name> # Désinstaller
# Kustomize
kubectl kustomize <dir> # Générer les manifestes
kubectl apply -k <dir> # Appliquer
kubectl delete -k <dir> # Supprimer
kubectl diff -k <dir> # Voir les différences