# Introduction to Helm
## We need a Kubernetes cluster
Lets create a Kubernetes cluster to play with using [kind](https://kind.sigs.k8s.io/docs/user/quick-start/)
```
kind create cluster --name helm --image kindest/node:v1.19.1
```
# Getting Started with Helm
Firstly, I like to do most of my work in containers so everything is reproducible
and my machine remains clean.
## Get a container to work in
Run a small `alpine linux` container where we can install and play with `helm`:
```
docker run -it --rm -v ${HOME}:/root/ -v ${PWD}:/work -w /work --net host alpine sh
# install curl & kubectl
apk add --no-cache curl nano
curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
chmod +x ./kubectl
mv ./kubectl /usr/local/bin/kubectl
export KUBE_EDITOR="nano"
# test cluster access:
/work # kubectl get nodes
NAME STATUS ROLES AGE VERSION
helm-control-plane Ready master 26m v1.19.1
```
## Install Helm CLI
```
curl -LO https://get.helm.sh/helm-v3.4.0-linux-amd64.tar.gz
tar -C /tmp/ -zxvf helm-v3.4.0-linux-amd64.tar.gz
rm helm-v3.4.0-linux-amd64.tar.gz
mv /tmp/linux-amd64/helm /usr/local/bin/helm
chmod +x /usr/local/bin/helm
```
## Create our first Chart
For reference in the rest of the guide, I have left my full templates in:
`/kubernetes/helm/example-app`
```
cd kubernetes/helm
mkdir temp && cd temp
helm create example-app
```
## Cleanup the template
We can delete unwanted files:
* delete everything under /templates, keeping only `_helpers.tpl`
* delete `tests` folder under `templates`
## Add Kubernetes files to our new Chart
Copy the following files into our `example-app/templates/` folder
* `/kubernetes/deployments/deployment.yaml`
* `/kubernetes/services/service.yaml`
* `/kubernetes/configmaps/configmap.yaml`
* `/kubernetes/secrets/secret.yaml`
## Test the rendering of our template
```
helm template example-app example-app
```
## Install our app using our Chart
```
helm install example-app example-app
# list our releases
helm list
# see our deployed components
kubectl get all
kubectl get cm
kubectl get secret
```
## Value injections for our Chart
For CI systems, we may want to inject an image tag as a build number
Basic parameter injection:
```
# values.yaml
deployment:
image: "aimvector/python"
tag: "1.0.4"
# deployment.yaml
image: {{ .Values.deployment.image }}:{{ .Values.deployment.tag }}
# upgrade our release
helm upgrade example-app example-app --values ./example-app/values.yaml
# see revision increased
helm list
```
## Make our Chart more generic
Let's make our chart generic so it can be reused:
For the following objects, replace `example-deploy` and `example-app` to inject: `"{{ .Values.name }}"`
* deployment.yaml
* services.yaml
* secret.yaml
* configmap.yaml
Now that our application is generic
We can deploy another copy of it.
Rename `values.yaml` to `example-app.values.yaml`
Create our second app values file `example-app-02.values.yaml`
```
helm install example-app-02 example-app --values ./example-app/example-app-02.values.yaml
```
## Trigger deployment change when config changes
By default, a deployment will not rollout new pods when a configmap changes.
Some application read configuration at start up and deployment may need to roll out
new pods when a configmap changes. Let's do that:
```
# deployment.yaml
kind: Deployment
spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
# rollout the change
helm upgrade example-app example-app --values ./example-app/example-app-01.values.yaml
```
## If\Else and Default values
You can also set default values in case they are not supplied by the `values.yaml` file.
This may help you keep the `values.yaml` file small
```
{{- if .Values.deployment.resources }}
resources:
{{- if .Values.deployment.resources.requests }}
requests:
memory: {{ .Values.deployment.resources.requests.memory | default "50Mi" | quote }}
cpu: {{ .Values.deployment.resources.requests.cpu | default "10m" | quote }}
{{- else}}
requests:
memory: "50Mi"
cpu: "10m"
{{- end}}
{{- if .Values.deployment.resources.limits }}
limits:
memory: {{ .Values.deployment.resources.limits.memory | default "1024Mi" | quote }}
cpu: {{ .Values.deployment.resources.limits.cpu | default "1" | quote }}
{{- else}}
limits:
memory: "1024Mi"
cpu: "1"
{{- end }}
{{- else }}
resources:
requests:
memory: "50Mi"
cpu: "10m"
limits:
memory: "1024Mi"
cpu: "1"
{{- end}}
# rollout the change
helm upgrade example-app example-app --values ./example-app/example-app-01.values.yaml
```