Kustomize is built from generators and transformers; the former make kubernetes YAML, the latter transform said YAML.
Kustomize, via the helmCharts
field, has the ability to
use the helm
command line program in a subprocess to
inflate a helm chart, generating YAML as part of (or as the
entirety of) a kustomize base.
This YAML can then be modified either in the base directly (transformers always run after generators), or via a kustomize overlay.
Either approach can be viewed as last mile modification of the chart output before applying it to a cluster.
The example below arbitrarily uses the minecraft chart pulled from the artifact hub chart repository.
This example defines the helm
command as
helmCommand=${MYGOBIN:-~/go/bin}/helmV3
This value is needed for testing this example in CI/CD.
A user doesn't need this if their binary is called
helm
and is on their shell's PATH
.
Make a place to work:
DEMO_HOME=$(mktemp -d)
mkdir -p $DEMO_HOME/base $DEMO_HOME/dev $DEMO_HOME/prod
Define a kustomization representing your development variant.
This could involve any number of kustomizations (see
other examples), but in this case just add the name
prefix 'dev-
' to all resources:
cat <<'EOF' >$DEMO_HOME/dev/kustomization.yaml
namePrefix: dev-
resources:
- ../base
EOF
Likewise define a production variant, with a name
prefix 'prod-
':
cat <<'EOF' >$DEMO_HOME/prod/kustomization.yaml
namePrefix: prod-
resources:
- ../base
EOF
These two variants refer to a common base.
Define this base the usual way by creating a
kustomization
file:
cat <<'EOF' >$DEMO_HOME/base/kustomization.yaml
helmCharts:
- name: minecraft
includeCRDs: false
valuesInline:
minecraftServer:
eula: true
difficulty: hard
rcon:
enabled: true
releaseName: moria
version: 3.1.3
repo: https://itzg.github.io/minecraft-server-charts
EOF
The only thing in this particular file is a helmCharts
field, specifying a single chart.
The valuesInline
field overrides some native chart values.
The includeCRDs
field instructs Helm to generate
CustomResourceDefinitions
.
See the Helm documentation for details.
Check the directory layout:
tree $DEMO_HOME
Expect something like:
/tmp/whatever ├── base │ └── kustomization.yaml ├── dev │ └── kustomization.yaml └── prod └── kustomization.yaml
Attempt to build the base
:
cmd="kustomize build --helm-command $helmCommand $DEMO_HOME/base"
if ($cmd); then
echo "Build should fail!" && false # Force test to fail.
else
echo "Build failed because no --enable-helm flag (desired outcome)."
fi
This build
fails and complains about a missing
--enable-helm
flag.
The flag --enable-helm
exists to have the user
acknowledge that kustomize is running an external program as
part of the build
step. It's like the
--enable-plugins
flag, but with a helm focus.
The flag --helm-command
has a default value (helm
of
course) so it's not suitable as an enablement flag. A user
with helm
on their PATH
need not awkwardly specify
'--helm-command helm'
.
Given the above, define a helper function to run kustomize
with the
flags required for helm
use in this demo:
function kustomizeIt {
kustomize build \
--enable-helm \
--helm-command $helmCommand \
$DEMO_HOME/$1
}
Now build the base
:
kustomizeIt base
This works, and you see an inflated chart complete
with a Secret
, Service
, Deployment
, etc.
As a side effect of this build, kustomize pulled the chart
and placed it in the charts
subdirectory of the base.
Take a look:
tree $DEMO_HOME
If the chart had already been there, kustomize would not have tried to pull it.
To change the location of the charts, use this in your kustomization file:
helmGlobals: chartHome: charts
Change charts
as desired, but it's best to keep it
in (or below) the same directory as the kustomization.yaml
file.
If it's outside the kustomization root, the build
command will
fail unless given the flag '--load-restrictor=none'
to
disable file loading restrictions.
Now build the two variants dev
and prod
and compare their differences:
diff <(kustomizeIt dev) <(kustomizeIt prod) | more
This shows so-called last mile hydration of two variants made from a common base that happens to be generated from a helm chart.
The command kustomize used to download the chart is something like
$helmCommand pull \ --untar \ --untardir $DEMO_HOME/base/charts \ --repo https://itzg.github.io/minecraft-server-charts \ --version 3.1.3 \ minecraft
The first use of kustomize above (when the base
was
expanded) fetched the chart and placed it in the charts
directory next to the kustomization.yaml
file.
This chart was reused, not re-fetched, with the variant
expansions prod
and dev
.
If a chart exists, kustomize will not overwrite it (so to suppress a pull, simply assure the chart is already in your kustomization root). kustomize won't check dates or version numbers or do anything that smells like cache management.
kustomize is a YAML manipulator. It's not a manager of a cache of things downloaded from the internet.
To show that the locally stored chart is being re-used, modify its values file.
First make note of the password encoded in the production inflation:
test 1 == $(kustomizeIt prod | grep -c "rcon-password: Q0hBTkdFTUUh")
The above command succeeds if the value of the generated
password is as shown (Q0hBTkdFTUUh
).
Now change the password in the local values file:
values=$DEMO_HOME/base/charts/minecraft-3.1.3/minecraft/values.yaml
grep CHANGEME $values
sed -i 's/CHANGEME/SOMETHING_ELSE/' $values
grep SOMETHING_ELSE $values
Run the build, and confirm that the same rcon-password
field in the output has a new value, confirming that the
chart used was a local chart, not a chart freshly
downloaded from the internet:
test 1 == $(kustomizeIt prod | grep -c "rcon-password: U09NRVRISU5HX0VMU0Uh")
Finally, clean up:
rm -r $DEMO_HOME
To recap, the helm-related kustomization fields make kustomize run
helm pull ... helm template ...
as a convenience for the user to generate YAML from a helm chart.
Helm's pull
command downloads the chart. Helm's template
command inflates the chart template, spitting the inflated
template to stdout (where kustomize captures it) rather than
immediately sending it to a cluster as helm install
would.
To improve performance, a user can retain the chart after
the first pull, and commit the chart to their configuration
repository (below the kustomization.yaml
file that refers
to it). kustomize only tries to pull the chart if it's not
already there.
To further improve performance, a user can inflate the chart themselves at the command line, e.g.
helm template {releaseName} \ --values {valuesFile} \ --version {version} \ --repo {repo} \ {chartName} > {chartName}.yaml
then commit the resulting {chartName}.yaml
file to a git
repo as a configuration base, mentioning that file as a
resource
in a kustomization.yaml
file, e.g.
resources: - minecraft_v3.1.3_Chart.yaml
The user should choose when or if to refresh their local
copy of the chart's inflation. kustomize would have no
awareness that the YAML was generated by helm, and kustomize
wouldn't run helm
during the build
. This is analogous
to Go
module vendoring.
Although the helm
related fields discussed above are handy
for experimentation and development, it's best to avoid them
in production.
The same argument applies to using remote git URL's in other kustomization fields. Handy for experimentation, but ill-advised in production.
It's irresponsible to depend on a remote configuration
that's not under your control. Annoying enablement flags
like '--enable-helm'
are intended to remind one of a
risk, but offer zero protection from risk. Further, they
are useless are reminders, since annoying things are
immediately scripted away and forgotten, as was done above
in the kustomizeIt
shell function.
Don't use remote configuration that you don't control in production.
Maintain a local, inflated fork of a remote configuration, and have a human rebase / reinflate that fork from time to time to capture upstream changes.