Helm support
The Helm project is the biggest ecosystem of high quality, well maintained application definitions for Kubernetes.
Even though Grafana Tanka uses the Jsonnet language for resource definition, you can still consume Helm resources, as described below.
Consuming Helm Charts from Jsonnet
Section titled “Consuming Helm Charts from Jsonnet”Helm support is provided using the
github.com/grafana/jsonnet-libs/tanka-util
library. Install it with:
jb install github.com/grafana/jsonnet-libs/tanka-util
The following example shows how to extract the individual resources of the
grafana
Helm Chart:
local tanka = import "github.com/grafana/jsonnet-libs/tanka-util/main.libsonnet";local helm = tanka.helm.new(std.thisFile);
{ grafana: helm.template("grafana", "./charts/grafana", { namespace: "monitoring", values: { persistence: { enabled: true } } })}
The Chart itself is required to be vendored at a relative
path, in this case ./charts/grafana
.
Once invoked, the $.grafana
key holds the individual resources of Helm Chart as
a regular Jsonnet object that looks roughly like so:
{ cluster_role_binding_grafana_clusterrolebinding: {/* ... */}, cluster_role_grafana_clusterrole: {/* ... */}, config_map_grafana: {/* ... */}, config_map_grafana_test: {/* ... */}, deployment_grafana: {/* ... */}, // ...}
Above can be manipulated in the same way as any other Jsonnet data.
Under the hood, this feature invokes the
helm template
CLI command.
The following options control how the command is invoked:
...
{ grafana: helm.template("grafana", "./charts/grafana", { namespace: "monitoring", values: { persistence: { enabled: true } }, // Equivalent to: --api-versions v1 --api-versions apps/v1 apiVersions: ['v1', 'apps/v1'] // Equivalent to: --kube-version v1.20.0 kubeVersion: 'v1.20.0' // Equivalent to: --no-hooks noHooks: true,}
Tanka will install Custom Resource Definitions (CRDs) automatically, if the
Helm Chart requires them and ships them in crds/
. This is equivalent to helm template --include-crds
. This can be disabled using includeCrds: false
:
{ grafana: helm.template("grafana", "./charts/grafana", { includeCrds: false })}
Vendoring Helm Charts
Section titled “Vendoring Helm Charts”Tanka, like Jsonnet, is hermetic. It always yields the same resources when the project is strictly self-contained.
Helm however keeps Charts and repository configuration somewhere around
~/.config/helm
, which violates above requirement.
To comply with this requirement, Tanka expects Helm Charts to be found inside the
bounds of a project. This means, you MUST put your Charts somewhere next to
the file that calls helm.template()
, so that it can be referred to using a
relative path.
Vendor Location
Section titled “Vendor Location”Where to actually put them inside the project is up to you, but keep in mind you need to refer to them using relative paths.
We recommend always writing libraries that wrap the actual Helm Chart, so the
consumer does not need to be aware of it. Whether you put these into your local lib/
directory or
publish and vendor them into the vendor/
directory is up to you.
A library usually looks like this:
Directory/
- jsonnetfile.json
- main.libsonnet
When adopting Helm inside it, we recommend vendoring at the top level, as such:
Directory/
- jsonnetfile.json
- main.libsonnet
Directorycharts
- <someChart>
This way, you can refer to the charts as ./charts/<someChart>
from inside
main.libsonnet
. By keeping the chart as close to the consumer as possible, the
library is kept portable.
Charttool
Section titled “Charttool”Helm does not make vendoring incredibly easy by itself. helm pull
provides the
required plumbing, but it does not record its actions in a reproducible manner.
Therefore, Tanka ships a special utility at tk tool charts
, which automates
helm pull
:
# Create a chartfile.yaml in the current directory, e.g. in lib/myLibrarytk tool charts init
# Install the MySQL chart at version 1.6.7 from the stable repositorytk tool charts add stable/mysql@1.6.7
Adding charts
Section titled “Adding charts”To add a chart, use the following:
tk tool charts add <repo>/<name>@<version>
This will also call tk tool charts vendor
, so that the charts/
directory is updated.
Adding repositories
Section titled “Adding repositories”By default, the stable
repository is automatically set up for you. If you wish
to add another repository, you can use the add-repo
command:
# Add the official Grafana repositorytk tool charts add-repo grafana https://grafana.github.io/helm-charts
Another way is to modify chartfile.yaml
directly:
version: 1repositories: - name: stable url: https://charts.helm.sh/stable - name: grafana url: https://grafana.github.io/helm-charts
Installing multiple versions of the same chart
Section titled “Installing multiple versions of the same chart”If you wish to install multiple versions of the same chart, you can write them to a specific directory.
You can do so with a :<directory>
suffix in the add
command, or by modifying the chartfile manually.
tk tool charts add stable/mysql@1.6.7:1.6.7tk tool charts add stable/mysql@1.6.8:1.6.8
The resulting chartfile will look like this:
version: 1directory: chartsrepositories: - name: stable url: https://charts.helm.sh/stablerequires: - chart: stable/mysql directory: 1.6.7 version: 1.6.7 - chart: stable/mysql directory: 1.6.8 version: 1.6.8
Install charts from chartfile
Section titled “Install charts from chartfile”To install charts from an existing chartfile, use the following:
tk tool charts vendor
Optionally, you can also pass the --prune
flag to remove vendored charts that are no longer in the chartfile.
OCI Registry Support
Section titled “OCI Registry Support”Tanka supports pulling charts from OCI registries. To use one, the chart name must be split into two parts: the registry and the chart name.
As example, if you wanted to pull the oci://public.ecr.aws/karpenter/karpenter:v0.27.3
image, your chartfile would look like this:
version: 1directory: chartsrepositories: - name: karpenter url: oci://public.ecr.aws/karpenterrequires: - chart: karpenter/karpenter directory: v0.27.3 version: v0.27.3
Registry login is not supported yet.
Troubleshooting
Section titled “Troubleshooting”Helm executable missing
Section titled “Helm executable missing”Helm support in Tanka requires the helm
binary installed on your system and
available on the $PATH
. If Helm is not installed, you will see this error message:
evaluating jsonnet: RUNTIME ERROR: Expanding Helm Chart: exec: "helm": executable file not found in $PATH
To solve this, you need to install Helm.
If you cannot install it system-wide, you can point Tanka at your executable
using TANKA_HELM_PATH
opts.calledFrom unset
Section titled “opts.calledFrom unset”This occurs, when Tanka was not told where it helm.template()
was invoked
from. This most likely means you didn’t call new(std.thisFile)
when importing tanka-util
:
local tanka = import "github.com/grafana/jsonnet-libs/tanka-util/main.libsonnet";local helm = tanka.helm.new(std.thisFile); ↑ This is important
Failed to find Chart
Section titled “Failed to find Chart”helmTemplate: Failed to find a Chart at 'stable/grafana': No such file or directory.helmTemplate: Failed to find a Chart at '/home/user/stuff/tanka/environments/default/grafana': No such file or directory.
Tanka failed to locate your Helm chart on the filesystem. It looked at the
relative path you provided in helm.template()
, starting from the directory of
the file you called helm.template()
from.
Please check there is actually a valid Helm chart at this place. Referring to
charts as <repo>/<name>
is disallowed by design.
Two resources share the same name
Section titled “Two resources share the same name”To make customization easier, helm.template()
returns the resources not as the
list it receives from Helm, but instead converts this into an object.
For the indexing key it uses kind_name
by default. In some rare cases, this
might not be enough to distinguish between two resources, namely when the same
resource exists in two namespaces.
To handle this, pass a custom name format, e.g. to also include the namespace:
custom: helm.template('foo', './charts/foo', { nameFormat: '{{ print .metadata.namespace "_" .kind "_" .metadata.name | snakecase }}'})
The literal default format used is {{ print .kind "_" .metadata.name | snakecase }}
Tanka deploys test charts
Section titled “Tanka deploys test charts”By default, Tanka will deploy charts using the default flags for helm template
which also includes things like test resources. If that’s not what
you want, then you can set the skipTests
option when running helm.template
:
custom: helm.template('foo', './charts/foo', { skipTests: true,})