Thursday, April 15, 2021

Simple Helm example for Kubernetes with Node and Express.

 Please refer to the older post before starting this with Helm uses.

In below example we will try to perform following operation

we will create a helm chart, install it and upload the chart on the public repository. we will also understand update, search, delete chart command using helm client or cli.

In this example we will try to deploy and node application with express that display simple hello world text on the browser using helm and finally we will upload this chart on the public repository of helm.

lets first create simple node-express programe that will show hello world to us on the browser.

C:\vscode-node-workspace\siddhu-node-helloworld

now execute this command to create package.json file

PS C:\vscode-node-workspace\siddhu-node-helloworld> npm init -y
Wrote to C:\vscode-node-workspace\siddhu-node-helloworld\package.json:

{
  "name": "siddhu-node-helloworld",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Modify above package.json file as shown below

{
  "name": "siddhu-node-helloworld",
  "version": "1.0.0",
  "description": "A sample siddhu Node.js app",
  "main": "index.js",
  "dependencies": {
    "express": "^4.17.1"
  },
  "engines": {
    "node": "14.16.0"
  },
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Siddharatha Dhumale",
  "license": "ISC"
}

Create an index.js file with below code

index.js :-


'use strict';

const express = require('express');

// Constants
const PORT = 8080;
const HOST = '0.0.0.0';

// App
const app = express();
app.get('/', (req, res) => {
  res.send('Hello world\n');
});

app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

Now lets run this example in local machine and check if it is working fine.

Run npm install to install all the dependencies.

Then npm start.

Now lets create a docker image of our this application and upload the same on our docker hub.

For that we will first create a docker file as shown below

docker:

from node:14.16.0
# Create app directory
WORKDIR /usr/node/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD [ "npm", "start" ]

Now lets create the docker image from this file

Run command:

docker build -t /

i.e.

docker build -t shdhumale/siddhu-node-helloworld .

This command will create a docker image that we will push to docker hub and later will use in helm chart to deploy the application to the kubernetes cluster.

now lets see the images using the list command of the docker :

docker images

You will find our docker image is created.

Now lets push this in our docker hub using below command.

docker login // To login into dockerhub
docker push shdhumale/siddhu-node-helloworld // push image to your repo



Now check in your repo you will find this docker image ready for use.



Now lets use the helm to perform the operation of installtion of this image in our machine and running it.

Please follow below step religiously :-

1- Install helm

Check its installtion using belwo command

C:\Users\Siddhartha>helm version
version.BuildInfo{Version:”v3.5.3″, GitCommit:”041ce5a2c17a58be0fcd5f5e16fb3e7e95fea622″, GitTreeState:”dirty”, GoVersion:”go1.15.8″}

Step 1:- Create helm chart:

PS C:\vscode-node-workspace\siddhu-node-helloworld> helm create siddhu-helm-chart
Creating siddhu-helm-chart

we have two folder chart and template and two files chart and value.yaml files

Chart.yaml :- this file contains some information like chart version, name , its dependencies i.e. in short it contains meta data for the chart.
Values.yaml :- this files contains configuration template values that can be used in the tempalate applicaiton specific yaml files. This are default values and we can override it later.
charts/ :- this folder contains depenencies that myChartName has. i.e. if we create a chart that is used to deploy elastic stake but in depth it depends on some XYZ chart used to install addition package such as transection,persistant etc.
template/ :- this is the folder that contains all the template files that used to install/update application in K8 cluster using yaml. It will contains the values that is configured in values/yaml files.

Now lets modifiy the required files.

values.yaml:-

image:
  repository: shdhumale/siddhu-node-helloworld #by siddhu give our docker image name
  pullPolicy: IfNotPresent
  # Overrides the image tag whose default is the chart appVersion.
  tag: latest #by siddhu to have the latest version.


service:
  type: NodePort #by siddhu give the nodeport so that we can access it from out side.
  #port: 8080
  exposePort: 30000 #by siddhu expose to node 
  targetPort: 8080 #by siddhu App server listening on this port
  internalPort: 3000 #by siddhu Internal exposed within the pod

service.yaml:-

apiVersion: v1
kind: Service
metadata:
  name: {{ include "siddhu-helm-chart.fullname" . }}
  labels:
    {{- include "siddhu-helm-chart.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
  - nodePort: {{ .Values.service.exposePort }}
      port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "siddhu-helm-chart.selectorLabels" . | nindent 4 }}

Finally we are ready to use the helm

helm install –name siddhu-helm-chart siddhu-helm-chart/

but before that lets check we did not have anything in our minikube

1- First start the minikue using below command

C:\Users\Siddhartha>minikube start
* minikube v1.18.1 on Microsoft Windows 10 Enterprise LTSC 2019 10.0.17763 Build 17763
* minikube 1.19.0 is available! Download it: https://github.com/kubernetes/minikube/releases/tag/v1.19.0
* To disable this notice, run: 'minikube config set WantUpdateNotification false'

* Using the docker driver based on existing profile
* Starting control plane node minikube in cluster minikube
* Restarting existing docker container for "minikube" ...
* Preparing Kubernetes v1.20.2 on Docker 20.10.3 ...
* Verifying Kubernetes components...
! Executing "docker container inspect minikube --format={{.State.Status}}" took an unusually long time: 3.6063039s
* Restarting the docker service may improve performance.
  - Using image gcr.io/k8s-minikube/storage-provisioner:v4
* Enabled addons: storage-provisioner, default-storageclass
* Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

2- then check if we have any container in our minikube with node.

C:\Users\Siddhartha>kubectl get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   14d

Now les Run helm template to 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 –

helm template siddhu-helm-chart

C:\vscode-node-workspace\siddhu-node-helloworld>helm template siddhu-helm-chart
---
# Source: siddhu-helm-chart/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: RELEASE-NAME-siddhu-helm-chart
  labels:
    helm.sh/chart: siddhu-helm-chart-0.1.0
    app.kubernetes.io/name: siddhu-helm-chart
    app.kubernetes.io/instance: RELEASE-NAME
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
---
# Source: siddhu-helm-chart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: RELEASE-NAME-siddhu-helm-chart
  labels:
    helm.sh/chart: siddhu-helm-chart-0.1.0
    app.kubernetes.io/name: siddhu-helm-chart
    app.kubernetes.io/instance: RELEASE-NAME
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  type: NodePort
  ports:
    - nodePort: 30000
      port: 3000
      targetPort: 8080
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: siddhu-helm-chart
    app.kubernetes.io/instance: RELEASE-NAME
---
# Source: siddhu-helm-chart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: RELEASE-NAME-siddhu-helm-chart
  labels:
    helm.sh/chart: siddhu-helm-chart-0.1.0
    app.kubernetes.io/name: siddhu-helm-chart
    app.kubernetes.io/instance: RELEASE-NAME
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: siddhu-helm-chart
      app.kubernetes.io/instance: RELEASE-NAME
  template:
    metadata:
      labels:
        app.kubernetes.io/name: siddhu-helm-chart
        app.kubernetes.io/instance: RELEASE-NAME
    spec:
      serviceAccountName: RELEASE-NAME-siddhu-helm-chart
      securityContext:
        {}
      containers:
        - name: siddhu-helm-chart
          securityContext:
            {}
          image: "shdhumale/siddhu-node-helloworld:latest"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {}
---
# Source: siddhu-helm-chart/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: "RELEASE-NAME-siddhu-helm-chart-test-connection"
  labels:
    helm.sh/chart: siddhu-helm-chart-0.1.0
    app.kubernetes.io/name: siddhu-helm-chart
    app.kubernetes.io/instance: RELEASE-NAME
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
  annotations:
    "helm.sh/hook": test
spec:
  containers:
    - name: wget
      image: busybox
      command: ['wget']
      args: ['RELEASE-NAME-siddhu-helm-chart:']
  restartPolicy: Never

C:\vscode-node-workspace\siddhu-node-helloworld>

As shown above we did not get any error and also our service.yaml, deployment.yaml are created properly.

Also try to run helm lint command lint provided by helm which you could run to identify possible issues forehand.

As shown above we did not get any error.

Now let use the helm command -dry-run. this allows developer to test its configuration before running the final install command

Use the following -dry-run command to verify our siddhu-helm-chart Helm Chart

helm install siddhu-helm-chart –debug –dry-run siddhu-helm-chart

C:\vscode-node-workspace\siddhu-node-helloworld>helm install siddhu-helm-chart --debug --dry-run siddhu-helm-chart
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: C:\vscode-node-workspace\siddhu-node-helloworld\siddhu-helm-chart

NAME: siddhu-helm-chart
LAST DEPLOYED: Thu Apr 15 19:43:07 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
affinity: {}
autoscaling:
  enabled: false
  maxReplicas: 100
  minReplicas: 1
  targetCPUUtilizationPercentage: 80
fullnameOverride: ""
image:
  pullPolicy: IfNotPresent
  repository: shdhumale/siddhu-node-helloworld
  tag: latest
imagePullSecrets: []
ingress:
  annotations: {}
  enabled: false
  hosts:
  - host: chart-example.local
    paths:
    - backend:
        serviceName: chart-example.local
        servicePort: 80
      path: /
  tls: []
nameOverride: ""
nodeSelector: {}
podAnnotations: {}
podSecurityContext: {}
replicaCount: 1
resources: {}
securityContext: {}
service:
  exposePort: 30000
  internalPort: 3000
  targetPort: 8080
  type: NodePort
serviceAccount:
  annotations: {}
  create: true
  name: ""
tolerations: []

HOOKS:
---
# Source: siddhu-helm-chart/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: "siddhu-helm-chart-test-connection"
  labels:
    helm.sh/chart: siddhu-helm-chart-0.1.0
    app.kubernetes.io/name: siddhu-helm-chart
    app.kubernetes.io/instance: siddhu-helm-chart
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
  annotations:
    "helm.sh/hook": test
spec:
  containers:
    - name: wget
      image: busybox
      command: ['wget']
      args: ['siddhu-helm-chart:']
  restartPolicy: Never
MANIFEST:
---
# Source: siddhu-helm-chart/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: siddhu-helm-chart
  labels:
    helm.sh/chart: siddhu-helm-chart-0.1.0
    app.kubernetes.io/name: siddhu-helm-chart
    app.kubernetes.io/instance: siddhu-helm-chart
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
---
# Source: siddhu-helm-chart/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: siddhu-helm-chart
  labels:
    helm.sh/chart: siddhu-helm-chart-0.1.0
    app.kubernetes.io/name: siddhu-helm-chart
    app.kubernetes.io/instance: siddhu-helm-chart
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  type: NodePort
  ports:
    - nodePort: 30000
      port: 3000
      targetPort: 8080
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: siddhu-helm-chart
    app.kubernetes.io/instance: siddhu-helm-chart
---
# Source: siddhu-helm-chart/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: siddhu-helm-chart
  labels:
    helm.sh/chart: siddhu-helm-chart-0.1.0
    app.kubernetes.io/name: siddhu-helm-chart
    app.kubernetes.io/instance: siddhu-helm-chart
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: siddhu-helm-chart
      app.kubernetes.io/instance: siddhu-helm-chart
  template:
    metadata:
      labels:
        app.kubernetes.io/name: siddhu-helm-chart
        app.kubernetes.io/instance: siddhu-helm-chart
    spec:
      serviceAccountName: siddhu-helm-chart
      securityContext:
        {}
      containers:
        - name: siddhu-helm-chart
          securityContext:
            {}
          image: "shdhumale/siddhu-node-helloworld:latest"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {}

NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services siddhu-helm-chart)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT

