Authoring a Helm Chart on Kubernetes / AKS - Parametrized values
Solution ·In the last article, we authored a very simple chart.
In this article I want to show how to use one of the powerful features of Helm: values.
Values act as parameters to a chart.
Having parameters is key for dev ops as we want to deploy the same chart to different environment with different parameters.
As usual, the code is in GitHub. In order to try the example in the article, simple clone the repo locally.
Let’s dive in!
A Service
Let’s start by deploying a slightly more complicated chart. That chart will deploy a service instead of a namespace.
So, from the root of the repo, we can type:
$ helm upgrade --install myservice b-service
Here we use the idempotent form of install with Helm. This command will install the first time and update subsequent time. It is equivalent to a kubectl apply
.
We install the chart b-service (which is in the b-service sub folder from the repo’s root). We call the release myservice.
We can see that deployed a cluster-IP service in the b namespace:
$ kubectl get svc --namespace=b
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service ClusterIP 10.0.44.202 <none> 80/TCP 8m
It also deployed a deployment with 2 pods:
$ kubectl get deploy --namespace=b
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
my-deployment 2 2 2 2 8m
We could test the service using
kubectl run -i --tty console --image=appropriate/curl -- sh
and curling the service.
Instead, let’s look at files in the chart:
b-service/
Chart.yaml
README.md # Optional but quick to write
values.yaml # Mandatory, but empty in our case
templates/
deployment.yaml # A deployment
namespace.yaml # The namespace b
service.yaml # A service bound to the deployment
NOTES.txt # Optional but quick to write
This time around we have two (3) yaml files in the templates folder.
deployment.yaml, a vanilla deployment with 2 replicas:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
labels:
app: get-started
spec:
replicas: 2
selector:
matchLabels:
app: get-started
template:
metadata:
labels:
app: get-started
spec:
containers:
- name: myapp
image: vplauzon/get-started:part2-no-redis
ports:
- containerPort: 80
namespace.yaml, a vanilla namespace:
apiVersion: v1
kind: Namespace
metadata:
name: b
service.yaml, a vanilla service of type ClusterIP:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: ClusterIP
ports:
- port: 80
selector:
app: get-started
This is Helm without values, without parameters.
Namespace
Helm can override the default namespace with the --namespace
option for the install.
It doesn’t manage the namespace as one would expect though. It doesn’t delete the namespace when the Helm release is deleted for instance. Similarly, it wouldn’t recreate a namespace if it gets deleted. This is a partially documented issue.
For those reasons we instead manage the namespace explicitly by declaring a namespace object. This way, when we delete the release, the namespace will go away. This is useful for the demo aspect of this article.
For traditional work the --namespace
is likely more useful. Often more than one chart / release will go in one namespace. We just need to be aware of the issue mentionned above.
Enter values parameters
Now, let’s deploy another chart:
helm upgrade --install myparameteredsvc c-parametrized-service
This is c-parametrized-service.
On the surface, it is quite similar to the previous chart. It deploys a service and a deployment with 2 replicas:
$ kubectl get svc --namespace=c
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
param-service ClusterIP 10.0.187.51 <none> 80/TCP 3m
$ kubectl get deploy --namespace=c
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
get-started 2 2 2 2 3m
The major difference is that this chart uses values. Let’s look at values.yaml:
# We use parameters here:
service:
name: param-service # Name of the Kubernetes' service
replicaCount: 2 # Number of pods in the replica set
deployment:
name: get-started # Name of the deployment
This file is a plain old YAML file. Any values in the nodes of the YAML tree can be used. For instance service.name
.
For instance, let’s look at namespace.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: {{ .Values.namespace }}
We see the value for the namespace name is pulled from the values yaml tree.
The template files are leveraging GO templates.
Overriding values
We can then override the values. We can do it piece by piece, using the set option. For instance, let’s bump the number of replica from 2 to 5:
helm upgrade --install myparameteredsvc c-parametrized-service --set service.replicaCount=5
We can then confirm the number of replica was changed:
$ kubectl get deploy --namespace=c
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
get-started 5 5 5 5 1m
Using this we can parametrize a release.
Overriding many values
Using the previous method of overriding can quickly become cumbersome.
We can instead pass a file to override values.
Let’s look at _values-override.yaml:
deployment:
name: my-deployment
service:
replicaCount: 4
Here we override the replica count but also the name of deployment.
The file name starts with an underscore. This is a trick to get a file ignored in the chart folder.
We can use that file with the values
option:
helm upgrade --install myparameteredsvc c-parametrized-service --values=c-parametrized-service/_values-override.yaml
We can then validate:
$ kubectl get deploy --namespace=c
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
my-deployment 4 4 4 4 30s
The number of replica and the name of the deployment just changed.
Clean up
We can clean up our cluster with the following command:
helm delete myservice myparameteredsvc --purge
The --purge
option clears the releases from Helm’s audit.
Summary
Using values in our Helm chart makes them parameterizable.
This makes them much more reusable but also enables Dev Ops scenarios.
I hope this article gives you tips to enable you to leverage Helm in your Dev Ops scenarios by authoring great charts!