Aller au contenu principal

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

ObjetDescription
.ValuesValeurs du values.yaml et overrides
.ReleaseInformations sur la release
.ChartContenu du Chart.yaml
.FilesAccès aux fichiers du chart
.CapabilitiesInformations sur le cluster
.TemplateInformations 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


← Retour à la table des matières