C:\vscode-node-workspace\siddhu-node-helloworld>

Above text show that we did not have any error in our files.

Now it is the time to execute the final command that will install

helm install siddhu-helm-chart siddhu-helm-chart

C:\vscode-node-workspace\siddhu-node-helloworld>helm install siddhu-helm-chart siddhu-helm-chart
NAME: siddhu-helm-chart
LAST DEPLOYED: Thu Apr 15 19:21:29 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services siddhu-helm-chart)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT

C:\vscode-node-workspace\siddhu-node-helloworld>

Now if you see the command kubectl get all you will see we have deployed our node properly in K8 cluster.

Congratulation our application is successfully running on K8 cluster.
now lets test via browser, get url of the application using below commands:

minikube service list // To get service name

C:\vscode-node-workspace\siddhu-node-helloworld>minikube service list
|————-|——————-|————–|—————————|

NAMESPACENAMETARGET PORTURL
defaultkubernetesNo node port
defaultsiddhu-helm-charthttp/3000http://192.168.49.2:30000
kube-systemkube-dnsNo node port
————-——————-————–—————————

C:\vscode-node-workspace\siddhu-node-helloworld>

minikube service siddhu-helm-chart –url // To get access url for your application

Now let check other command of helm

1:- helm list -a

C:\vscode-node-workspace\siddhu-node-helloworld>helm list -a
NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
siddhu-helm-chart       default         1               2021-04-15 19:43:32.98192 +0530 IST     deployed        siddhu-helm-chart-0.1.0 1.16.0

