A simple example for Helm chart

Ying Ray Lu
DeepQ Research Engineering Blog
6 min readAug 5, 2019

In Kubernetes’ world, while you want to deploy a microservices, you need to have some of the requirements like docker images, manifest YAML of deployments, services, etc. For docker images, it easily controls the version with the version tag of the images and usual stores in the docker registry.

Helm chart packages all of Kubernetes manifests and also provides the version tag. Besides, Helm provides Go-Template syntax for you. You can configure all the values, inject to manifests when deploying to the cluster.

Sounds good right? Let’s start to play a simple example with Helm!

brew install kubernetes-helm

Before playing with Helm, you need a Kubernetes cluster. You can use your existing cluster or refer to this instruction and set up a local cluster.

Okay, let’s try Helm install command to install the WordPress chart which is provided from Helm. And you’ll get the error message.

helm install --name wordpress stable/wordpress
>> Error: could not find tiller

Before learning Helm, you need to know what Tiller is.

Tiller is the server portion of Helm, and you need to install it into your Kubernetes cluster.

Helm Tiller vs Kubectl

You can simply use Helm init command to deploy Tiller into the cluster.

helm init

Now, Tiller runs inside of your Kubernetes cluster. Check Tiller running into the Kube-system namespace:

kubectl get pods --namespace kube-system
>>
...
tiller-deploy-845fb7cfc6-qkwgh 1/1 Running 0 83m

And then do Helm install command again, you may get another warning like:

>> Error: release wordpress failed: namespaces "default" is forbidden: User "system:serviceaccount:kube-system:default" cannot get resource "namespaces" in API group "" in the namespace "default"

It means Tiller has no permission to release the chart. Let’s create a cluster role binding because it needs cluster-admin permission to deploy the services.

kubectl create serviceaccount tiller -n kube-system
kubectl create clusterrolebinding tiller \
--clusterrole cluster-admin \
--serviceaccount=kube-system:tiller

Then initialized Helm Tiller within the Tiller service account

helm init --service-account tiller

Ensure the version of Helm server and client:

helm version
>>
Client: &version.Version{SemVer:"v2.14.2", GitCommit:"a8b13cc5ab6a7dbef0a58f5061bcc7c0c61598e7", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.14.2", GitCommit:"a8b13cc5ab6a7dbef0a58f5061bcc7c0c61598e7", GitTreeState:"clean"}

Install again and get the release notes. You can follow the notes and get your own WordPress website with the browser. Today, we will learn how to create and customize a Helm chart, so please remove it from the cluster.

helm del --purge wordpress

Create a Helm chart

Firstly, let’s create a Helm chart with CLI:

helm create what-the-helm

Inside of the directory:

what-the-helm
├── Chart.yaml
├── charts
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── ingress.yaml
│ ├── service.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml

In this Helm chart, there’s deployment, service, ingress manifests in the templates folder…

Let’s start to deploy the Helm chart:

helm install --name what-the-helm .
>>
NAME: what-the-helm
LAST DEPLOYED:
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
what-the-helm 0/1 1 0 0s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
what-the-helm-7d78fbf657-xgftv 0/1 ContainerCreating 0 0s
==> v1/Service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
what-the-helm ClusterIP 10.0.27.42 <pending> 80:31081/TCP 0s
NOTES:
1. Get the application URL by running these commands:
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace default svc -w what-the-helm'
export SERVICE_IP=$(kubectl get svc --namespace default what-the-helm -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:80

Wait for pod running:

kubectl get pods -w
>>
NAME READY STATUS RESTARTS AGE
what-the-helm-7d78fbf657-xgftv 1/1 Running 0 76s

Use port-forward to forward the local port to service.

kubectl port-forward svc/what-the-helm 8888:80

Check browser: http://localhost:8888, then you’ll see Nginx welcome page.

Helm Revision

Now we make a little change for what-the-helm. Firstly, let’s create a ConfigMap Yaml in templates folder with the given configuration below:

apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configmap
data:
index.html: |
<h1>What the Helm!!!</h1>

And mount this ConfigMap volume to Pod:

    volumeMounts:
- name: nginx
mountPath: /usr/share/nginx/html
volumes:
- name: nginx
configMap:
name: nginx-configmap

Then upgrade it!

helm upgrade what-the-helm .

And check http://localhost:8080 again, you can see the welcome page was changed to our custom page.

Also, try to use go template syntax like this:

# configmap.yaml
index.html: {{ .Values.pageContent }}

For this example, Helm will render it from the values.YAML, so that we need to add the parameter to values.yaml.

# values.yaml
pageContent: |
<h1> What the Helm Template 0.0 </h1>

Before upgrading the chart, if you want to test the template rendering, but not actually install anything, you can use the command below. This will send the chart to the Tiller server, which will render the templates. But instead of installing the chart, it will return the rendered template to you.

helm install . --dry-run --debug

Also, you can use the template command. This will directly send the rendered template for you. Let’s check it out!

helm template .
>>>
---
# Source: what-the-helm/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configmap
data:
index.html: <h1> What the Helm Template 0.0 </h1>
---
...

Helm provides a simple linter to verify that your chart is well-formed.

helm lint .

Okay, it seems like everything all right. Upgrade it and check it out with browser!

Helm also provides the feature for accessing files inside templates, let’s try to create a new HTML file:

# what-the-helm/static/index.html
<h1> What the Helm accessing files :)) </h1>

Modify configmap.yaml.

# what-the-helm/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configmap
data:
{{- (.Files.Glob "static/*").AsConfig | nindent 2 }}

Upgrade it and check it out with browser again.

Nice job!

helm history what-the-helm
>>>
REVISION UPDATED STATUS CHART DESCRIPTION
1 ... SUPERSEDED what-the-helm-0.1.0 Install complete
2 ... SUPERSEDED what-the-helm-0.1.0 Upgrade complete
3 ... SUPERSEDED what-the-helm-0.1.0 Upgrade complete
4 ... DEPLOYED what-the-helm-0.1.0 Upgrade complete

Let’s try to rollback the chart to the first revision.

helm rollback what-the-helm 1

Then you’ll see Nginx welcome page come back and add another revision into the history as well.

helm history what-the-helm
>>>
REVISION UPDATED STATUS CHART DESCRIPTION
...
5 ... DEPLOYED what-the-helm-0.1.0 Rollback to 1

By the way, if you want to keep the Helm history shortly, set the history max when initializing Tiller.

helm init --service-account tiller --history-max 3

Or edit the tiller-deploy deployment and change TILLER_HISTORY_MAX.

The final step, let’s list all of the releases by Helm and delete the chart we made.

helm list 
>>
NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
what-the-helm 8 Sun Aug 4 17:43:28 2019 DEPLOYED what-the-helm-0.1.0 1.0 default
helm del --purge what-the-helm
>> release "what-the-helm" deleted

Distributing Charts

To distribute your own chart, it definitely to package your chart first.

helm package .
>> Successfully packaged chart and saved it to: /what-the-helm/what-the-helm-0.1.0.tgz

In this example, I will create a Github project for storing helm charts, so that let’s make a new empty folder and connect with your own Github project.

mkdir charts
cd charts
git init ...

Copy the package of your chart into this folder. Then generate index.yaml which is the repository manifest with the command below:

mv /what-the-helm/what-the-helm-0.1.0.tgz .
helm repo index .
cat index.yaml
>>
apiVersion: v1
entries:
what-the-helm:
- apiVersion: v1
appVersion: "1.0"
created: ""
description: A Helm chart for Kubernetes
digest: xxx
name: what-the-helm
urls:
- what-the-helm-0.1.0.tgz
version: 0.1.0

After pushing, uploading the charts to your storage, add this repo URL to Helm.

helm repo add my-repo https://raw.githubusercontent.com/ACCOUNT/REPO_NAME/masterhelm repo list
>>
NAME URL
stable https://kubernetes-charts.storage.googleapis.com
my-repo https://raw.githubusercontent.com/ACCOUNT/REPO_NAME/master
...

With Helm searching command, you can find your own repo and charts.

helm search

For now on, you can directly install your own chart with only one command:

helm install --name what-the-helm my-repo/what-the-helm

--

--

Ying Ray Lu
DeepQ Research Engineering Blog

Life can only be understood backwards, but it must be lived forwards.