Package and distribute the VotingApp with Helm

In this exercise, you will package the VotingApp application into a Helm Chart.

  1. Install the Helm Client

If you do not already have the Helm client installed, you can do so using the following command:

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh
  1. Creating a Helm Chart

Use the following command to create a Chart named vote.

helm create vote

By default, it includes the following elements:

  • a Chart.yaml file that defines the project metadata
  • a template for creating a Deployment that manages a single Pod (based on nginx)
  • a template for creating a Service to expose this Pod within the cluster
  • a template for creating an Ingress resource to expose the service externally
  • a values.yaml file used to substitute placeholders in the templates with dynamic values
  • a NOTES.txt file that provides information on creating the release and during updates

You can view its contents using the tree command (install it first with “sudo apt install tree”):

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

First, in the templates directory, delete the yaml files, the NOTES.txt file, and the test directory.
Next, copy all the manifests from VotingApp into the templates directory.
Also, delete the contents of the values.yaml file but do not delete the file itself.

The vote directory will then have the following contents:

$ tree vote/
vote/
├── Chart.yaml
├── charts
├── templates
│   ├── _helpers.tpl
│   ├── cronjob.yaml
│   ├── deploy-db.yaml
│   ├── deploy-redis.yaml
│   ├── deploy-result.yaml
│   ├── deploy-resultui.yaml
│   ├── deploy-vote.yaml
│   ├── deploy-voteui.yaml
│   ├── deploy-worker.yaml
│   ├── ingress.yaml
│   ├── pvc-db.yaml
│   ├── pvc-redis.yaml
│   ├── secret-db.yaml
│   ├── svc-db.yaml
│   ├── svc-redis.yaml
│   ├── svc-result.yaml
│   ├── svc-resultui.yaml
│   ├── svc-vote.yaml
│   └── svc-voteui.yaml
└── values.yaml
  1. Deploying the Application

From the vote directory, deploy the application using the following command:

helm upgrade --install vote .

You should see a result similar to the one below:

Release "vote" does not exist. Installing it now.
NAME: vote
LAST DEPLOYED: Tue Feb 13 10:27:48 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

Then, check that all the Pods of the VotingApp are in the Running status:

$ kubectl get po
NAME                         READY   STATUS      RESTARTS   AGE
worker-56b544777-nt6wf       1/1     Running     0          45s
result-ui-5cdd74d999-bpwkj   1/1     Running     0          45s
vote-6c847fd45-jqvhr         1/1     Running     0          45s
vote-ui-74849dd9b4-gbmbp     1/1     Running     0          45s
redis-5c4f4598f5-n8kxf       1/1     Running     0          45s
result-854cd4779c-w4jhm      1/1     Running     0          45s
db-54d89ccb97-nxz7v          1/1     Running     0          45s
seed-28463608-dwgst          0/1     Completed   0          34s

Ensure that the application is accessible at http://vote.votingapp.com / http://result.votingapp.com (or at http://vote.IP_OF_YOUR_VM.nip.io / http://result.IP_OF_YOUR_VM.nip.io if you are using the nip.io approach)

Vote

Result

  1. Using the Helm templating
  • Image Tags

You will ensure that image tags are no longer based on latest (which is actually a very bad practice) but on a value specified in the values.yaml file. First, add the following content to values.yaml:

registry: voting
voteui:
  tag: v1.0.19
vote:
  tag: v1.0.13
worker:
  tag: v1.0.15
result:
  tag: v1.0.16
resultui:
  tag: v1.0.15
tools:
  tag: v1.0.4

Then, modify the specifications of the Deployments voteui, vote, worker, result, and resultui so that the image name is generated from the values of the registry property and the corresponding tag for the microservice. For example, the specification for the voteui Deployment will be modified as follows:

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: vote-ui
  name: vote-ui
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vote-ui
  template:
    metadata:
      labels:
        app: vote-ui
    spec:
      containers:
        - image: {{ .Values.registry }}/vote-ui:{{ .Values.voteui.tag }}
          name: vote-ui
  • Regular Vote Generation

You will now configure the creation of 5 dummy votes every 2 minutes. Add the following content to the end of the values.yaml file:

# Add dummy votes on a regular basis
seed: enabled
schedule: "*/2 * * * *"
number_of_votes: 5

Then, modify the cronjob.yaml specification as follows:

{{ if .Values.seed }}{{ if eq .Values.seed "enabled" }} 
apiVersion: batch/v1
kind: CronJob
metadata:
  name: seed
spec:
  schedule: "{{ .Values.schedule }}"
  jobTemplate:
    metadata:
      name: seed
    spec:
      template:
        spec:
          containers:
          - image: voting/tools:{{ .Values.tools.tag }}
            name: seed
            env:
            - name: NUMBER_OF_VOTES
              value: "{{ .Values.number_of_votes }}"
            imagePullPolicy: Always
          restartPolicy: OnFailure
{{ end }}{{ end }}

This specification uses Helm templating language:

  • The cronjob is created only if the seed property exists and is equal to “enabled” in the values file
  • The schedule for the cronjob is retrieved from the schedule property in the values file
  • The number of votes is defined in the NUMBER_OF_VOTES environment variable, with the value also retrieved from the values file

Update the application using the same command used for creation:

helm upgrade --install vote .
ℹ️
The values.yaml file is used by default

The second revision of the application will then be created:

Release "vote" has been upgraded. Happy Helming!
NAME: votingapp
LAST DEPLOYED: Tue Feb 13 11:05:21 2024
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None

You will also see that the different Pods have been recreated to account for the changes made in their specifications:

$ kubectl get po
NAME                         READY   STATUS      RESTARTS   AGE
db-54d89ccb97-mp28m          1/1     Running     0          31m
redis-5c4f4598f5-wgw2r       1/1     Running     0          31m
seed-28463643-s2kzd          0/1     Completed   0          2m34s
seed-28463644-n5b4w          0/1     Completed   0          94s
seed-28463645-4kmqc          0/1     Completed   0          34s
result-ui-76bdf59f99-qks6w   1/1     Running     0          13s
vote-779875ff5b-t7drr        1/1     Running     0          13s
vote-ui-695759b448-c7jgw     1/1     Running     0          13s
result-66f5856c8b-xp9d6      1/1     Running     0          13s
worker-6c5d7ddcf5-hprn7      1/1     Running     0          12s

From the result interface, verify that 5 new votes are being created every 2 minutes.

  1. Uninstalling the Application

Use the following command to uninstall the application:

helm uninstall vote
  1. Distributing the Application

A Helm Chart can easily be packaged and distributed to an OCI registry like DockerHub.

First, use the following command to log in to Docker Hub (if you don’t have a Docker Hub account, you can create one for free in just a few minutes):

echo $DOCKERHUB_PASSWORD | helm registry login registry-1.docker.io -u $DOCKERHUB_USERNAME --password-stdin

Then, create a package of the application (specifying version v0.0.1 for the application):

helm package --version v0.0.1 .

You can then push this package to DockerHub:

helm push vote-v0.0.1.tgz oci://registry-1.docker.io/$DOCKERHUB_USERNAME

The application is now available and ready to be retrieved from Docker Hub.

DockerHub

DockerHub