Now how to upgrade the application version for that you can use the upgrade command of helm.

As shown above the version of the app is 1.16.0 lets change it to new version 1.17.0

C:\vscode-node-workspace\siddhu-node-helloworld\siddhu-helm-chart>helm upgrade siddhu-helm-chart .
Release "siddhu-helm-chart" has been upgraded. Happy Helming!
NAME: siddhu-helm-chart
LAST DEPLOYED: Thu Apr 15 19:52:53 2021
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
1. Get the application URL by running these commands:
  export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services siddhu-helm-chart)
  export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
  

Lets check the image is change by starting the helm

C:\vscode-node-workspace\siddhu-node-helloworld\siddhu-helm-chart>helm list -a
NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
siddhu-helm-chart       default         2               2021-04-15 19:52:53.2377071 +0530 IST   deployed        siddhu-helm-chart-0.1.0 1.17.0

If you see above the REVISION is gone to 2 that means this is second operation we had done on this chart.

Now lets rollback to its original version using rollback command.

to see the effect lets change the replicacount in our values.yaml to 2 from 1.

C:\vscode-node-workspace\siddhu-node-helloworld>helm list -a
NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
siddhu-helm-chart       default         3               2021-04-15 19:58:38.9020264 +0530 IST   deployed        siddhu-helm-chart-0.1.0 1.17.0

