Templates et Values
1 - Introduction aux templates
Les templates Helm utilisent le moteur de templates Go avec des extensions spécifiques Helm.
Syntaxe de base
# Délimiteurs
{{ }} # Action template
{{- }} # Supprime les espaces avant
{{ -}} # Supprime les espaces après
{{- -}} # Supprime les espaces des deux côtés
# Commentaires
{{/* Ceci est un commentaire */}}
2 - Built-in Objects
2.1 Objets disponibles
| Objet | Description |
|---|---|
.Values | Valeurs du values.yaml et overrides |
.Release | Informations sur la release |
.Chart | Contenu du Chart.yaml |
.Files | Accès aux fichiers du chart |
.Capabilities | Informations sur le cluster |
.Template | Informations sur le template actuel |
2.2 .Values
# values.yaml
replicaCount: 3
image:
repository: nginx
tag: "1.25"
# Dans le template
apiVersion: apps/v1
kind: Deployment
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
- name: nginx
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
2.3 .Release
# Propriétés disponibles
{{ .Release.Name }} # Nom de la release
{{ .Release.Namespace }} # Namespace de déploiement
{{ .Release.IsUpgrade }} # true si upgrade
{{ .Release.IsInstall }} # true si installation
{{ .Release.Revision }} # Numéro de révision
{{ .Release.Service }} # Toujours "Helm"
# Exemple
metadata:
name: {{ .Release.Name }}-config
namespace: {{ .Release.Namespace }}
labels:
release: {{ .Release.Name }}
2.4 .Chart
# Propriétés du Chart.yaml
{{ .Chart.Name }} # Nom du chart
{{ .Chart.Version }} # Version du chart
{{ .Chart.AppVersion }} # Version de l'application
{{ .Chart.Description }} # Description
{{ .Chart.Type }} # Type (application/library)
# Exemple
labels:
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
2.5 .Capabilities
# Informations sur le cluster
{{ .Capabilities.KubeVersion }} # Version K8s complète
{{ .Capabilities.KubeVersion.Major }} # Version majeure
{{ .Capabilities.KubeVersion.Minor }} # Version mineure
{{ .Capabilities.APIVersions.Has "apps/v1" }} # API disponible?
# Exemple conditionnel basé sur la version
{{- if semverCompare ">=1.21" .Capabilities.KubeVersion.Version }}
apiVersion: networking.k8s.io/v1
{{- else }}
apiVersion: networking.k8s.io/v1beta1
{{- end }}
kind: Ingress
2.6 .Files
# Accéder aux fichiers du chart
{{ .Files.Get "config/app.conf" }} # Contenu d'un fichier
{{ .Files.GetBytes "binary/data.bin" }} # Contenu binaire
{{ .Files.Glob "configs/*.yaml" }} # Glob de fichiers
# Exemple: ConfigMap depuis fichier
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-config
data:
app.conf: |-
{{ .Files.Get "config/app.conf" | indent 4 }}
# Ou plusieurs fichiers
{{- range $path, $content := .Files.Glob "configs/*.yaml" }}
{{ base $path }}: |-
{{ $content | indent 4 }}
{{- end }}
3 - Fonctions et Pipelines
3.1 Pipelines
Les pipelines permettent d'enchaîner les fonctions :
# Syntaxe pipeline
{{ valeur | fonction1 | fonction2 | fonction3 }}
# Équivalent à
{{ fonction3 (fonction2 (fonction1 valeur)) }}
# Exemples
{{ .Values.name | upper }} # Majuscules
{{ .Values.name | lower | quote }} # Minuscules puis guillemets
{{ .Values.data | toYaml | indent 4 }} # YAML indenté
3.2 Fonctions de chaînes
# Manipulation de chaînes
{{ upper "hello" }} # HELLO
{{ lower "HELLO" }} # hello
{{ title "hello world" }} # Hello World
{{ trim " hello " }} # hello
{{ trimSuffix "-" "hello-" }} # hello
{{ trimPrefix "v" "v1.0.0" }} # 1.0.0
{{ quote "hello" }} # "hello"
{{ squote "hello" }} # 'hello'
{{ nospace "hello world" }} # helloworld
{{ trunc 5 "hello world" }} # hello
{{ substr 0 5 "hello world" }} # hello
{{ replace "old" "new" "old text" }} # new text
{{ contains "lo" "hello" }} # true
{{ hasPrefix "he" "hello" }} # true
{{ hasSuffix "lo" "hello" }} # true
# Génération
{{ randAlphaNum 10 }} # Chaîne aléatoire
{{ randNumeric 5 }} # Nombre aléatoire
{{ now | date "2006-01-02" }} # Date formatée
{{ uuidv4 }} # UUID v4
3.3 Fonctions de conversion
# Types
{{ int "123" }} # 123 (int)
{{ int64 "123" }} # 123 (int64)
{{ float64 "1.23" }} # 1.23 (float64)
{{ toString 123 }} # "123"
{{ toJson .Values.config }} # JSON
{{ toYaml .Values.config }} # YAML
{{ toPrettyJson .Values }} # JSON formaté
{{ fromYaml "key: value" }} # Parse YAML
{{ fromJson "{\"k\":\"v\"}" }} # Parse JSON
# Encodage
{{ b64enc "hello" }} # Base64 encode
{{ b64dec "aGVsbG8=" }} # Base64 decode
{{ sha256sum "hello" }} # Hash SHA256
3.4 Fonctions de listes
# values.yaml
hosts:
- host1.example.com
- host2.example.com
- host3.example.com
# Opérations
{{ first .Values.hosts }} # host1.example.com
{{ last .Values.hosts }} # host3.example.com
{{ rest .Values.hosts }} # [host2, host3]
{{ initial .Values.hosts }} # [host1, host2]
{{ len .Values.hosts }} # 3
{{ has "host1.example.com" .Values.hosts }} # true
{{ without .Values.hosts "host1.example.com" }} # [host2, host3]
{{ concat .Values.hosts (list "host4.com") }} # Fusion
# Création de listes
{{ list "a" "b" "c" }} # [a, b, c]
{{ tuple 1 2 3 }} # (1, 2, 3)
3.5 Fonctions de dictionnaires
# Opérations sur maps
{{ dict "key1" "val1" "key2" "val2" }} # Créer un dict
{{ get .Values.config "key" }} # Récupérer une clé
{{ set .Values.config "key" "value" }} # Définir une clé
{{ unset .Values.config "key" }} # Supprimer une clé
{{ hasKey .Values.config "key" }} # Vérifier une clé
{{ keys .Values.config }} # Liste des clés
{{ values .Values.config }} # Liste des valeurs
{{ pluck "key" .Values.dict1 .Values.dict2 }} # Extraire de plusieurs dicts
{{ merge .Values.dict1 .Values.dict2 }} # Fusionner
# Exemple pratique
{{- $labels := dict
"app" .Chart.Name
"version" .Chart.Version
"release" .Release.Name
-}}
labels:
{{- toYaml $labels | nindent 2 }}
3.6 Fonctions logiques
# Comparaisons
{{ eq "a" "a" }} # true (égal)
{{ ne "a" "b" }} # true (différent)
{{ lt 1 2 }} # true (inférieur)
{{ le 1 1 }} # true (inférieur ou égal)
{{ gt 2 1 }} # true (supérieur)
{{ ge 2 2 }} # true (supérieur ou égal)
# Logique
{{ and true true }} # true
{{ or false true }} # true
{{ not true }} # false
# Conditions
{{ default "valeur_defaut" .Values.optionnel }}
{{ coalesce .Values.a .Values.b "default" }} # Premier non-vide
{{ empty .Values.maybe }} # true si vide
{{ ternary "oui" "non" true }} # oui (condition ternaire)
4 - Structures de contrôle
4.1 Conditions if/else
# Syntaxe de base
{{- if condition }}
# contenu
{{- else if autreCondition }}
# autre contenu
{{- else }}
# sinon
{{- end }}
# Exemples
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "app.fullname" . }}
spec:
rules:
{{- range .Values.ingress.hosts }}
- host: {{ . }}
{{- end }}
{{- end }}
# Conditions combinées
{{- if and .Values.postgresql.enabled .Values.redis.enabled }}
# Les deux sont activés
{{- end }}
{{- if or .Values.dev .Values.staging }}
# Environnement non-production
{{- end }}
# Vérifier si une valeur existe
{{- if .Values.resources }}
resources:
{{- toYaml .Values.resources | nindent 2 }}
{{- end }}
4.2 Boucles range
# Itérer sur une liste
{{- range .Values.hosts }}
- host: {{ . }}
{{- end }}
# Avec index
{{- range $index, $value := .Values.hosts }}
- index: {{ $index }}
host: {{ $value }}
{{- end }}
# Itérer sur un dictionnaire
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
# Exemple complet
env:
{{- range $key, $value := .Values.environment }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- range .Values.envFromSecrets }}
- name: {{ .name }}
valueFrom:
secretKeyRef:
name: {{ .secretName }}
key: {{ .secretKey }}
{{- end }}
4.3 with - Changer le scope
# Changer le contexte (.)
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 2 }}
{{- end }}
# Attention: à l'intérieur de with, . change de contexte
{{- with .Values.ingress }}
host: {{ .host }}
# Pour accéder au contexte parent, utilisez $
release: {{ $.Release.Name }}
{{- end }}
4.4 Variables
# Définir une variable
{{- $name := .Values.name -}}
{{- $fullname := include "app.fullname" . -}}
# Utiliser la variable
metadata:
name: {{ $name }}
labels:
app: {{ $fullname }}
# Variable dans une boucle
{{- range $idx, $host := .Values.hosts }}
- name: HOST_{{ $idx }}
value: {{ $host }}
{{- end }}
5 - Définir et utiliser des templates nommés
5.1 define et template
{{/* _helpers.tpl */}}
{{/*
Définir un template nommé
*/}}
{{- define "app.labels" -}}
app.kubernetes.io/name: {{ include "app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Template avec paramètres via dict
*/}}
{{- define "app.servicePort" -}}
{{- $svc := .svc -}}
{{- $port := .port -}}
- port: {{ $port }}
targetPort: {{ $svc.targetPort | default $port }}
protocol: {{ $svc.protocol | default "TCP" }}
name: {{ $svc.name | default "http" }}
{{- end }}
{{/* deployment.yaml */}}
metadata:
labels:
# Utiliser template
{{- template "app.labels" . }}
# Ou include (recommandé car peut être pipeliné)
{{- include "app.labels" . | nindent 4 }}
# Appeler avec des paramètres
ports:
{{- include "app.servicePort" (dict "svc" .Values.service "port" 80) | nindent 2 }}
5.2 Différence template vs include
# template - Ne peut pas être pipeliné
{{- template "app.labels" . }}
# include - Peut être pipeliné (RECOMMANDÉ)
{{- include "app.labels" . | nindent 4 }}
{{- include "app.labels" . | indent 2 }}
6 - Patterns courants
6.1 Génération conditionnelle de ressources
{{/* ingress.yaml */}}
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "app.fullname" . }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "app.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}
6.2 Checksum pour redémarrage automatique
# Redémarrer les pods quand ConfigMap/Secret change
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
6.3 Ressources avec defaults
{{- if .Values.resources }}
resources:
{{- toYaml .Values.resources | nindent 2 }}
{{- else }}
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
{{- end }}
7 - Debugging des templates
7.1 Commandes utiles
# Voir le rendu complet
helm template my-release ./my-chart
# Avec des values spécifiques
helm template my-release ./my-chart -f values-prod.yaml
# Debug verbose
helm template my-release ./my-chart --debug
# Voir un seul template
helm template my-release ./my-chart -s templates/deployment.yaml
# Dry-run contre le cluster
helm install my-release ./my-chart --dry-run --debug
7.2 Fonction de debug
# Afficher une valeur pour debug
{{- $debug := toYaml .Values.config -}}
{{- printf "DEBUG: %s" $debug | fail -}}
# Ou avec un commentaire
# DEBUG: {{ .Values.someValue | toJson }}
Résumé
Dans ce chapitre, nous avons maîtrisé :
- Les built-in objects (Values, Release, Chart, etc.)
- Les fonctions et pipelines
- Les structures de contrôle (if, range, with)
- Les templates nommés avec define/include
- Les patterns courants de templating
- Le debugging des templates
Prochaine étape
Dans le prochain chapitre, nous explorerons les Repositories Helm.
→ Chapitre suivant : Repositories Helm