Building first Helm Chart with Spring Boot Microservices
When someone talks about managing the kubernetes cluster then I can very much assume that a particular someone is running a lot of kubectl, kubeadm command on terminal and which is quite obvious because managing kubernetes cluster is not as easy as it seems to be.
Managing kubernets cluster means checking cluster, pods, nodes, application deployment, replicas, load-balancer and the list goes one. So the question which arises in my mind -
Is there an easy way to manage this or at least some part of it?
The answer is Yes and its Helm Chart.
What is Helm Chart?
Helm Chart is an application package manager for the kubernetes cluster, just like we have apt packager manager in Linux.
So what can we do with Helm Chart -
- Define k8s application
- Install k8s application
- Upgrade k8s application
Most important aspect of the Helm Chart is you do not have to use Kubernetes CLI(command line interface) and neither you need to remember complex kubernetes commands to manage the kubernetes manifest.
Lets start playing with Helm Chart.
1. How to Install Helm Chart?
Installing Helm is fairly easy and there are various package manager available for you -
Homebrew
1brew install helm
Chocolatey
1choco install kubernetes-helm
Scoop
1scoop install helm
GoFish
1gofish install helm
Snap
1sudo snap install helm --classic
Binary
If you do not like any of the above packager manager then you could download the binaries as well
- Get the Binary - Download Binary
- Unpack it using - tar -zxvf helm-vxxx-xxxx-xxxx.tar.gz
- Move it - mv linux-amd64/helm /usr/local/bin/helm
Using Script
There is one more way to install latest Helm Version using script. Refer to the following terminal command for installing latest version of Helm -
1curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
1chmod 700 get_helm.sh
1./get_helm.sh
Verify Helm Chart Installation
I am assuming you might have choose one of the installation option for Helm Chart.
To verify the installation use the following command
1which helm
1/usr/local/bin/helm
2. Let's create Our First Helm Chart
Before we create a our First Helm Chart, we need to have kubernetes cluster up and running. Use the following command to verify the status of kubernetes cluster -
1kubectl get all
1NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
2service/kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 27d
If your kubernetes cluster is up and running then you should see default service .i.e. service/kubernetes .
If you do not know how to prepare or push your docker image to docker hub then I would highly recommend you to follow my guide from Step 1 to step 7
And for setting up local kubernetes cluster you can refer to - 12 Steps for Installing a Production Ready Kubernetes Cluster.
Well enough with the per-requisites , lets run some Helm Commands for creating our first Helm Chart
1helm create springboot
That is it and the basic Helm Chart skeleton with the name springboot is ready.
(Spoiler Alert - We are going to create our first Helm Chart for Springboot application but do not worry the same steps can be used for deploying any other application as well.)
3. Helm Chart Structure
Before we deep dive into the nitty gritty of Helm Chart, let's go through the Helm Chart Skeleton. Run the following command to see the tree structure of our Springboot Helm Chart -
1tree springboot
1springboot
2├── Chart.yaml
3├── charts
4├── templates
5│ ├── NOTES.txt
6│ ├── _helpers.tpl
7│ ├── deployment.yaml
8│ ├── hpa.yaml
9│ ├── ingress.yaml
10│ ├── service.yaml
11│ ├── serviceaccount.yaml
12│ └── tests
13│ └── test-connection.yaml
14└── values.yaml
(*Note - If you do not have tree command installed then use - sudo apt-get install tree or sudo yum -y install tree )
Inside Helm Chart ecosystem we define every configuration as YAML configuration. In the next section we will go through each YAML configuration
Chart.yaml
This file contains all the metadata about our Helm Chart for example -
1apiVersion: v2 #mandatory
2name: springboot #mandatory
3description: A Helm chart for Kubernetes
4type: application
5version: 0.1.0 #mandatory
6appVersion: 1.16.0
You do not need to define each configuration here but you must need to define -
- apiVersion
- name
- version
Other configurations are optional
Versioning - Each chart should has its own version number and it should follow the Semantic Versioning 2.0 aka SemVer 2. But do not get confuse with apiVersion, there are no strict rules for apiVersion.
values.yaml
As the name suggests we have do something with the values and yes you are right about it. This configuration file holds values for the configuration.
Do not worry it is fairly simple to understand once you look at the following values.yaml
1replicaCount: 1
2image:
3 repository: rahulwagh17/kubernetes:jhooq-k8s-springboot #updated url
4 pullPolicy: IfNotPresent
5 tag: ""
6imagePullSecrets: []
7nameOverride: ""
8fullnameOverride: ""
9serviceAccount:
10 create: true
11 annotations: {}
12 name: ""
13podAnnotations: {}
14podSecurityContext: {}
15
16securityContext: {}
17service:
18 type: ClusterIP
19 port: 8080 #updated port
20ingress:
21 enabled: false
22 annotations: {}
23 hosts:
24 - host: chart-example.local
25 paths: []
26 tls: []
27resources: {}
28
29autoscaling:
30 enabled: false
31 minReplicas: 1
32 maxReplicas: 100
33 targetCPUUtilizationPercentage: 80
34
35nodeSelector: {}
36
37tolerations: []
38
39affinity: {}
It looks quite enormous but trust me you do not need to write or remember every configuration by heart. Helm Create command generates the bare minimum values.yaml for you.
Since in this example we are going to try our Helm Chart for spring boot application, lets go through the configuration which we need to modify for deploying our spring boot application.
- repository : image:repository: rahulwagh17/kubernetes:jhooq-k8s-springboot
- port: 8080
So in the whole values.yaml you need to update the configuration at two places repository and port
Note :You should have a docker image of your spring boot application uploaded into the docker hub
Alright now we are ready with our Chart.yaml and values.yaml, lets jump to next configuration yamls
deployment.yaml
The next configuration we need to update is deployment.yaml and as the name suggest it is used for deployment purpose. So lets see how does it looks like
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4 name: {{ include "springboot.fullname" . }}
5 labels:
6 {{- include "springboot.labels" . | nindent 4 }}
7spec:
8{{- if not .Values.autoscaling.enabled }}
9 replicas: {{ .Values.replicaCount }}
10{{- end }}
11 selector:
12 matchLabels:
13 {{- include "springboot.selectorLabels" . | nindent 6 }}
14 template:
15 metadata:
16 {{- with .Values.podAnnotations }}
17 annotations:
18 {{- toYaml . | nindent 8 }}
19 {{- end }}
20 labels:
21 {{- include "springboot.selectorLabels" . | nindent 8 }}
22 spec:
23 {{- with .Values.imagePullSecrets }}
24 imagePullSecrets:
25 {{- toYaml . | nindent 8 }}
26 {{- end }}
27 serviceAccountName: {{ include "springboot.serviceAccountName" . }}
28 securityContext:
29 {{- toYaml .Values.podSecurityContext | nindent 8 }}
30 containers:
31 - name: {{ .Chart.Name }}
32 securityContext:
33 {{- toYaml .Values.securityContext | nindent 12 }}
34 image: "{{ .Values.image.repository }}" #update here
35 imagePullPolicy: {{ .Values.image.pullPolicy }}
36 ports:
37 - name: http
38 containerPort: 8080 #update here
39 protocol: TCP #comment it
40 #livenessProbe: #comment it
41 #httpGet: #comment it
42 #path: / #comment it
43 #port: http #comment it
44 #readinessProbe: #comment it
45 #httpGet: #comment it
46 #path: / #comment it
47 #port: http #comment it
48 resources:
49 {{- toYaml .Values.resources | nindent 12 }}
50 {{- with .Values.nodeSelector }}
51 nodeSelector:
52 {{- toYaml . | nindent 8 }}
53 {{- end }}
54 {{- with .Values.affinity }}
55 affinity:
56 {{- toYaml . | nindent 8 }}
57 {{- end }}
58 {{- with .Values.tolerations }}
59 tolerations:
60 {{- toYaml . | nindent 8 }}
61 {{- end }}
Do not get scared we do not need to update each and every configuration. But we need to update the containerPort to 8080
- containerPort : 8080
Because we need to deploy our spring boot application at port 8080.
service.yaml
The service.yaml is basically used for exposing our kubernetes springboot deployment as service. The good thing over here we do not need to update any configuration here.
1apiVersion: v1
2kind: Service
3metadata:
4 name: {{ include "springboot.fullname" . }}
5 labels:
6 {{- include "springboot.labels" . | nindent 4 }}
7spec:
8 type: {{ .Values.service.type }}
9 ports:
10 - port: {{ .Values.service.port }}
11 targetPort: http
12 protocol: TCP
13 name: http
14 selector:
15 {{- include "springboot.selectorLabels" . | nindent 4 }}
4. Run $ helm template springboot
Now we are into the step no 4 and we are pretty much ready with our first Helm Chart for our spring boot application.
But wait - Wouldn't it be nice if you could see the service.yaml, deployment.yaml with its actual values before running the helm install command?
Yes you can do that with the helm template command -
1helm template springboot
(You can not run the above command from inside the springboot directory, so you should get out from the springboot directory and then execute the command)
After running the above command it should return you will service.yaml, deployment.yaml and test-connection.yaml with actual values
1---
2# Source: springboot/templates/serviceaccount.yaml
3apiVersion: v1
4kind: ServiceAccount
5metadata:
6 name: RELEASE-NAME-springboot
7 labels:
8 helm.sh/chart: springboot-0.1.0
9 app.kubernetes.io/name: springboot
10 app.kubernetes.io/instance: RELEASE-NAME
11 app.kubernetes.io/version: "1.16.0"
12 app.kubernetes.io/managed-by: Helm
13---
14# Source: springboot/templates/service.yaml
15apiVersion: v1
16kind: Service
17metadata:
18 name: RELEASE-NAME-springboot
19 labels:
20 helm.sh/chart: springboot-0.1.0
21 app.kubernetes.io/name: springboot
22 app.kubernetes.io/instance: RELEASE-NAME
23 app.kubernetes.io/version: "1.16.0"
24 app.kubernetes.io/managed-by: Helm
25spec:
26 type: ClusterIP
27 ports:
28 - port: 8080
29 targetPort: http
30 protocol: TCP
31 name: http
32 selector:
33 app.kubernetes.io/name: springboot
34 app.kubernetes.io/instance: RELEASE-NAME
35---
36# Source: springboot/templates/deployment.yaml
37apiVersion: apps/v1
38kind: Deployment
39metadata:
40 name: RELEASE-NAME-springboot
41 labels:
42 helm.sh/chart: springboot-0.1.0
43 app.kubernetes.io/name: springboot
44 app.kubernetes.io/instance: RELEASE-NAME
45 app.kubernetes.io/version: "1.16.0"
46 app.kubernetes.io/managed-by: Helm
47spec:
48 replicas: 1
49 selector:
50 matchLabels:
51 app.kubernetes.io/name: springboot
52 app.kubernetes.io/instance: RELEASE-NAME
53 template:
54 metadata:
55 labels:
56 app.kubernetes.io/name: springboot
57 app.kubernetes.io/instance: RELEASE-NAME
58 spec:
59 serviceAccountName: RELEASE-NAME-springboot
60 securityContext:
61 {}
62 containers:
63 - name: springboot
64 securityContext:
65 {}
66 image: "rahulwagh17/kubernetes:jhooq-k8s-springboot"
67 imagePullPolicy: IfNotPresent
68 ports:
69 - name: http
70 containerPort: 8080
71 protocol: TCP
72 resources:
73 {}
74---
75# Source: springboot/templates/tests/test-connection.yaml
76apiVersion: v1
77kind: Pod
78metadata:
79 name: "RELEASE-NAME-springboot-test-connection"
80 labels:
81 helm.sh/chart: springboot-0.1.0
82 app.kubernetes.io/name: springboot
83 app.kubernetes.io/instance: RELEASE-NAME
84 app.kubernetes.io/version: "1.16.0"
85 app.kubernetes.io/managed-by: Helm
86 annotations:
87 "helm.sh/hook": test-success
88spec:
89 containers:
90 - name: wget
91 image: busybox
92 command: ['wget']
93 args: ['RELEASE-NAME-springboot:8080']
94 restartPolicy: Never
I love this command because it locally renders the templates by replacing all the placeholders with its actual values.
There is one more sanitary command lint provided by helm which you could run to identify possible issues forehand.
1helm lint springboot
1==> Linting springboot
2[INFO] Chart.yaml: icon is recommended
3
41 chart(s) linted, 0 chart(s) failed
As you can see the command output 1 chart(s) linted, 0 chart(s) failed. So there is no failure and you are good to go.
<
/>
5. helm -debug -dry-run
The next check which we are going to do is -dry-run. Helm is full of such useful utility which allows developer to test its configuration before running the final install command
Use the following -dry-run command to verify your Spring Boot Helm Chart
1helm install springboot --debug --dry-run springboot
If there is something wrong with your Helm chart configuration then it will going to prompt you immediately.
<
/>
6. helm install
Alright lets run the install command.
1helm install myfirstspringboot springboot
Lets break down the command because if you are doing it for the first time then it might be little confusing for you.
There are two name which we used during the installation command -
- myfirstspringboot : It's a release name for helm chart otherwise helm will generate its own release name that is why we have assigned this name.
- springboot : It is our actual chart name which we created in Step 2.
7. Verify the helm install
Next question which comes into my mind - "How to see all the releases? "
Use the following list command to list down all the releases -
1helm list -a
It should return you the release .i.e. - myfirstspringboot which we did in the Step 6.
Lets do some cross verification using kubectl commands also, so that we can make sure helm has done its work.
1kubectl get all
Now we have installed our first helm chart of springboot application. Lets test the spring boot application by accessing it
1curl 10.233.28.240:8080/hello
1Hello - Jhooq-k8s
As you can it return with a response Hello - Jhooq-k8s.
Kudos if you made this far then I would say you learned "How to create and install your first Helm Chart"
8. Upgrade helm release
There is one more feature of Helm Chart which is helm upgrade. It makes it easy for devops to release the new version of application.
Lets take the same myfirstspringboot release and update its replicaCount from 1 to 2
But before we need to update the replicaCount. First we need to udpate the version in Chart.yaml from 0.1.0 to 0.1.1
1apiVersion: v2
2name: springboot
3description: A Helm chart for Kubernetes
4type: application
5version: 0.1.1
6appVersion: 1.16.0
Alright now lets update the replicaCount in values.yaml
1replicaCount: 2
2image:
3 repository: rahulwagh17/kubernetes:jhooq-k8s-springboot
4 pullPolicy: IfNotPresent
5 tag: ""
6imagePullSecrets: []
7nameOverride: ""
8fullnameOverride: ""
9serviceAccount:
10 create: true
11 annotations: {}
12 name: ""
13podAnnotations: {}
14podSecurityContext: {}
15
16securityContext: {}
17service:
18 type: ClusterIP
19 port: 8080
20ingress:
21 enabled: false
22 annotations: {}
23 hosts:
24 - host: chart-example.local
25 paths: []
26 tls: []
27resources: {}
28
29autoscaling:
30 enabled: false
31 minReplicas: 1
32 maxReplicas: 100
33 targetCPUUtilizationPercentage: 80
34
35nodeSelector: {}
36
37tolerations: []
38
39affinity: {}
Okay now we are done with the update and ready to make our new release upgrade. Use the following command -
1helm upgrade myfirstspringboot .
You should see a message with your release name .i.e. - Release "myfirstspringboot" has been upgraded. Happy Helming!
Verify your helm upgrade by running following list command
As you can see now the revision count is 2.
Lets again run kubectl get deployment
1kubectl get deployments
And now you can see we have successfully upgraded the replica count from 1 to 2.
<
/>
9. Rollback Helm release
In the Step 8 we upgraded the Helm chart release from version 1 to version 2.
So let's see one more rollback feature of Helm Chart.
1helm rollback myfirstspringboot 1
As you can see from the above screenshot we successfully rolled back the release to the previous version. But one interesting thing about Helm is, it still updates the REVISION to 3
1helm list -a
To confirm that we have actually rolled back our Helm Chart release, lets run some kubectl commands
1kubectl get deployments
Now as you can see from the screenshot we now have only one replica running for "myfirstspringboot" deployments.
<
/>
10. Delete Helm release
Wouldn't it be nice if you need to run only one command to delete your Helm release and you do not have to do anything else.
1helm delete myfirstspringboot
As you can see now you have successfully delete your release with single helm delete command.
Summary
As I can summarize what we have learned -
- We started from scratch and as a first step we installed Helm Chart on the development box
- Then we created our first Helm Chart using $ helm create springboot
- After the helm chart creation, we went through the structure of Helm Chart
- We explored some of the utility commands provided by the helm .i.e. $ helm template springboot
- Then we have seen how to do -dry-run for the Helm Release
- After verifying our Helm Chart then we executed helm install $ myfirstspringboot springboot
- We used $helm list -a to verify the helm release
- Then we have used $ helm upgrade command to upgrade the release
- Finally, we rolled back and delete the release
You can follow all the above steps for almost any application but provided you have the docker image uploaded to either docker hub or some other container registry.
Read More -
- Helm chart - How to Add/Install plugins
- Getting started with Helm Chart
- Helm chart - WordPress Installation with MariaDB on Kubernetes
- Helm chart - Build you first helm chart with Spring Boot
- Helm Chart - Convert Kubernetes YAML into Helm Chart YAML
- Helm Chart - Pass environment variables
- Helm Chart - Plugin
- Helm Chart - Dry Run Install
- Helm Chart - How to create multiple values files inside helm chart?
- Helmfile - How to use Helmfile for managing helm chart?
Posts in this Series
- How to use Helmfile for managing helm chart?
- How to create multiple values files inside helm chart?
- Pass environment variables into Helm Chart?
- How to fix - Helm install unknown flag --name/Error must either provide a name or specify --generate-name?
- Understanding Helm dry run for template debugging
- How to fix - Error create failed to create Secret invalid metadata.name Invalid value DNS-1123 subdomain must consist of lower case alphanumeric characters - or ., and must start and end with an alphanumeric character (e.g. example.com, regex used for validation is)
- Convert Kubernetes deployment YAML into Helm Chart YAML
- Helm chart - Wordpress Installation with MariaDB on Kubernetes
- Helm chart - How to Add/Install plugins
- Getting Started with Helm Chart
- Building first Helm Chart with Spring Boot Microservices