Skip to content

helm

"The Kubernetes Package Manager" - https://github.com/kubernetes/helm

These notes are all about helm version 3. Charts that require helm 3 should use apiVersion: v2, though helm 3 does support v1.

Tips

List all versions of a chart in a given repo

helm search repo repo_name/chart_name --devel --versions

Include pre-release versions in all versions

You have to use mastermind/semver constraints with helm, which dictate that you have to include a pre-release component if you want to match against prereleases:

helm search repo repo_name/chart_name --devel --versions --version '^1.5-0'

This would show all versions including prereleases before or equal to 1.5.x. If you only want to show the latest version even if it is a prerelease, leave off --versions.

Get values of a deployed chart

This only shows values that were passed in, not default values.

$release_name is the NAME column in helm list

helm get values -o yaml "$release_name" > values.yaml

To get a list of all values, use

helm get values --all -o yaml "$release_name" > values.yaml`

Show notes for a deployed service

Notes are printed when you install a service, but they can be viewed again by running helm status <release_name> where <release_name> is one of the releases from helm list.

Install the stable repo

helm repo add stable https://charts.helm.sh/stable

Install the incubator repo

https://github.com/helm/charts#how-do-i-enable-the-incubator-repository

helm repo add incubator https://charts.helm.sh/incubator

Show metadata about a specific release in json

You can find the revision in a few places, like helm list -A. Default is to store data about the last 10 releases per release_name.

helm history -n "$NS" "$RELEASE_NAME" -o json | jq '.[] | select(.revision == 157)'

Show raw data about what helm sent to the k8s server for a recent release

First, find the secret that you will want to search. You can get the release number from helm history -n "$NS" foo or dig in kubectl -n $NS get secret

$ k -n "$NS" get secret | grep sh.helm.release | tail -n 3 | column -t
sh.helm.release.v1.foo.v338  helm.sh/release.v1  1  14d
sh.helm.release.v1.foo.v339  helm.sh/release.v1  1  13d
sh.helm.release.v1.foo.v340  helm.sh/release.v1  1  4d23h

Then send that secret into the following command to get the full manifest that was sent to the k8s api:

k -n "$NS" get secret "$SECRET" -o go-template='{{ .data.release | base64decode | base64decode }}' |
  gzip -d

The result is a json blob with all the details of how the helm chart was applied, including hook manifests, app manifests, and other metadata.

Splay cron jobs

Splaying cron jobs avoids the thundering herd problem by spreading the jobs out over time with deterministic randomness.

The functions available when using Helm templates are not as plentiful and general purpose like you would expect in a normal programming language, so we have to get creative for some things. One thing that would be great is if Helm provided a deterministic random feature. It does have randomness, but there is no way to seed the random number generator. To work around this, we can use other functions that do take inputs in order to generate deterministic random-ish numbers. One such example is using adler32sum, which returns a base-10 hash value of an input.

The following example splays a cron job that runs every 15 minutes from 3-12 inclusive, which should avoid high-demand minutes at the beginning of 0/15, and still give a few minutes for work to complete before coming back around to the next 0/15 interval.

'{{- add 3 (regexFind ".$" (adler32sum .Release.Name)) -}}-59/15 * * * *'

This bit of code aler32sums the .Release.Name value, which is expected to be unique for every deployment but may not be in your environment, takes only the right-most digit, which is 0-9, and adds 3 to it, then uses that number as the starting minute in the cron schedule, EG: 7-59/* * * * *.

Here is a python script that shows what minute number would be generated for 235,976 inputs:

#!/usr/bin/env python3

from zlib import adler32
from pathlib import Path

_input = Path("/usr/share/dict/words").read_text().split()
output = {x + 3: 0 for x in range(10)}

for item in _input:
    cksum = adler32(str.encode(item))
    splay_minute = int(str(cksum)[-1]) + 3
    output[splay_minute] += 1

for k, v in output.items():
    print(f"{k:2d}: {v}")

And the output shows a pretty even splay across all minutes, with each minute containing roughly 1/10th of the input lines:

$ ./test-adler32sum.py
 3: 23483
 4: 23523
 5: 23699
 6: 23628
 7: 23464
 8: 23750
 9: 23435
10: 23833
11: 23605
12: 23556

Surely there is more rigorous statistical analysis needed to better understand exactly how the inputs are being spread, but if you care that much about it, you are probably better off submitting a pr with your desired behavior to https://github.com/Masterminds/sprig, which is where the helm template functions come from.

Detect helm resources that do not have proper annotations

Helm requires that certain annotations exist. This this check will return all deployments that do not contain the required anntoations:

kubectl get deployments -A -o json |
jq '.items[] | select((.metadata.annotations."meta.helm.sh/release-name" == null) or (.metadata.annotations."meta.helm.sh/release-namespace" == null)) | .metadata.name'