In questi giorni ho fatto una scoperta che mi ha deliziato. Gli hook dei chart di Helm

Fatalità con uno dei casi tipici indicati direttamente nella documentazione. La necessità di inizializzare un database prima di eseguire il deployment vero e proprio dell’applicazione (verificare se il db esiste, a che versione è, aggiornare lo schema ecc…).

Gli hook disponibili

Gli hook disponibili sono diversi (dalla doc ufficiale)

Annotation Value Description
pre-install Executes after templates are rendered, but before any resources are created in Kubernetes
post-install Executes after all resources are loaded into Kubernetes
pre-delete Executes on a deletion request before any resources are deleted from Kubernetes
post-delete Executes on a deletion request after all of the release’s resources have been deleted
pre-upgrade Executes on an upgrade request after templates are rendered, but before any resources are updated
post-upgrade Executes on an upgrade request after all resources have been upgraded
pre-rollback Executes on a rollback request after templates are rendered, but before any resources are rolled back
post-rollback Executes on a rollback request after all resources have been modified
test Executes when the Helm test subcommand is invoked (view test docs)

Il mio caso del database

Il chart di helm viene usato sia in installazione che update quindi ho usato gli hooks pre-install e pre-upgrade per fare il check del database e l’eventuale aggiornamento dello schema.

Ecco l’esempio

Il core del mio hook è un job che viene eseguito prima dell’installazione o dell’aggiornamento del chart. Ecco un esempio di come appare il job:

apiVersion: batch/v1
kind: Job
metadata:
  name: ...
  labels:
    ...
    app.kubernetes.io/component: db-init
  annotations:
    "helm.sh/hook": pre-install,pre-upgrade
    "helm.sh/hook-weight": "1"
    "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec: ...

Maaa…. Altro problema! Siccome il job fa uso di un secret per scaricare l’immagine da un container registry privato, ho dovuto aggiungere anche un imagePullSecrets al job e di conseguenza installarlo nel cluster con un hook pre-install e pre-upgrade con weight 0 (così da essere eseguito prima del job vero e proprio).

apiVersion: v1
kind: Secret
metadata:
  name: {{ $secretName }}
  namespace: {{ .Release.Namespace }}
  labels:
    ...
  annotations:
    "helm.sh/hook": pre-install,pre-upgrade
    "helm.sh/hook-weight": "0"

Conclusioni

Semplici e pratici gli hook di helm mi hanno permesso quindi di “preparare” in anticipo il terreno (in questo caso il database) prima di eseguire il deployment vero e proprio dell’applicazione che, in un deployment tradizionale, avrebbe fallito miseramente perché un Job senza hook non avrebbe potuto essere seguito in modo garantito prima del resto e quindi… patatrac!