Helm is een package-manager voor Kubernetes. Helm gebruikt een packageformaat genaamd Charts. Een Chart is een verzameling bestanden die een samenhangende set Kubernetes-resources beschrijft. Net zoals apt het installeren en beheren van software vereenvoudigt op Debian/Ubuntu, doet Helm dat voor Kubernetes-resources. In deze handleiding laten we zien hoe je zelf een Helm Chart maakt en gebruikt.
- Installeer voor je begint de Helm package manager en kubectl.
- We gaan voor deze handleiding uit van enige bekendheid met Kubernetes, zoals het 'maken van Kubernetes Objects’, labels en selectors en het gebruik van bestaande Helm Charts.
Een Helm-Chart handmatig aanmaken
Stap 1
Een Helm Chart gebruikt een specifieke folderstructuur en bestanden. Je kunt deze handmatig aanmaken, of automatisch met “helm create”. Dit laatste is het snelst en eenvoudigst en werkt als volgt:
helm create demo-Chart
Met dit commando maak je automatisch een map aan met de volgende bestanden:
demo-Chart
├── Chart.yaml
├── values.yaml
├── Charts/
└── templates/
├── _helpers.tpl
├── NOTES.txt
├── deployment.yaml
├── service.yaml
├── ingress.yaml
├── hpa.yaml
├── serviceaccount.yaml
└── tests/
└── test-connection.yaml
Stap 2
Vanaf hier pas je de bestanden aan waar nodig. Open om te beginnen “Chart.yaml”, bijvoorbeeld:
nano demo-Chart/Chart.yaml
Pas de inhoud aan naar wens en sla je wijzigingen op (ctrl + x > y > enter), bijvoorbeeld:
apiVersion: v2
name: demo-Chart
description: Een Helm-Chart voor Nginx
type: application
version: 0.1.0
appVersion: "1.29.1"
kubeVersion: ">=1.24.0-0"
maintainers:
- name: Jouw Naam
email: jij@example.com
Dit bestand bevat metadata voor je Chart, zoals de naam, versie en beschrijving. De vereiste velden in het Chart.yaml-bestand zijn apiVersion, name en version, die respectievelijk de API-versie van de Chart, de naam van de Chart en de versie van de Chart bepalen. De overige velden zijn optioneel en kunnen worden gebruikt om extra informatie over de Chart op te geven.
De juiste appVersion kun je achterhalen door bijvoorbeeld de huidige softwareversie te controleren in een bestaande Chart op Artifact Hub.
De meestgebruikte velden in Chart.yaml zijn als volgt:
apiVersion: v2 # De API-versie van de Chart, altijd "v2" (vereist)
name: demo-Chart # De naam van de Chart (vereist)
description: "Korte beschrijving" # Een omschrijving van je project
type: application # Application of Library, zie de default comments in Chart.yaml
version: 0.1.0 # De versie van de Chart (SemVer, vereist)
appVersion: "8.0" # Appversie (vrij formaat)
kubeVersion: ">=1.24.0-0" # Compatibel Kubernetes-versie
keywords: "Software A, B" # Een lijst met trefwoorden over je project (optioneel)
home: https://... # Homepage van je project
sources: # URLs die verwijzen naar broncode
- https://...
maintainers: # Optioneel de gegevens van de maintainer(s) van de Helm Chart
- name: ...
email: ...
url: ...
engine: gotpl # De naam van de sjablonenengine (standaard is gotpl)
icon: https://.../icon.png # Een URL naar een SVG- of PNG-afbeelding die als icoon moet worden gebruikt.
deprecated: 0 # Of deze Chart verouderd is (boolean)
Stap 3
Het volgende bestand “values.yaml” is een van de belangrijkste: hierin geef je de waardes op van veel variabelen. In ieder bestand waar de variabele vervolgens voorkomt, wordt de waarde ervan automatisch ingevuld door terug te verwijzen naar de variabele in het values.yaml bestand, bijvoorbeeld: {{ .Values.replicaCount }}. Hier geeft .Values aan dat de variabele zich bevindt in values.yaml en replicaCount dat het om de waarde van de variabele replicaCount gaat.
Het voordeel van het gebruik van values.yaml is dat je vervolgens niet in andere .yaml-files aanpassingen hoeft te maken wanneer je de waardes van variabelen wijzigt maar dit vanuit één enkel bestand doet: values.yaml. Open nu eerst values.yaml:
nano demo-Chart/values.yaml
Pas het bestand naar wens aan, bijvoorbeeld voor een minimale Nginx-deployment values.yaml aan als volgt (zonder de comments) en sla je wijzigingen op (ctrl + x > y > enter). Hierbij gaan we uit van een Nginx setup met bijbehorende service.
deploymentName: nginx
# Een korte, herkenbare naam die je ook als label/selector en resource-namen gebruikt.
replicaCount: 1
# Aantal pods. Voor stateful DB's meestal 1 (tenzij je replication/clustering regelt).
image:
repository: nginx
# De naam van de container image naam. Er zijn drie opties:
# - De naam zoals in Docker Hub (e.g. de mysql in https://hub.docker.com/_/mysql): "mysql"
# - Een volledig docker.io adres: "docker.io/library/mysql"
# - Een private registry, bijvoorbeeld: "registry.example.com/team/mysql"
tag: "1.29.1"
# Versie van de image. Voor productieomgevingen is een vaste tag aanbevolen, bijv 1.29.1.
# Alternatief kun je ook "latest" gebruiken.
pullPolicy: IfNotPresent
# - Always: haalt elke keer dat de pod opnieuw gestart wordt de image binnen.
# - IfNotPresent: haalt alleen de image binnen als die lokaal niet aanwezig is (default).
# - Never: haal de image nooit binnen (image MOET lokaal staan; deze optie is zelden nodig).
service:
name: nginx
# Kubernetes Service-naam (DNS entry binnen cluster).
type: ClusterIP
# Kies een van de volgende Service-types:
# - ClusterIP: intern bereikbaar (cluster-only). De meest veilige optie voor databases.
# - NodePort: extern via iedere node:port; simpel maar beperkt.
# - LoadBalancer: externe IP via cloud-LB; gebruik dit enkel als de service echt van buiten benaderbaar moet zijn.
port: 80 # De poort waarop de service luistert.
protocol: TCP # TCP, UDP
Stap 4
In de map ‘templates’ staan template/sjabloonbestanden voor de Kubernetes-resources die door je Chart worden beheerd. Open het bestand deployment.yaml, bijvoorbeeld:
nano demo-Chart/templates/deployment.yaml
In het standaard aangemaakte bestand zijn een hoop opties opgenomen, zie ook de eerder genoemde handleiding Kubernetes Objects maken.
Voor een simpele Nginx-deployment volstaat een layout zoals hieronder. Er staan de nodige waardes in met een structuur als {{ .Values.deploymentName }}. Hier wordt de waarde dus automatisch ingevuld op basis van de waarde van de deploymentName zoals gedefinieerd in values.yaml, zie stap 3.
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.deploymentName }}
labels:
app.kubernetes.io/name: {{ .Values.deploymentName }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: {{ .Values.deploymentName }}
template:
metadata:
labels:
app.kubernetes.io/name: {{ .Values.deploymentName }}
spec:
containers:
- name: nginx
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
Stap 5
In stap 3 zijn ook de waardes voor een nginx-service opgenomen. Voor services is er al een voorbeeld te vinden in demo-Chart/templates/services.yaml:
nano demo-Chart/templates/services.yaml
Dankzij de configuratie in values.yaml kun je ook in services.yaml verwijzen naar values.yaml, bijvoorbeeld voor een simpele Nginx-setup als volgt:
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.service.name }}
labels:
app.kubernetes.io/name: {{ .Values.deploymentName }}
spec:
type: {{ .Values.service.type }}
selector:
app.kubernetes.io/name: {{ .Values.deploymentName }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.port }}
protocol: {{ .Values.service.protocol }}
Stap 6 - optioneel
Tot zover gingen we uit van een minimale setup. Mocht je echter ook een ingress toe willen voegen dan kan dat ook door de benodigde variabelen aan values.yaml toe te voegen:
nano demo-Chart/values.yaml
Pas het bestand naar wens aan, bijvoorbeeld als volgt (maar dan zonder de comments) en sla je wijzigingen op (ctrl + x > y > enter).
ingress:
enabled: true # schakelt de ingress resource in
ingressClassName: nginx # laat deze optie weg als je enkel annotaties gebruikt, bijvoorbeeld zoals hieronder.
annotations: # optioneel; verwijder deze optie als je de ingressClassName gebruikt
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
hosts:
- host: example.local # de hostname van je Nginx-setup
paths:
- path: /
pathType: Prefix
# overschrijf optioneel de waarde voor de serviceName en servicePort (uit de service hierboven)
# serviceName: nginx-demo
# servicePort: 80
# Optioneel met TLS; er is hier wel een Secret voor nodig.
tls:
- hosts:
- example.local
secretName: example-local-tls
Voor het gebruik van Secrets zijn er meerdere opties, zie bijvoorbeeld ook deze Nginx Chart, of onze Traefik-handleiding voor een voorbeeld hoe je een Secret aanmaakt en gebruikt in een Kubernetes-Object.
De standaard aanwezige demo-Chart/templates/ingress.yaml file is zo handig in elkaar gestoken dankzij if statements dat, tenzij je de ingress inschakelt in values.yaml en de bijbehorende variabelen invult die niet gebruikt wordt en verder alle opties automatisch worden ingevuld. Voor de volledigheid is hieronder de standaard inhoud van ingress.yaml.
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "demo-Chart.fullname" . }}
labels:
{{- include "demo-Chart.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.ingressClassName }}
ingressClassName: {{ . }}
{{- 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 }}
{{- with .pathType }}
pathType: {{ . }}
{{- end }}
backend:
service:
name: {{ include "demo-Chart.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}
Stap 7
Er zijn nog enkele bestanden in de templates-folder terug te vinden, zoals hpa.yaml (nog niet ondersteund op ons platform) en serviceaccount.yaml. Deze zijn ook dusdanig ingestoken dat ze niet gebruikt worden tenzij je in values.yaml anders hebt aangegeven. Je bent vrij NOTES.txt, hpa.yaml en serviceaccount.yaml te verwijderen. Laat echter wel _helpers.tpl staan: hier staan kleine snippets in die je in andere bestanden weer kunt aanroepen zoals {{ include "demo-Chart.name" . }}.
Er zijn nu geen verdere aanpassingen voor nodig en je kunt nu direct verder met het installeren van je Helm Chart.
De Helm Chart installeren en beheren
De Helm Chart installeren
Er zijn een aantal opties om een Helm Chart (i.e. je Helm release) te installeren. We beginnen met de eenvoudigste en gaan ervan uit dat je je op command-line (ongeacht OS) in de map waarin de Helm Chart is aangemaakt bevindt (/demo-Chart/ in dit voorbeeld) Meer informatie over het helm install commando vind je hier.
helm install nginx . -f values.yaml
Voeg optioneel -n namespace toe aan het commando en pas ‘namespace’ aan naar een gewenste naam. Dit bepaalt in welke namespace de Helm Chart wordt geïnstalleerd. Dit is optioneel en hiervoor is wel een bestaande namespace nodig (kubectl create ns namespacenaam).
In ons voorbeeld zijn we niet uit gegaan van een setup met gevoelige wachtwoorden. Mocht je daar echter gebruik van maken dan zijn er een aantal opties om die aan te bieden (in de voorbeelden gaan we uit van een mysql-setup):
Met een Secret (voor productieomgevingen):
helm install mysql-demo \
--set mysql.existingSecret=mysql-prod-Secret \
--set mysql.database=mydb
Het maken van Secrets valt buiten de scope van deze handleiding, maar een voorbeeld van het maken en gebruik van Secrets vind je bijvoorbeeld in onze Traefik-handleiding.
Inline wachtwoorden (voor testomgevingen):
helm install mysql-demo \
--set mysql.rootPassword="$(openssl rand -base64 24)" \
--set mysql.password="$(openssl rand -base64 24)" \
--set mysql.user=appuser
Je Helm release controleren
Alle releases op je cluster zie je eenvoudig terug met het commando:
helm list
De output ziet er als volgt uit (let op de scroll balk):
NAME NAMESPACE REVISION UPDATED STATUS Chart APP VERSION
mysql-1670416172 default 1 2022-12-07 13:29:33.9111825 +0100 STD deployed mysql-9.4.4 8.0.31
Specifiekere informatie vergelijkbaar met de output van het 'helm install'-commando vraag je op met:
helm status releasename
Uiteraard kun je ook individuele componenten van je release controleren met vertrouwde kubectl-commando's, bijvoorbeeld:
kubectl get deployment
Vergeet niet als je gebruik maakt van een namespace (aanbevolen) om -n namespacenaam toe te voegen aan het commando.
Je Helm release verwijderen
Een release verwijder je even eenvoudig als dat je hem installeert:
helm uninstall releasename
Vervang hierbij 'releasename' door de naam van de release zoals zichtbaar onder 'NAME' in de output van het 'helm list'-commando.
Optioneel kun je de flag --keep-history toevoegen. Dit is een handige optie om de informatie over de release te behouden:
helm uninstall releasename --keep-history
Je kunt dan later de history van de release 'releasename' terugbekijken met het commando:
helm history releasename
Helm gaat zelfs nog een stapje verder: je kunt met deze informatie ook een release na de-installatie weer terugrollen met het commando:
helm rollback releasename revision
Het revision nummer zie je terug in de output van het helm history commando.
Hiermee zijn we aan het eind gekomen van deze handleiding over het maken van Helm Charts. In een toekomstige update breiden we deze verder uit met aanvullende componenten zoals secrets, persistent volumes, etc.