Helm — comandi e troubleshooting
Helm fa due cose: renderizza template in manifest Kubernetes e tiene traccia di cosa ha applicato, in un Secret nel namespace della release. Quasi tutti i problemi si spiegano con una delle due: o il template produce qualcosa di diverso da quello che pensi, o lo stato registrato non corrisponde a quello che c’è nel cluster.
Repository
helm repo add bitnami https://charts.bitnami.com/bitnamihelm repo add prometheus-community https://prometheus-community.github.io/helm-chartshelm repo listhelm repo updatehelm repo remove <nome>
helm search repo <parola>helm search repo <parola> --versions # tutte le versioni disponibilihelm search hub <parola> # cerca su Artifact Hubhelm repo update aggiorna l’indice locale: senza, helm search e helm install continuano a vedere le versioni del giorno in cui hai aggiunto il repo.
Ambienti air-gapped — scaricare il chart per portarlo dentro:
helm pull bitnami/redis --version 18.1.5helm pull bitnami/redis --version 18.1.5 --untar --untardir ./chartshelm show values bitnami/redis --version 18.1.5 > values-default.yamlhelm show chart bitnami/redishelm show readme bitnami/redisRegistry OCI, il formato ormai standard:
helm registry login registry.example.it -u <user>helm pull oci://registry.example.it/charts/mychart --version 1.0.0helm push mychart-1.0.0.tgz oci://registry.example.it/chartshelm install myrel oci://registry.example.it/charts/mychart --version 1.0.0Install e upgrade
helm install <release> <chart> -n <ns>helm install <release> <chart> -n <ns> --create-namespacehelm install <release> ./chart-locale -n <ns>
helm upgrade <release> <chart> -n <ns>helm upgrade --install <release> <chart> -n <ns> # idempotente: installa se non c'èhelm upgrade --install è la forma da usare in pipeline: stesso comando alla prima esecuzione e a tutte le successive.
Flag che contano davvero:
helm upgrade --install myrel ./chart -n myns \ --values values-prod.yaml \ --set image.tag=1.4.2 \ --atomic \ --timeout 10m \ --wait--atomic— se l’upgrade fallisce, fa rollback automatico allo stato precedente. Implica--wait.--wait— aspetta che le risorse siano pronte prima di dichiarare successo.--timeout— quanto aspettare; il default di 5 minuti è spesso corto per StatefulSet con PVC.--create-namespace— crea il namespace se manca.--dry-run— non applica nulla, mostra cosa farebbe.--force— sostituisce le risorse invece di aggiornarle. Da usare con cautela: ricrea gli oggetti e può causare downtime.--reset-values/--reuse-values— vedi sotto, è la fonte di sorprese più comune.
Values: la parte che genera più errori
helm show values <chart> > values-default.yaml # tutti i default documentatihelm get values <release> -n <ns> # solo i values sovrascritti da tehelm get values <release> -n <ns> --all # values effettivi, default inclusiPrecedenza, dalla più debole alla più forte: values.yaml del chart → file passati con -f nell’ordine in cui compaiono → --set → --set-string / --set-file.
helm upgrade myrel ./chart -n myns \ -f values-common.yaml \ -f values-prod.yaml \ --set replicaCount=3 \ --set-string image.tag="1.4" # forza stringa: evita che 1.4 diventi floatSintassi di --set per i casi non banali:
--set nodeSelector."kubernetes\.io/hostname"=worker-0 # punti nelle chiavi vanno escapati--set tolerations[0].key=dedicated # array per indice--set 'ingress.hosts={a.example.it,b.example.it}' # lista inline--set-file config.script=./setup.sh # contenuto di un file in un valueIl comportamento che sorprende tutti: dalla versione 3, helm upgrade riusa i values della release precedente solo per i valori che non ridefinisci, ma se passi -f con un file diverso i valori assenti tornano ai default del chart. Per essere espliciti:
helm upgrade myrel ./chart -n myns --reuse-values --set image.tag=1.4.3 # parte dai values attualihelm upgrade myrel ./chart -n myns --reset-values -f values-prod.yaml # riparte dai default del chartSe non specifichi né l’uno né l’altro e usi solo --set, Helm si comporta come --reuse-values. Con -f, no. In pipeline conviene sempre passare il file completo ed essere espliciti con --reset-values, così il risultato non dipende dalla storia della release.
Ispezionare una release
helm list -n <ns>helm list -A # tutti i namespacehelm list -A --pending # release bloccate in transizionehelm list -A --failedhelm status <release> -n <ns>helm history <release> -n <ns>helm history mostra le revisioni con stato e descrizione: è il primo comando da lanciare quando “ieri funzionava”.
helm get manifest <release> -n <ns> # i manifest realmente applicatihelm get notes <release> -n <ns>helm get hooks <release> -n <ns>helm get all <release> -n <ns>helm get manifest è la verità: mostra cosa Helm ha mandato all’API server, dopo il rendering dei template. Confrontarlo con quello che c’è nel cluster individua subito le modifiche fatte a mano fuori da Helm.
helm get manifest myrel -n myns > applied.yamloc -n myns get deploy myapp -o yaml > actual.yamldiff <(yq '.spec.template.spec.containers[0].image' applied.yaml) \ <(yq '.spec.template.spec.containers[0].image' actual.yaml)Dove Helm tiene lo stato:
oc -n <ns> get secret -l owner=helmoc -n <ns> get secret sh.helm.release.v1.<release>.v<N> -o jsonpath='{.data.release}' | \ base64 -d | base64 -d | gunzip | jq .infoIl doppio base64 non è un refuso: il payload è compresso e codificato due volte.
Rollback
helm history <release> -n <ns>helm rollback <release> -n <ns> # alla revisione precedentehelm rollback <release> <N> -n <ns> # a una revisione specificahelm rollback <release> <N> -n <ns> --wait --timeout 10mIl rollback crea una nuova revisione che riporta i manifest a quelli della revisione scelta. Non cancella la storia: dopo un rollback dalla 5 alla 3, ti ritrovi con la revisione 6 identica alla 3.
Il numero di revisioni conservate si controlla in fase di upgrade:
helm upgrade myrel ./chart -n myns --history-max 10Debug dei template
Il comando più utile dell’intero toolkit:
helm template <release> <chart> -n <ns> -f values-prod.yamlhelm template <release> <chart> -n <ns> -f values-prod.yaml --debughelm template <release> <chart> -n <ns> -s templates/deployment.yaml # un solo filehelm template renderizza in locale senza toccare il cluster: è dove si vedono i valori sbagliati, gli if che non scattano e le indentazioni rotte.
helm install myrel ./chart -n myns --dry-run --debughelm upgrade myrel ./chart -n myns --dry-run --debug--dry-run fa il rendering e valida contro l’API server, quindi intercetta anche campi inesistenti e CRD mancanti. helm template da solo no. Per la validazione lato server:
helm template myrel ./chart | oc apply --dry-run=server -f -Vedere le differenze prima di applicare, con il plugin più utile in circolazione:
helm plugin install https://github.com/databus23/helm-diffhelm diff upgrade myrel ./chart -n myns -f values-prod.yamlhelm diff upgrade myrel ./chart -n myns -f values-prod.yaml --context 3helm diff rollback myrel 3 -n mynsValidazione del chart e delle sue convenzioni:
helm lint ./charthelm lint ./chart -f values-prod.yaml --strictChart locale e dipendenze
Struttura minima:
mychart/├── Chart.yaml # nome, version, appVersion, dependencies├── values.yaml # valori di default├── templates/ # i manifest con i placeholder│ ├── _helpers.tpl # funzioni e nomi riusabili│ └── NOTES.txt # messaggio post-install└── charts/ # dipendenze scaricatehelm create mycharthelm dependency list ./mycharthelm dependency update ./mychart # scarica le dipendenze e scrive Chart.lockhelm dependency build ./mychart # usa Chart.lock senza riaggiornarehelm package ./mycharthelm package ./mychart --version 1.2.0 --app-version 2.4.1update risolve i vincoli e riscrive il lock, build si attiene al lock esistente. In pipeline si usa build, per avere risultati riproducibili.
Distinzione da tenere a mente: version è la versione del chart, appVersion è quella dell’applicazione che il chart installa. Sono indipendenti.
Hook
annotations: "helm.sh/hook": pre-upgrade,pre-install "helm.sh/hook-weight": "-5" "helm.sh/hook-delete-policy": before-hook-creation,hook-succeededFasi disponibili: pre-install, post-install, pre-upgrade, post-upgrade, pre-delete, post-delete, pre-rollback, post-rollback, test.
Il peso ordina gli hook della stessa fase, dal più basso al più alto. La hook-delete-policy decide se il Job resta nel cluster: senza hook-succeeded ti ritrovi decine di Job completati.
helm get hooks <release> -n <ns>Un hook che fallisce blocca l’upgrade: se una release resta in pending-upgrade, il primo posto dove guardare sono i Job di hook nel namespace.
oc -n <ns> get jobsoc -n <ns> logs job/<hook-job>Test della release:
helm test <release> -n <ns>helm test <release> -n <ns> --logsRelease bloccate e recupero
Sintomo classico: helm list mostra pending-install, pending-upgrade o pending-rollback e ogni comando successivo si rifiuta con “another operation is in progress”.
Succede quando il processo Helm è stato interrotto (pipeline killata, timeout della shell) lasciando il Secret di stato a metà.
helm list -A --pendinghelm history <release> -n <ns>Recupero, in ordine di invasività:
# 1. rollback all'ultima revisione buonahelm rollback <release> <N-buona> -n <ns>
# 2. se il rollback si rifiuta, il plugin dedicatohelm plugin install https://github.com/Nightapes/helm-mapkubeapisoc -n <ns> get secret -l owner=helm,name=<release>
# 3. ultima spiaggia: cancellare il Secret della revisione bloccataoc -n <ns> delete secret sh.helm.release.v1.<release>.v<N-bloccata>Il punto 3 fa dimenticare a Helm l’operazione in corso, ma non tocca le risorse nel cluster: dopo, verifica con helm get manifest che lo stato registrato corrisponda alla realtà.
Altri errori ricorrenti e cosa significano:
| Errore | Causa | Rimedio |
|---|---|---|
cannot re-use a name that is still in use | release esistente, anche fallita | helm list -a -n <ns>, poi upgrade o uninstall |
has no deployed releases | la prima install è fallita | helm uninstall e reinstalla |
field is immutable | modifica a selector o a un campo non aggiornabile | --force, o delete e reinstall della risorsa |
rendered manifests contain a resource that already exists | risorsa creata fuori da Helm | adottala con le annotation meta.helm.sh/release-name e -namespace più la label app.kubernetes.io/managed-by: Helm |
UPGRADE FAILED: timed out waiting for the condition | --wait scaduto, pod non pronti | oc get events, oc describe pod — il problema è applicativo |
Adozione di una risorsa preesistente:
oc -n <ns> annotate <kind>/<nome> meta.helm.sh/release-name=<release> --overwriteoc -n <ns> annotate <kind>/<nome> meta.helm.sh/release-namespace=<ns> --overwriteoc -n <ns> label <kind>/<nome> app.kubernetes.io/managed-by=Helm --overwriteDisinstallazione
helm uninstall <release> -n <ns>helm uninstall <release> -n <ns> --keep-history # mantiene lo storico per un futuro rollbackhelm uninstall <release> -n <ns> --waitI PVC creati da un StatefulSet non vengono rimossi da Helm: vanno cancellati a mano.
oc -n <ns> get pvcSpecificità OpenShift
Le SecurityContextConstraints sono la causa più frequente di chart pubblici che non partono: molti impostano runAsUser fisso o fsGroup, incompatibili con l’SCC restricted-v2 che assegna gli UID dal range del namespace.
oc get sccoc -n <ns> get saoc adm policy add-scc-to-user nonroot-v2 -z <serviceaccount> -n <ns>Nei values dei chart Bitnami e simili, la soluzione pulita è svuotare i campi invece di aggiungere privilegi:
podSecurityContext: fsGroup: nullcontainerSecurityContext: runAsUser: null runAsGroup: nullVerificare cosa impedisce l’avvio:
oc -n <ns> get events --sort-by=.lastTimestamp | tail -20oc -n <ns> describe pod <pod> | sed -n '/Events/,$p'oc -n <ns> get pod <pod> -o jsonpath='{.metadata.annotations.openshift\.io/scc}{"\n"}'Se il chart crea Ingress e ti serve una Route, quasi tutti i chart supportano annotation custom; in alternativa OpenShift genera la Route automaticamente dall’Ingress.
Comandi di servizio
helm versionhelm env # dove Helm cerca cache, config e datahelm plugin listhelm completion bash > /etc/bash_completion.d/helm