Getting started with Helm Kubernetes Package Manager

In this short blog post, we will look at getting starting with Helm. Helm is a package manager for Kubernetes, similar to Apt, RPM, Yum to install Linux packages.  In the Cloud Native space  Helm can be used to install, update and package applications that are deployed to a Kubernetes cluster.

Installing packages with Helm is as simple as adding a repository with helm repo add <<repo_name>> << charts_url >> and then running helm install bitnami/nginx  <<name>. The quickstart guide on the Helm site is a great resource to get started – https://helm.sh/docs/intro/quickstart/

In addition to installing applications to a Kubernetes platform Helm can be used to package your own application for easy deployment.

Before we get into some of the details of creating a sample helm chart, let’s look at the main concepts. With Helm, there are some important concepts,

  • Charts –  A chart is information required to create an instance of a Kubernetes application.
  • Config – A collection of configuration files that gets packaged into the chart
  • Repo – A place to store charts
  • Release –  A release is a running instance of a chart that would have its own release name.  On a Kubernetes cluster, there can be more than one instance of the same chart each with its own release name.

Packaging an application into a Helm Chart

With the introductory concepts out of the way let’s look at creating a sample  Helm Chart.  At a very high level creating a helm chart involves defining variables in the Kubernetes manifest files and providing values for those variables as part of the Helm package. Helm then parses the manifest files through its templating engine substituting the defined variables.

In this example, I’m using the sample PHP GuestBook application, the manifest files can be found here PHP GuestBook. The application contains a front-end pod with a front-end service and a mongo DB pod with its service. To get started we will run,

helm create guestbook

This will create a directory structure that looks like the below output with some boilerplate manifests that we can leverage. To package the guestbook application we will place the deployment and service manifest in the template directory, we can also get rid of the boilerplate YAML files.


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

We will now edit the mongo deployment manifest and add variables in the YAML file. Helm provides built-in objects such as the Release, Chart, Values objects that we can use in our manifest files, In this case, I have defined values for variables in the helm values.yaml file.
The frontend pods and the mongo DB pods can also be split into two different charts with their own values.yaml. In this way, the mongo DB pod can be updated independently from the frontend application

Below spec is the deployment and service manifest for the frontend pod. I’ve provided variables for the name of deployment/service, the number of replicas, image repository and image version. Similar variables are added to the deployment and service manifest of the mongo DB pod.


apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{.Values.fe_deploy.name}}
  labels:
    app.kubernetes.io/name: guestbook
    app.kubernetes.io/component: frontend
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: guestbook
      app.kubernetes.io/component: frontend
  replicas: {{.Values.fe_deploy.replicas}}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: guestbook
        app.kubernetes.io/component: frontend
    spec:
      containers:
      - name: {{.Values.fe_deploy.name}}
        image: {{.Values.fe_deploy.images.repository}}:{{.Values.fe_deploy.images.version}}
        # image: {{.Values.fe_deploy.images.repository}}:{{.Values.fe_deploy.images.version}}
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        env:
        - name: GET_HOSTS_FROM
          value: dns
        ports:
        - containerPort: 8
---
apiVersion: v1
kind: Service
metadata:
  name: {{.Values.fe_svc.name}}
  labels:
    app.kubernetes.io/name: guestbook
    app.kubernetes.io/component: frontend
spec:
  # if your cluster supports it, uncomment the following to automatically create
  # an external load-balanced IP for the frontend service.
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30007
  selector:
    app.kubernetes.io/name: guestbook
    app.kubernetes.io/component: frontend
---

Now that variables are defined in the Kubernetes manifest files we need to provide values for these variables. To do so we will edit the values.yaml in that directory and define values for our variables.


mongo_deploy:
 name: gb-mongo
 replicas: 1
 images:
  version: 4.2

mongo_svc:
 name: mongo


fe_deploy:
 name: gb-frontend
 replicas: 3
 images:
  repository: paulczar/gb-frontend
  version: v5

fe_svc:
 name: gb-frontend-svc

To test that our helm package works and the variables are substituted correctly we can run helm install with the –dry-run option. The output should provide Kubernetes manifests with the defined values.

helm install guestbook –dry-run ./guestbook

To install our application we run

helm install guestbook ./guestbook

We can validate the status of our application by running kubectl get pods to verify if all the pods are running. We can run helm list to list installed charts



~/ helm list
NAME             NAMESPACE REVISION  UPDATED                                STATUS   CHART              APP VERSION
guestbook        default   1         2021-06-10 02:33:16.280572 +1000 AEST deployed  guestbook-0.1.0    1.16.0
nginx-1623140150 default   1         2021-06-08 18:15:54.889611 +1000 AEST deployed  nginx-9.1.0        1.21.0