Helm Charts: Kubernetes-pakketbeheer

Kubernetes-implementaties met Helm-pakketbeheer

Helm heeft de toepassingsimplementatie in Kubernetes revolutioneerd door het invoeren van pakketbeheerconcepten die bekend zijn van traditionele besturingssystemen.

Met de groei van Kubernetes-adoptie wordt het steeds uitdagender om complexe toepassingen met tientallen YAML-bestanden te beheren. Helm Charts lossen dit probleem op door alle resources te bundelen in versiebeheerde, aanpasbare pakketten.

software-developer in de natuur Deze mooie afbeelding is gegenereerd door AI model Flux 1 dev.

Helm begrijpen: De Kubernetes-pakketbeheerder

Helm is voor Kubernetes wat apt is voor Debian, yum voor RedHat of Homebrew voor macOS. Het verpakt Kubernetes-toepassingen in Charts – verzamelingen van bestanden die gerelateerde Kubernetes-resources beschrijven. Een enkel Chart kan een volledige toepassingsstack implementeren: webserver, databases, cachinglagen, ingresregels en monitoringcomponenten. Voor mensen die nieuw zijn in Kubernetes, biedt een Kubernetes Cheatsheet essentiële commando’s en concepten om mee te beginnen.

Waarom Helm belangrijk is in moderne DevOps

Complexiteitsvermindering: In plaats van 20+ YAML-bestanden te beheren, beheer je één Chart met aanpasbare waarden.

Herhaalbaarheid: Implementeer identieke configuraties over ontwikkeling, testen en productie met omgevingsspecifieke waardeoverervingen. Dit is vooral waardevol bij het implementeren van complexe microservicesarchitecturen waarbij consistentie belangrijk is.

Versiebeheer: Charts zijn versiebeheerd, wat eenvoudige terugkeer en upgradevolgregistratie mogelijk maakt.

Community-ecosysteem: Tientallen vooraf gebouwde Charts zijn beschikbaar via Artifact Hub (vormerlijk Helm Hub) voor populaire toepassingen zoals PostgreSQL, Redis, NGINX, Prometheus en meer.

Sjabloonkracht: Go-sjablonen maken dynamische resourcegeneratie mogelijk op basis van invoerwaarden, wat duplicatie verminderd.

Helm-architectuur en kernconcepten

Helm 3-architectuur

Helm 3 vereenvoudigde de architectuur door Tiller, het problematische serversidecomponent van Helm 2, te verwijderen:

  • Helm Client: CLI-tool die direct met de Kubernetes API communiceert
  • Chart: Pakketformaat met sjablonen en metadata
  • Release: Een instantie van een Chart die in een Kubernetes-cluster draait
  • Repository: Opslaglocatie voor Charts (HTTP-server of OCI-registry)

Belangrijke componenten van een Helm-Chart

my-app-chart/
├── Chart.yaml          # Chart metadata en versie
├── values.yaml         # Standaard configuratie waarden
├── charts/             # Afhankelijke charts
├── templates/          # Kubernetes resource sjablonen
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── _helpers.tpl    # Sjabloonhelpers
│   └── NOTES.txt       # Post-installatie notities
├── .helmignore         # Bestanden negeren bij het verpakken
├── README.md
└── LICENSE

Je eerste Helm-Chart maken

Een nieuw Chart initialiseren

helm create my-application
cd my-application

Dit genereert een starter Chart met voorbeeldsjablonen voor een implementatie, service en ingre.

Chart.yaml: Metadata definiëren

apiVersion: v2
name: my-application
description: Een productiebereid toepassingschart
type: application
version: 1.0.0        # Chart versie
appVersion: "2.4.1"   # Versie van de toepassing

maintainers:
  - name: Je Team
    email: team@company.com

dependencies:
  - name: postgresql
    version: "12.x.x"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled

Values.yaml: Configuratiebeheer

Het values.yaml-bestand definieert standaardconfiguraties die gebruikers kunnen overschrijven. Deze aanpak schept een scheiding tussen configuratie en sjablonen, waardoor het makkelijker is om verschillende omgevingen (ontwikkeling, testen, productie) te beheren en implementaties aan te passen zonder sjabloonbestanden te wijzigen.

replicaCount: 3

image:
  repository: myapp/backend
  tag: "1.0.0"
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: true
  className: "nginx"
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
  hosts:
    - host: myapp.example.com
      paths:
        - path: /
          pathType: Prefix

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

Sjablonen: Dynamische Kubernetes-manifesten

