Helm In Kubernetes — Part 3: Hand on with Flow Control and Pipelines

Felix Lee
7 min readMay 29, 2021

--

Photo by Andrew Neel from Pexels

We have seen how we can create a simple Helm Chart. This time we are going to take a look at flow control and pipelines in Helm.

At the end of this post, you should be able to:

  • Use flow control in Helm template
  • Use pipelines in Helm template

If you want to follow along or take a look at the code, you can find it here.

This is the app(2 apps actually) that we want to deploy.

We have app-1 and app-2 — 2 separate Node apps. On /service path of app-1 , it will curl app-2 root path. Likewise, On /service path of app-2 , it will curl app-1 root path. Take a look at the content of app-1 as an example. So we need some way to provide environment variable for the request address that we want to curl to our apps.

Key point:

  • cmd basically curl whatever we set forREQUEST_ADDRESS as our environment variable.

Both app-1 and app-2 are ready as Docker image, the image names are leeyoongti/node-web-app-1:1.0.2 and leeyoongti/node-web-app-2:1.0.2 respectively.

Let’s create our Helm Chart first. Run:

helm create node-web-app

Delete everything under the templates folder. Then, copy deployment.yml and service.yml inside 02-node-webapp/app-1/yml folder and paste them inside the templates folder so we don’t have to type everything from scratch.

Next, create 2 files named app-1.values.yaml and app-2.values.yaml . We will be using these files to inject values to our templates. Feel free to delete values.yaml file as we’re not going to use it.

You should end up having something like this in your newly created Helm Chart.

Everything in the templates are hardcoded, let’s change that and define the values in the value files.

Edit app-1.values.yaml to the following:

A few key points:

  • The app is running on port 3000.
  • The value for REQUEST_ADDRESS has to match whatever we provide when we are deploying the service for app-2 . Take a look at Line 4 in templates/service.yaml , we define the name of the service to be {{ .Values.name }}-service . So it means, when we are creating our app-2.values.yaml , we have to use app-2 as the name.
  • Usually we have to also define the port that we want to request, but app-2 is running on port 80, which is the default. So we do not have to specify it.

Edit app-2.values.yaml to the following:

A few key points:

  • We define the port for REQUEST_ADDRESS because app-1 is running on port 3000 instead of the default 80.
  • service.port is not defined for app-2. Later we will see in templates/service.yaml , we define a default value of 80 for it.

Edit templates/deployment.yaml to the following:

A few key points to cover here:

  • | sign here(Line 8 and Line 22) is known as a pipeline. Pipeline is used to chain a sequence of function together. We use is here to set a default value of 1 to replicas and default value of 80 to container port. So we can choose not to provide value for replicas and it will default to 1. So, for our case, app-1.values.yaml does not provide value for replicas, so we will be deploying the app with 1 replica.
  • with is used to specify a scope. Say we have image , tag and containerPort under the deployment scope (Check app-1.values.yaml Line 3–5). We can use with so that we do not have to define the value placeholder repeatedly, like so: .Values.deployment.image , .Values.deployment.tag , .Values.deployment.containerPort . We have to close the scope with end
  • range is used to loop a list of values. We can define a list of values and use range to loop over them(Check app-1.values.yaml Line 6 — 10). We will close the loop with end on Line 28.
  • spec.env is how we define environment variables for our app.

Edit templates/service.yaml to the following:

A few key points to cover for service.yaml

  • On Line 6, we have a if keyword. This is to check whether service value is provided. If it is not provided, it will go to the else on Line 17. Which means, the output file will include Line 18–23, and not Line 7–15. In another word, service and all the values nested under it are optional.
  • Again, we see pipeline and default in action to define a default value if the value is not provided. Port and target port will be set to 80 if service.port is not provided.
  • Here we have something called quote . It is used to add quote to the value, i.e. NodePort will become "NodePort" .

Now, let’s try installing(deploying) our Helm Chart by running(Make sure you are running the command in the directory that you created your Helm Chart:

// helm install [NAME] [CHART]
helm install node-web-app-1 node-web-app

You will probably see an error like this.

Error: template: node-web-app/templates/deployment.yaml:8:22: executing "node-web-app/templates/deployment.yaml" at <.Values.deployment.replicas>: nil pointer evaluating interface {}.replicas

It says .Values.deployment is nil, what gives?

If we look back at our deployment.yaml file on Line 8, the template is expecting us to provide a directory called deployment , the template never check whether deployment exists before accessing the replicas value.

Also, since we deleted values.yaml , we need to tell Helm which value file we want to use to install the app. So we should run this command instead:

helm install node-web-app-1 node-web-app --values ./node-web-app/app-1.values.yaml

You should see that your deployment has been successfully deployed.

NAME: node-web-app-1
LAST DEPLOYED: Sat May 29 22:55:53 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

Since we deploy our service as NodePort on port 30111(Line 14 in app-1.values.yaml), we can access it outside the Kubernetes cluster. Run the following command to get your Minikube IP.

minikube ip

Then access app-1 through YOUR_MINIKUBE_APP:30111 , replace YOUR_MINIKUBE_IP with the IP you get by running the command above.

You should be able to see the following:

Nice! We have successfully deployed app-1. Also if we want to check what is the generated output files before we actually deploy our app, we can run this command:

// helm template [CHART]
// helm template [CHART] --values [VALUE]
helm template node-web-app --values ./node-web-app/app-1.values.yaml

But if we try to access /service (Remember /service will curl from our app-2 , it will show error on the browser. So let’s deploy our app-2 as well. Run the command:

helm install node-web-app-2 node-web-app --values ./node-web-app/app-2.values.yaml

You should see that your app is successfully deployed. You can check by going to your existing app-1 and go to /service

You can also access app-2 at YOUR_MINIKUBE_IP:30112 as we define the node port of 30112 for app-2.

Conclusion

We have seen how we can deploy 2 different apps by providing different value files to the same Helm Chart. We also learned about how we can use with , if/else , and range to make our template more powerful and flexible.

Thanks for reading! If you like the post, leave a like so other people can see it as well.

--

--

Felix Lee

Software engineer in Singapore. Write random tech stuff. Still figuring out this “life” thing in life.