Build your first Helm chart with Docker Desktop on Mac

Anuja Arosha
5 min readDec 1, 2021

Hello friends!, this is a beginning on a new journey to explore Kubernetes (K8s) world. In this post, we will try to use Helm, which is the package manager forK8s.

As a habit, I’m describing my working environment which I have tested the content of this blog post.

  • macOS Big Sur (Version 11.5.2)
  • Docker Desktop Version 4.0.0 (4.0.0.12)
  • Kubernetes version 1.21 (both client and server)
  • Helm Version “v3.5.4”

Let’s dive in. Go inside an empty directory and execute following command using the Terminal app. Instead of “my-website”, you can provide any name you like.

helm create my-website

Now a directory will be created with the name that you given and inside that you can see structure similar to below.

▶ tree my-website 
my-website
├── Chart.yaml
├── charts
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml

I’m not going to describe the purpose of these files and the default content of each and every file, since Helm documentation has done a pretty good job on that.

As default, this helm chart consist with nginx image which means now you have a simple web server application. Next task is running that application in our local Kubernetes environment. Since I do not want to mess with my other work, I create a separate sub-cluster that we call namespace in K8s world. Here also you can provide any name you wish instead of “k8s-lessons”

kubectl create namespace k8s-lessons

If you want to check what are the existing namespaces already created when the Docker Desktop installed and enabled Kubernetes of that, you can run following command.

kubectl get namespace

Now you can deploy your simple web server in that given namespace like below. Here “my-web” is the name given by me for the application.

helm install my-web ./my-website -n k8s-lessons

You can check what K8s components has started, related to your application by running this command.

▶ kubectl get all -n k8s-lessons
NAME READY STATUS RESTARTS AGE
pod/my-web-my-website-6ddd8859bf-fx2p4 1/1 Running 0 5m10s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/my-web-my-website ClusterIP 10.96.30.226 <none> 80/TCP 5m10s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/my-web-my-website 1/1 1 1 5m10s
NAME DESIRED CURRENT READY AGE
replicaset.apps/my-web-my-website-6ddd8859bf 1 1 1 5m10s

As you can see from the above output, it has started a Pod, Service, Deployment and a ReplicaSet. In your Pod status, it says that your application is running. But can you access your web site from your browser? No, you cannot, because you have not set an external IP address. You can see that in the Service line in above out put.

Since Helm does not like to put you through trouble on running your default application, they have provided a temporary solution using port forwarding. Those details are available as the output of helm install command. If I share my output, it is like this.

1. Get the application URL by running these commands:  export POD_NAME=$(kubectl get pods --namespace k8s-lessons -l "app.kubernetes.io/name=my-website,app.kubernetes.io/instance=my-web" -o jsonpath="{.items[0].metadata.name}")  export CONTAINER_PORT=$(kubectl get pod --namespace k8s-lessons $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")  echo "Visit http://127.0.0.1:8080 to use your application"  kubectl --namespace k8s-lessons port-forward $POD_NAME 8080:$CONTAINER_PORT

We will see a better way of doing this. What we are going to do is, create a new service that will communicate external world with our application pod using K8s default LoadBalancer type. You can see the deployment name in an earlier output and you can provide any name for the service as you wish instead of the name that I’ve provided here.

kubectl expose deployment my-web-my-website --type=LoadBalancer --name=my-web-svc -n k8s-lessons

If you check the available services now, you can see the newly created service as well as the service we have used with port forwarding. Apart from that, you can see localhost has been assigned as the external IP that can communicate with the Pod.

▶ kubectl get svc -n k8s-lessons                                                                  
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-web-my-website ClusterIP 10.96.30.226 <none> 80/TCP 27m
my-web-svc LoadBalancer 10.105.230.45 localhost 80:32402/TCP 4s

This is a good improvement, but is this the best approach? Before you give an answer, think what will happen if you want to deploy your Helm chart in a different environment. Then you can manually create the service again, which is not good. Then let’s try whether we can set this as a configuration. Before that we will delete the service which we have created just now, in order to verify the configuration that we are going to do is effective.

kubectl delete svc my-web-svc -n k8s-lessons

If you check your localhost now, you will see that your service has down. As the next step, go to your project directory and find the values.yaml and open it where you feel comfortable to edit. In that, you will be able to find a service tag and I want you to change the value for type as below.

type: LoadBalancer

It’s time to upgrade your Helm chat by executing below command.

▶ helm upgrade -f my-website/values.yaml my-web ./my-website -n k8s-lessons 
Release "my-web" has been upgraded. Happy Helming!
NAME: my-web
LAST DEPLOYED: Wed Dec 1 11:31:15 2021
NAMESPACE: k8s-lessons
STATUS: deployed
REVISION: 2
...

I’ll come back to the reason that I’ve put some of the output above at the later part of this post. First we will check our expectation has met with the change we have done.

▶ kubectl get svc -n k8s-lessons                                           
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-web-my-website LoadBalancer 10.96.30.226 localhost 80:30568/TCP 64m

Yes, the service has updated with LoadBalancer type and also external IP has been set which you can access using your web browser. There are more better approaches we can include but for this post, we will stick to this.

Before ending up, let’s go back to few paragraph above where I’ve mentioned about an output of a command. I want to highlight the REVISION: 2 line. This means K8s is smart enough to keep track of your changes you have done to your Pods. You can see the history using following command.

▶ helm history my-web -n k8s-lessons 
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
1 Wed Dec 1 10:27:36 2021 superseded my-website-0.1.0 1.16.0 Install complete
2 Wed Dec 1 11:31:15 2021 deployed my-website-0.1.0 1.16.0 Upgrade complete

If you need, you can rollback to revision 1, which is the very first version that you have once you finished installing the Helm chart. But this will break your service which you have enabled in revision 2. Who cares 😂 try it out for fun, I promise you can rollback to revision 2 again once you understand the concept.

helm rollback my-web 1 -n k8s-lessons

Run the history command again to see what happened behind the scene. Then you can rollback to revision 2 to have a running application.

Yep, I think this is more than enough for today’s post. I hope you have learned something out of this and keep in touch for more related posts 👍

--

--

Anuja Arosha

Native mobile application development enthusiasm. DevOps engineer.