Helm Cheatsheet

Last Updated: 2024-03-03

Talking to an OCI registry

Starting from Helm v3.8.0, OCI support is enabled by default.

Image name in the registry: <domain>/<project>/<repository>:<tag>.

# login
$ helm registry login -u admin xx.xx.xx.xx
Login Succeeded

# push
$ helm push mychart-0.1.0.tgz oci://localhost:5000/helm-charts

# pull from an OCI registry
$ helm pull oci:// --version 1.2.3

Note for Harbor users: there's no /v2 in the uri.

Talking to a K8s Cluster

Use --kubeconfig=KUBECONFIG when your kubeconfig is not at the default location.

Lifecycle: Install / Uninstall / Upgrade / Rollback

# Install bar/baz from the repo and name it foo
$ helm install foo bar/baz

# Generate a name
$ helm install bar/baz --generate-name

# Install from an unpacked chart dir
$ helm install foo /path/to/baz

# Install from a full url
$ helm install foo https://example.com/charts/foo-1.2.3.tgz

# Install a local chart archive
$ helm install foo foo-0.1.1.tgz

# Uninstall
$ helm uninstall foo
$ helm uninstall foo --keep-history

# Upgrade
$ helm upgrade foo [RELEASE] [CHART] [flags]

# If something goes wrong, rollback manually
$ helm rollback $CHART -n $NAMESPACE --kubeconfig /path/to/kubeconfig


# List all deployed releases
$ helm list

# Include uninstalled releases
$ helm list --all

# List releases in all name spaces
$ helm list --all-namespaces

# If you have multiple clusters/kubeconfigs
$ helm list --kubeconfig=KUBECONFIG

# Check status
$ helm status $RELEASE

# Print out metadata and all yamls of the chart
$ helm get all $RELEASE -n $NAMESPACE --kubeconfig /path/to/kubeconfig

# Or just print part of the info
$ helm get hooks $RELEASE      # download all hooks for a named release
$ helm get manifest $RELEASE   # download the manifest for a named release
$ helm get notes $RELEASE      # download the notes for a named release
$ helm get values $RELEASE     # download the values file for a named release

# Check history of a chart
$ helm history $RELEASE -n $NAMESPACE --kubeconfig /path/to/kubeconfig

# Check helm envs
$ helm env


# Create a folder with common files.
$ helm create $CHART

# Validate and format.
$ helm lint $CHART

# Package the chart up for distribution.
# This creates a .tgz that is ready for `helm install`.
$ helm package $CHART

# List dependencies of a chart.
$ helm dependency list $CHART

# Inspect the content of a chart
$ helm show all $CHART

List all resources managed by the helm

Use label selector with label app.kubernetes.io/managed-by=Helm:

$ kubectl get all --all-namespaces -l='app.kubernetes.io/managed-by=Helm'

Chart File Structure

  charts/       # dependent charts
  crds/         # Custom Resource Definitions
  templates/    # templates
  Chart.yaml    # info about the chart
  values.yaml   # default values

Template + values = a valid k8s manifest.


What happens in helm install

helm install:

  • install CRDs in crds/ folder.
  • renders the templates.
  • pre-install hook.
  • creates/updates k8s resources.
  • post-install hook.

How to Create a hook

  • add the annotation to the yaml (e.g. a Job)
  • metadata.annotations."helm.sh/hook": pust-install

Where is the release info stored?

When we run helm list --kubeconfig KUBECONFIG, it pulls release info from that cluster. Where is that release info stored?

  • Helm 3 default: Secrets
  • Helm 2 default: ConfigMap
  • configurable by HELM_DRIVER env variable: [configmap, secret, sql]

Why Secret? The release information includes the contents of charts and values files, and therefore might contain sensitive data like passwords, private keys, and other credentials.

Why sql? Secret and ConfigMap are stored in etcd, 1mb limit

To use sql:

export HELM_DRIVER=sql
export HELM_DRIVER_SQL_CONNECTION_STRING=postgresql://helm-postgres:5432/helm?user=helm&password=changeme

What's the difference among CHART, RELEASE and REVISION?

  • CHART: a package of manifests (i.e. YAMLs) for deploying an app to k8s. A chart can be stored in a registry, the manifests inside the chart may have references to the images in the registry, but the chart itself does not include the images (and the size limit of a chart is usually 1 MB).
  • RELEASE: a running instance of a chart in a K8s cluster; One chart can often be installed many times into the same cluster; e.g. one MySQL chart but many databases instances running in the cluster, each is a "release".
  • REVISION: tracks the number of changes on a RELEASE.

Why "helm list" shows nothing?

Check the flags you are using:

  • specify namespace by -n or use --all-namespaces.
  • use --all to show all.
  • use --kubeconfig to specify the correct kubeconfig file.
$ helm ls --all-namespaces --all --kubeconfig KUBECONFIG


Use --debug

If you see any error in your helm command, add --debug to get more info.

Error: Too long: must have at most 1048576 bytes

Helm v3 stores chart state in a Kubernetes secret by default. Kubernetes secrets are limited to a max size based on etcd's configuration. The default etcd configuration limits secrets to a maximum size of 1MB. If you see this error, you need to reduce the size of your chart:

Error: create: failed to create: Secret “sh.helm.release.v1.MY_CHART_NAME.v1” is invalid: data: Too long: must have at most 1048576 bytes

Error: manifest does not contain minimum number of descriptors (2), descriptors found: 1

Maybe you are not pulling a "chart", not everything in the registry is a "chart"; "chart" and non-chart have different minimum number of descriptors.

"Could not locate a version matching provided version string"

Version should be specified by --version instead of as a suffix (chart:version).

$ helm pull oci:// --version 1.2.3

Helm Hook

"Hook" is just an annotation in the metadata of the yaml:

  • helm.sh/hook: the yaml will be in effect in the specified stage.
  • helm.sh/hook-weight: hooks will run in the ascending order of the weights.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
  name: foo-deployhook-clusterrole
    'helm.sh/hook': post-install,post-upgrade
    'helm.sh/hook-weight': '-1'
    'helm.sh/hook-delete-policy': before-hook-creation,hook-succeeded

helm.sh/hook values: pre-install, post-install, pre-delete, post-delete, pre-upgrade, post-upgrade, pre-rollback, post-rollback.

helm.sh/hook-delete-policy values:

  • before-hook-creation: Delete the previous resource before a new hook is launched (default)
  • hook-succeeded: Delete the resource after the hook is successfully executed
  • hook-failed: Delete the resource if the hook failed during execution


Helm internally uses labels and annotations to track the ownership of the managed resources to prevent multiple charts owning the same resources and causing glitches during upgrade/deletion. You can implicitly change resource ownership in a lot of ways. For example, renaming helm charts, merging helm charts, splitting helm charts, adding a new chart with existing resources in previous installation, these operations all cause change of ownership.

Helm SDK

Client works with OCI-compliant registries; Harbor is one of them. From go code:

import (
  // ...

// Create a new client
client, err := registry.NewClient()

// Push to the registry
info, err := client.Push(b, "localhost:5000/mycharts/foo:0.1.0")


  • Helm ChartMuseum is deprecated; newer versions of helm can fetch and upload charts in any OCI compliant registry.

Harbor and Helm

Circular dependencies:

  • Helm charts can live in Harbor.
  • Harbor can be installed to k8s by Helm.

The chart to install Harbor is stored in https://helm.goharbor.io.

$ helm repo add harbor https://helm.goharbor.io
$ helm repo list # find harbor in the list
$ helm fetch harbor/harbor --untar # this downloads the chart to a local `harbor` folder

# modify harbor/values.yaml

# install the chart in `harbor` as `my-release`
$ helm install my-release harbor



ORAS is used by Helm as the underlying library for working with registries.



Helm init takes a genericclioptions.RESTClientGetter



kube.New(getter) takes a RESTClientGetter to create a Client

chart.Apply(restClientGetter, installOptions) to install charts