C:\vscode-node-workspace\siddhu-node-helloworld>kubectl get deployments
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
siddhu-helm-chart   2/2     2            2           15m

As you can see above now the deployment is 2 and revision is 3 as we had perform 3rd operation on this chart. Now lets roll back to older version using command

helm rollback

helm rollback siddhu-helm-chart 2

C:\vscode-node-workspace\siddhu-node-helloworld>helm rollback siddhu-helm-chart 2
Rollback was a success! Happy Helming!

C:\vscode-node-workspace\siddhu-node-helloworld>
C:\vscode-node-workspace\siddhu-node-helloworld>helm list -a
NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
siddhu-helm-chart       default         4               2021-04-15 20:01:35.3910493 +0530 IST   deployed        siddhu-helm-chart-0.1.0 1.17.0

C:\vscode-node-workspace\siddhu-node-helloworld>kubectl get deployments
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
siddhu-helm-chart   1/1     1            1           18m

As shown above the REVISION is now 4 and we have deploment as 1 becuase i our 2 REVISION we have replicacoutn:1

Now lets see how to delete the chart using delete command.

helm delete

helm delete siddhu-helm-chart

‘- Search package/charts :- helm search

once you install helm and checked its version check if you are getting inbuild stable chart with it. If not then use below command to add the repo to your helm.

helm repo add stable https://charts.helm.sh/stable

you can also check the package directly from the remote hub using thins comamnd

C:\Users\Siddhartha>helm search hub node

for checking local chart use this command

C:\Users\Siddhartha>helm search repo node

3- Now lets take an example in which we will install node applicatoin and access it using browser inside K8 with docker as container.

There are two ways

A:- Either we check if we had a node helm package for node in local repo
B:- we can install the helm package for node from hub.

Lets take scenario-A
A:- Either we check if we had a node hlem package for node in local repo

Lets check if we have node in our local repo we can do this using follwing command

C:\Users\Siddhartha>helm search repo node
NAME                            CHART VERSION   APP VERSION     DESCRIPTION
stable/node-problem-detector    1.8.3           v0.8.1          DEPRECATED - Installs the node-problem-detector...
stable/node-red                 1.4.3           1.0.4           Node-RED is low-code programming for event-driv...
stable/prometheus-node-exporter 1.11.2          1.0.1           DEPRECATED A Helm chart for prometheus node-exp...
stable/acs-engine-autoscaler    2.2.2           2.1.1           DEPRECATED Scales worker nodes within agent pools
stable/aws-cluster-autoscaler   0.3.4                           DEPRECATED Scales worker nodes within autoscali...
stable/cloudserver              1.0.7           8.1.5           DEPRECATED An open-source Node.js implementatio...
stable/cluster-autoscaler       8.0.0           1.17.1          Scales worker nodes within autoscaling groups.
stable/ignite                   1.2.2           2.7.6           DEPRECATED - Apache Ignite is an open-source di...
stable/magic-ip-address         0.1.2           0.9.0           DEPRECATED - A Helm chart to assign static IP a...
stable/stellar-core             1.0.2           10.0.0          DEPRECATED Backbone node of the Stellar cryptoc...
stable/ghost                    9.1.13          3.9.0           DEPRECATED A simple, powerful publishing platfo...
stable/rocketchat               2.0.10          3.6.0           DEPRECATED - Prepare to take off with the ultim...
stable/verdaccio                0.7.8           3.11.6          DEPRECATED - A lightweight private npm proxy re...

But as you see in above list we did not get the node version which we are looking.

Now lets check the same in hub

B:- we can install the helm package for node from hub.

1- Go directly to the below helm hub site and search for node.

https://artifacthub.io/




We will have two command

1- helm repo add bitnami https://charts.bitnami.com/bitnami
this will add all the binami node meta data to our local repo
2- helm install my-release bitnami/node
this will install it in our K8 environment

We can also pull the files in local using pull commmand and then use the install command
helm pull my-release bitnami/node
helm install my-release bitnami/node

Create our own repository and create a new package and update on the helm repository

Download code :-
https://github.com/shdhumale/siddhu-node-helloworld.git
https://hub.docker.com/repository/docker/shdhumale/siddhu-node-helloworld

No comments: