Lab 21 - Writing your own chart
Lab 21 - Writing your own chart
Goal: package an application so it can be installed many times with different values. Chapter: Helm charts
# 1 - scaffold and read what you got
cd ~
helm create shop
find shop -type f | sort
cat shop/Chart.yaml
head -30 shop/values.yaml
helm create gives you a working nginx chart with far more machinery than you
need. Reading it is worthwhile: it shows the conventions every public chart
follows.
# 2 - render the default chart before changing anything
helm template shop | head -40
helm lint shop
helm template needs no cluster and no network. Run it after every edit - it is
faster than any install and it shows the real YAML.
Make it yours
# 3 - strip the scaffold down
cd shop
rm -f templates/hpa.yaml templates/ingress.yaml templates/serviceaccount.yaml
rm -rf templates/tests
Edit values.yaml:
replicaCount: 2
image:
repository: nginx
tag: "1.27"
pullPolicy: IfNotPresent
service:
type: NodePort
port: 80
nodePort: 30081
content:
message: "Shop from a chart"
serviceAccount:
create: false
Add templates/configmap.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "shop.fullname" . }}-content
data:
index.html: |
<h1>{{ .Values.content.message }}</h1>
<p>release: {{ .Release.Name }} / chart: {{ .Chart.Name }}-{{ .Chart.Version }}</p>
Two things to notice. include "shop.fullname" . is a macro from
templates/_helpers.tpl that builds a name from the release name - that is what
lets you install the chart twice without a collision. And .Release.Name is not
known until install time, which is exactly why a chart is a template and not a
manifest.
In templates/deployment.yaml, mount that ConfigMap into the container
(volumes + volumeMounts at /usr/share/nginx/html), and in
templates/service.yaml add nodePort: {{ .Values.service.nodePort }}.
# 4 - the loop: lint -> render -> dry-run -> install
helm lint .
helm template myshop . | less
helm install myshop . --dry-run --debug | head -40
helm install myshop . -n shop --create-namespace
kubectl get all,cm -n shop
curl -s http://worker01:30081
# 5 - the point of a chart: same package, different values
helm install myshop2 . -n shop \
--set content.message="Second instance" \
--set service.nodePort=30082 \
--set replicaCount=1
curl -s http://worker01:30082
helm list -n shop
Same templates, two releases, no name collisions, no copy-pasted YAML. This is what you would otherwise do with a folder per environment.
# 6 - upgrade by value
helm upgrade myshop . --set content.message="Upgraded" -n shop
curl -s http://worker01:30081
helm history myshop -n shop
# 7 - package it
cd ~
helm package shop
ls -l shop-0.1.0.tgz
helm install fromtgz ./shop-0.1.0.tgz -n shop --set service.nodePort=30083
curl -s http://worker01:30083
The .tgz is the shippable artifact - upload it to a chart repository or an OCI
registry and other people can install exactly this version.
If you have time
- Wrap an optional resource in
{{- if .Values.ingress.enabled }}and prove withhelm template --set ingress.enabled=falsethat it disappears. - Use
required "content.message is required" .Values.content.messageand see whathelm template --set content.message=nullreports. - Bump
versioninChart.yamlto0.2.0and package again.
Clean up
helm uninstall myshop myshop2 fromtgz -n shop
kubectl delete ns shop