Sjablonen gebruiken Go-sjabloonnotatie om Kubernetes-resources dynamisch te genereren. Deze sjablonen kunnen elke Kubernetes-resourcegenereren, van eenvoudige Implementaties tot complexe StatefulSets voor stateful toepassingen die persistente opslag vereisen. Voor toepassingen die stabiele identiteiten en persistente volumes nodig hebben, wil je StatefulSets gebruiken in plaats van Implementaties, zoals beschreven in onze gids over StatefulSets en persistente opslag in Kubernetes.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-application.fullname" . }}
  labels:
    {{- include "my-application.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "my-application.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "my-application.selectorLabels" . | nindent 8 }}
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: 8080
          protocol: TCP
        resources:
          {{- toYaml .Values.resources | nindent 10 }}

Sjabloonhelpers (_helpers.tpl)

Maak herbruikbare sjabloonfuncties aan om herhaling te vermijden:

{{/*
Uitbreiden van de naam van het chart.
*/}}
{{- define "my-application.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Creëer een standaard volledig gekwalificeerde appnaam.
*/}}
{{- define "my-application.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 }}

{{/*
Gemeenschappelijke labels
*/}}
{{- define "my-application.labels" -}}
helm.sh/chart: {{ include "my-application.chart" . }}
{{ include "my-application.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

Helm-Chartbeheer: Installatie en operaties

Een Chart installeren

# Installeren vanuit een repository
helm install my-release bitnami/postgresql

# Installeren vanuit een lokale map
helm install my-app ./my-application

# Installeren met aangepaste waarden
helm install my-app ./my-application -f values-production.yaml

# Installeren met inline waardeoverervingen
helm install my-app ./my-application \
  --set replicaCount=5 \
  --set image.tag=2.0.0

Releases upgraden

# Upgraden met nieuwe waarden
helm upgrade my-app ./my-application -f values-production.yaml

# Upgraden met automatische terugkeer bij mislukking
helm upgrade my-app ./my-application --atomic --timeout 5m

# Krachtige resourceupdates
helm upgrade my-app ./my-application --force

Terugkeer en geschiedenis

# Bekijk geschiedenis van de release
helm history my-app

# Terugkeer naar vorige versie
helm rollback my-app

# Terugkeer naar specifieke revisie
helm rollback my-app 3

Testen en debuggen

# Dry-run om gegenereerde manifesten te zien
helm install my-app ./my-application --dry-run --debug

# Sjabloonweergave zonder installatie
helm template my-app ./my-application

# Chart controleren op problemen
helm lint ./my-application

# Release testen met test hooks
helm test my-app

Geavanceerde Helm-functies

Chart-afhankelijkheden

Helm-Charten kunnen afhankelijk zijn van andere Charts, waardoor je complexe toepassingen kunt samenstellen uit herbruikbare componenten. Dit is vooral handig bij het implementeren van microservices die databases, berichtenwachtrijen of andere ondersteunende diensten nodig hebben. Definieer afhankelijkheden in Chart.yaml:

dependencies:
  - name: redis
    version: "17.x.x"
    repository: "https://charts.bitnami.com/bitnami"
    condition: redis.enabled
  - name: postgresql
    version: "12.x.x"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled

Update afhankelijkheden:

helm dependency update ./my-application

Helm Hooks voor levenscyclusbeheer

Hooks worden uitgevoerd op specifieke momenten in de levenscyclus van de release:

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "my-application.fullname" . }}-db-migration
  annotations:
    "helm.sh/hook": pre-upgrade,pre-install
    "helm.sh/hook-weight": "5"
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  template:
    spec:
      containers:
      - name: db-migrate
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        command: ["python", "manage.py", "migrate"]
      restartPolicy: Never

Hooktypes omvatten:

  • pre-install: Voor installatie van resources
  • post-install: Na installatie van alle resources
  • pre-upgrade: Voor upgrade
  • post-upgrade: Na upgrade
  • pre-delete: Voor verwijdering
  • post-delete: Na verwijdering
  • pre-rollback: Voor terugkeer
  • post-rollback: Na terugkeer

Voorwaardelijke logica en stroombeheer

{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "my-application.fullname" . }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  {{- if .Values.ingress.className }}
  ingressClassName: {{ .Values.ingress.className }}
  {{- end }}
  rules:
  {{- range .Values.ingress.hosts }}
  - host: {{ .host | quote }}
    http:
      paths:
      {{- range .paths }}
      - path: {{ .path }}
        pathType: {{ .pathType }}
        backend:
          service:
            name: {{ include "my-application.fullname" $ }}
            port:
              number: {{ $.Values.service.port }}
      {{- end }}
  {{- end }}
{{- end }}

OCI-registryondersteuning: Moderne Chartdistributie

Sinds Helm 3.8 is OCI (Open Container Initiative)-registryondersteuning stabiel, waardoor Charts kunnen worden opgeslagen naast containerbeelden.

Publiceren naar OCI-registry

# Aanmelden bij de registry
helm registry login registry.example.com

# Verpak de chart
helm package ./my-application

# Push naar OCI-registry
helm push my-application-1.0.0.tgz oci://registry.example.com/charts

# Installeer vanuit OCI-registry
helm install my-app oci://registry.example.com/charts/my-application --version 1.0.0

Voordelen van OCI-registries

  • Geïntegreerde opslag: Charts en beelden op één plek
  • Standaard gereedschap: Bestaande registryinfrastructuur gebruiken
  • Beter beveiliging: Gebruik registryauthenticatie en scanning
  • Eenvoudiger beheer: Geen aparte Chartrepositoryserver nodig

Beste praktijken voor productie Helm-Charten

1. Waardestructuur en documentatie

Documenteer alle waarden met commentaar:

# -- Aantal replica's voor de toepassing
replicaCount: 3

# -- Beeldconfiguratie
image:
  # -- Beeldrepository
  repository: myapp/backend
  # -- Beeldpullbeleid
  pullPolicy: IfNotPresent
  # -- Beeldtag (standaard is chart appVersion)
  tag: ""

2. Resourcebeheer

Stel altijd resourceaanvragen en -limieten in:

resources:
  limits:
    cpu: 1000m
    memory: 1Gi
  requests:
    cpu: 500m
    memory: 512Mi

3. Beveiligingscontexten

Definieer beveiligingscontexten voor containers:

securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  fsGroup: 1000
  capabilities:
    drop:
    - ALL
  readOnlyRootFilesystem: true

4. Gezondheidstests

Voeg levensduur- en gereedheidstests toe:

livenessProbe:
  httpGet:
    path: /health
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5

5. ConfigMap en geheimenbeheer

Proper geheimenbeheer is essentieel voor productieimplementaties. Gebruik externe geheimenbeheerders (Sealed Secrets, External Secrets Operator of Vault) in plaats van geheimen op te slaan in waardenbestanden. Dit zorgt ervoor dat gevoelige gegevens zoals databasewoorden, API-sleutels en certificaten veilig worden beheerd:

envFrom:
- secretRef:
    name: {{ include "my-application.fullname" . }}-secrets
- configMapRef:
    name: {{ include "my-application.fullname" . }}-config

6. Schemavalidatie

Maak values.schema.json aan om gebruikersinvoer te valideren:

{
  "$schema": "https://json-schema.org/draft-07/schema#",
  "properties": {
    "replicaCount": {
      "type": "integer",
      "minimum": 1
    },
    "image": {
      "type": "object",
      "properties": {
        "repository": {
          "type": "string"
        },
        "tag": {
          "type": "string"
        }
      },
      "required": ["repository"]
    }
  },
  "required": ["image"]
}

7. NOTES.txt voor gebruikersinstructies

Geef instructies na installatie:

1. Haal de toepassings-URL op door te voeren:
{{- if .Values.ingress.enabled }}
  https://{{ (index .Values.ingress.hosts 0).host }}
{{- else if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "my-application.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- end }}

2. Monitor de implementatie:
  kubectl --namespace {{ .Release.Namespace }} get pods -l "app.kubernetes.io/name={{ include "my-application.name" . }}"

Helm-Charttesten en CI/CD-integratie

Charttesten met chart-testing (ct)

# Installeer chart-testing
brew install chart-testing

# Lint charts
ct lint --config ct.yaml

# Installeer en test charts
ct install --config ct.yaml

Voorbeeld GitHub Actions

name: Helm Chart CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Set up Helm
        uses: azure/setup-helm@v3
        with:
          version: 3.12.0

      - name: Set up chart-testing
        uses: helm/chart-testing-action@v2

      - name: Lint charts
        run: ct lint --config ct.yaml

      - name: Create kind cluster
        uses: helm/kind-action@v1

      - name: Install charts
        run: ct install --config ct.yaml

GitOps met Helm: ArgoCD en Flux

GitOps-tools zoals ArgoCD en Flux integreren naadloos met Helm-Charten, waardoor declaratieve, geautomatiseerde implementaties mogelijk worden. Deze tools controleren je Git-repository op veranderingen en synchroniseren automatisch Helm-releases, waardoor continue implementatie eenvoudig is. Voor complexe microservicesarchitecturen, overweeg hoe gedistribueerde transactiepatronen zoals de Saga-patroon kunnen helpen bij het beheren van consistentie over services die via Helm zijn geïmplementeerd.

ArgoCD-toepassing

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-application
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/my-app-chart
    targetRevision: main
    path: charts/my-application
    helm:
      valueFiles:
        - values-production.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

Flux HelmRelease

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: my-application
  namespace: flux-system
spec:
  interval: 5m
  chart:
    spec:
      chart: my-application
      version: '1.x.x'
      sourceRef:
        kind: HelmRepository
        name: my-charts
  values:
    replicaCount: 5
    image:
      tag: "2.0.0"

Probleemoplossing van veelvoorkomende Helm-issues

Probleem: Mislukte upgrade vastgelopen in wachtrij

# Controleer releasestatus
helm list --all-namespaces

# Bekijk release details
helm status my-app -n namespace

# Forceer verwijdering indien nodig (gebruik met voorzichtigheid)
kubectl delete secret -n namespace -l owner=helm,name=my-app

Probleem: Sjabloonweergavefouten

# Debuggen van sjabloonweergave
helm template my-app ./my-application --debug

# Valideer tegen Kubernetes
helm template my-app ./my-application | kubectl apply --dry-run=client -f -

Probleem: Waarden niet toegepast

# Controleer samengevoegde waarden
helm get values my-app

# Toon alle berekende waarden
helm get values my-app --all

Helm-ecosysteem en tools

Het Helm-ecosysteem bevat tal van tools die zijn functionaliteiten uitbreiden en integreren met andere Kubernetes-technologieën. Wanneer toepassingen worden geïmplementeerd die geavanceerde netwerkfuncties zoals service-to-service communicatie, verkeerbeheer en beveiligingsbeleid vereisen, overweeg het integreren met een Service Mesh met Istio en Linkerd, die kunnen worden geïmplementeerd en beheerd via Helm-Charten.

Essentiële tools

  • Helmfile: Declaratief spec voor het implementeren van Helm-Charten
  • Helm Diff: Voorvertoning van veranderingen voor upgrade
  • Helm Secrets: Beheer van geheimen met SOPS
  • Nova: Vind verouderde Helm-Charten
  • Pluto: Detecteer verouderde Kubernetes-API’s

Voorbeeld Helmfile

repositories:
  - name: bitnami
    url: https://charts.bitnami.com/bitnami

releases:
  - name: postgresql
    namespace: database
    chart: bitnami/postgresql
    version: 12.x.x
    values:
      - postgresql:
          auth:
            database: myapp
            username: appuser

  - name: my-app
    namespace: production
    chart: ./charts/my-application
    values:
      - values-production.yaml
    needs:
      - database/postgresql

De toekomst van Helm

Het Helm-ecosysteem blijft evolueren:

  • OCI-Natief: Volledige overgang naar OCI-registries als standaard
  • Verbeterde beveiliging: Betere geheimenbeheer en ondertekening
  • Prestaties: Snelere weergave en installatie voor grote Charts
  • WASM-ondersteuning: WebAssembly voor Chartplugins en uitbreidingen
  • Betere validatie: Versterkte schemavalidatie en beleidsuitvoering

Conclusie

Helm is geworden tot de standaard voor Kubernetes-pakketbeheer, en het beheersen ervan is essentieel voor moderne DevOps-praktijken. Door de structuur van Charten, sjablonering, waardenbeheer en beste praktijken te begrijpen, kun je onderhoudbare, beveiligde en schaalbare Kubernetes-implementaties maken.

Begin met eenvoudige Charts, voeg geleidelijk geavanceerde functies zoals hooks en afhankelijkheden toe, en integreer met GitOps-tools voor productiegraad infrastructuur. Het Helm-community biedt duizenden vooraf gebouwde Charts, maar de echte kracht komt van het maken van aangepaste Charts die afgestemd zijn op de behoeften van je organisatie. Of je nu stateless toepassingen implementeert of stateful workloads die persistente opslag vereisen, vereenvoudigt Helm de complexiteit van Kubernetes-resourcebeheer. Voor teams die nieuwe Kubernetes-clusters instellen, overweeg Kubernetes installeren met Kubespray of Kubernetes-distributies zoals k3s of MicroK8s voor ontwikkelomgevingen. Als je beoordeelt welke distributie past bij je homelab of kleine clusterbehoeften, zie onze comprehensieve vergelijking van Kubernetes-distributies voor gedetailleerde analyse.