Recently I’ve been looking at
kpt fn as a driver for generating
configuration. The impetus is that
kpt pkg feels like that right way
to export and consume packages of configuraton in git repositories,
and this could work well in sympathy with other “GitOps”
tooling; however, I think that asking people to write
programs in YAML is a catastrophe, so there needs to be a way to
include other kinds of program.
programs for use with
kpt fn. The real prize is to be
able to use
kpt fn as insulation around arbitrary means of
generating configuration, and not just a general-purpose programming
lanaguage. The first case in point must surely be Helm charts.
The official solutions
To start, I’ll examine the advice given in
- Fetch a Helm chart
- Expand the Helm chart
- Publish the kpt package
This is OK if you just want to have YAMLs you can apply to your
cluster then and there. But it’s far short of what you’d want as a
distributable package, since all the particulars for an environment
are decided statically in step 2. If you want there to be any
parameters to the package, you’ll have to go back and create them for
the expanded files with
kpt cfg, which is pretty underpowered
compared to Helm.
Somewhat undermining the advice quoted above, there is a Helm chart
template function available from the function
catalogue, but it doesn’t (yet?) work with
kpt fn – you have to run
This may be a case of the examples running ahead of the released software; there are some technical barriers that would have to be overcome before the approach demonstrated worked well:
- Since it’s intended to work with any chart, it needs the chart to
be downloaded or vendored, and mounted into the container, which is
awkward for the otherwise streamlined user interface of
- Similarly, values for the chart parameters have to be provided as a
file that gets mounted into the container, which subverts the
protocol of providing config in a
In pursuit of an approach that produces a reusable package, and works
kpt, I’ll have to try another route.
Helm chart images
helm-template function does not satisfy because it needs you to
mount the chart and values into the container when you run it. So I
would like a method which
- doesn’t need you to do that; and,
- uses the function protocol (i.e,
functionConfig) to supply parameters for the chart.
The git repo kpt-helm-demo demonstrates a method with those two properties.
The main trade-off is that you must build an image for each Helm chart you want to use. I do not see this as much of a disadvantage, since it’s easy to do generically, and the alternatives also have extra steps (like vendoring the chart).
This is how it works
image/ speaks the
function protocol, by extracting values from the
the input, running a Helm chart with those values, and assembling the
results for output as another
The Dockerfile in
image/ creates an image including
the script above, and the Helm chart named in build args.
With those, you can build a container image that will run a Helm chart:
$ docker build -t squaremo/flux-helm-chart ./image
(The image is so-named because I’ve made Flux the chart used by default. You don’t need to build to image to follow along with the rest of the post, since I’ve pushed it to Docker Hub.)
Then you can run that image with
kpt fn, but be aware that you need
at least one resource to provide input to the function, otherwise
kpt fn will exit without doing anything. There’s a namespace manifest in
instance/ to serve this purpose.
$ cat instance/ns.yaml apiVersion: v1 kind: Namespace metadata: name: flux-system $ kpt fn run instance/ --image=squaremo/flux-helm-chart -- releaseName=flux namespace=flux-system
The command line above explicitly mentions the image and gives some
parameters for the chart (actually for the
invocation). It’s also possible to provide a config object, and to
provide values for the chart:
$ cat config.yaml apiVersion: v1 kind: ConfigMap metadata: annotations: config.kubernetes.io/function: | container: image: squaremo/flux-helm-chart data: releaseName: flux namespace: flux-system values: | git: readonly: true registry: disableScanning: true $ kpt fn run instance/ --fn-path=./config.yaml
Using the package elsewhere
The repository can be imported to another git repository using
kpt pkg get. If you do, say,
$ mkdir local-config $ cd local-config $ git init $ kpt pkg get https://github.com/squaremo/kpt-helm-demo.git/instance flux-chart
.. you’ll get a local copy of the package which you can run:
$ kpt fn run flux-chart/instance --fn-path=flux-chart/config.yaml
You can now edit the
config.yaml and rerun the function to change
the generated files; and, use
kpt pkg update to get changes from
Can’t I just write a config.yaml and run that?
Yes, you could. The image can be pulled from Docker Hub (or you can build your own, using the Dockerfile); the config file and a starter resource are all you need to run the function.
You will miss out on the benefit of
kpt pkg – being able to pull in
updates from upstream – but reasonably you might not care about that.
How is this different from just running the chart?
If you don’t care about
kpt pkg, you probably don’t care about using
kpt fn either. So the premise of this post, using Helm charts in a
way that’s compatible with
kpt, would be moot.
Is this better than just shipping YAMLs?
I think so. It makes it easier to adjust a configuration to suit your needs, in the same way Helm makes that easier (and with the same downside – every chart has its own API).