Templating

In the last chapter we successfully deployed multiple Kubernetes components with a single Helm chart. In this chapter we will be discussing how we can create our own configuration files called values.yaml and how we can use a custom values file to override those of public helm charts.

Exercise - Basic templating

values.yaml is a plain yaml file that contains default configuration values for the helm templates. These values will later be referenced in the templates and can be overridden with the helm install command.

Let’s start with a basic example and make the port property in our postgres service configurable.

nano postgresdb/helmchart/values.yaml

And add the following:

port: 5432

Then edit postgres-service.yaml and include our property:

nano postgresdb/helmchart/templates/postgres-service.yaml

Change this

ports:
  - port: 5432

To this

ports:
  - port: { { .Values.port } }

As you can see we used helms templating syntax {{ }} to reference an attribute of the Values object.

Exercise - Configuring environment variables

You may remember how we changed the name of the postgres deployment from postgresdb to helm-postgresdb. This will break our backend as it’s trying to connect to the host name postgresdb. Fortunately this host name is configurable using an environment variable called POSTGRES_HOST.

You can view this environment variable in todobackend.yaml:

containers:
  - name: todobackend
    env:
      - name: SPRING_PROFILES_ACTIVE
        value: prod
      - name: POSTGRES_HOST
        value: postgresdb

Your job now is to adjust the values file for the todobackend in todobackend/helmchart/values.yaml to include an override for the POSTGRES_HOST property and set it’s value to helm-postgresdb.

Then edit the helm chart template in todobackend/helmchart/templates/todobackend.yaml to include the new property.

Solution

values.yaml

image:
  repository: novatec/technologyconsulting-containerexerciseapp-todobackend
  tag: v0.1

port: 8080
replicaCount: 1

springProfiles: prod
postgresHost: helm-postgresdb

todobackend.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helm-{{ .Chart.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: helm-{{ .Chart.Name }}
  template:
    metadata:
      name: helm-{{ .Chart.Name }}
      annotations:
        rollme: {{ randAlphaNum 5 | quote }}
      labels:
        app: helm-{{ .Chart.Name }}
    spec:
      containers:
        - name: helm-{{ .Chart.Name }}
          image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
          imagePullPolicy: Always
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: {{ .Values.springProfiles }}
            - name: POSTGRES_HOST
              value: {{ .Values.postgresHost }}
      restartPolicy: Always

What is this annotation rollme used for, you might ask? This - in combination with imagePullPolicy: Always - ensures that any deployment of this Helm chart will restart the todobackend with the most recent version of the corresponding image. We will need this later on in the exercises when we start building the images ourselves, that’s why we have it already defined.

More built-in objects

There are some other built-in objects we can address to access additional helm attributes. Here’s a list of the most often used objects and attributes:

  • Release: Contains attributes related to this release

    • Release.Name: The name of the release
    • Release.Namespace: The namespace this release is deployed in
  • Chart: Contains the attributes from Chart.yaml

    • Chart.Name: The name of the chart
    • Chart.Version: The version of the chart

Addressing these objects is done in the same way as with the Values object, e.g.:

{{ .Release.Namespace }}

or

{{ .Chart.Name }}

Exercise - Finish templating the postgresdb helmchart

Now that you have learned how we can use helm’s templating syntax to include external configuration in our template files you can go ahead and apply this knowledge to our postgres helm chart. Please follow these steps to complete this exercise:

  1. Create an attribute in values.yaml for the name of the image
  2. Include the property in the template files (postgres.yaml and postgres-service.yaml)
  3. Replace the hard-coded “postgresdb” with the name of the Chart
Solution

values.yaml

port: 5432
image:
  repository: postgres

postgres.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helm-{{ .Chart.Name }}
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helm-{{ .Chart.Name }}
  template:
    metadata:
      labels:
        app: helm-{{ .Chart.Name }}
        tier: database
    spec:
      containers:
        - image: { { .Values.image.repository | quote } }
          name: helm-{{ .Chart.Name }}
          env:
            - name: POSTGRES_USER
              valueFrom:
                secretKeyRef:
                  name: db-security
                  key: db.user.name
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-security
                  key: db.user.password
            - name: POSTGRES_DB
              valueFrom:
                configMapKeyRef:
                  name: postgres-config
                  key: postgres.db.name

postgres-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: helm-{{ .Chart.Name }}
spec:
  type: ClusterIP
  ports:
    - port: { { .Values.port } }
  selector:
    app: helm-{{ .Chart.Name }}

Exercise - Experimenting with values

You can now install the chart again using the helm install ... command. Try changing the name of the chart in Chart.yaml to ‘mynewpostgresdb’ and see what happens!

Solution
  1. Open Chart.yaml for editing

    nano postgresdb/helmchart/Chart.yaml

  2. Change the name to ‘mynewpostgresdb’

    apiVersion: v2
    name: mynewpostgresdb
    description: postgresdb
    type: application
    version: 0.1.0
    appVersion: 1.16.0
  3. Run helm install to create a release

    helm install postgresdb ./postgresdb/helmchart/

  4. Watch helm create the kubernetes objects

    kubectl get svc,deploy,po

  5. You will see that the kubernetes objects are now called helm-mynewpostgresdb

    NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    service/helm-mynewpostgresdb   ClusterIP   10.98.188.155   <none>        5432/TCP   16s
    
    NAME                                   READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/helm-mynewpostgresdb   1/1     1            1           16s
    
    NAME                                       READY   STATUS    RESTARTS   AGE
    pod/helm-mynewpostgresdb-89f5b945d-dmv95   1/1     Running   0          16s

Exercise - Postgres cleanup

Use helm uninstall again to remove the helm deployment and change the name of the chart back to ‘postgresdb’ in postgresdb/helmchart/Chart.yaml.

Solution

helm uninstall postgresdb

release "postgresdb" uninstalled

Exercise - Using the values parameter to override values

When using charts from public repositories we have no way to access their values file directly, but there are still ways to override those values when installing the chart. The simplest approach is just appending value overrides via helm’s --set flag when installing. Most public helm charts offer a list of overridable values and their default values. The wordpress chart is no exception and here’s an excerpt from its values table:

Parameter Description Default
wordpressUsername User of the application user
wordpressPassword Application password random 10 character long alphanumeric string
wordpressEmail Admin email user@example.com
wordpressBlogName Blog name User’s Blog!

As you can see there’s a multitude of options for configuring the WordPress chart but we are mostly interested in the wordpressBlogName parameter.

Tip

You can obtain the values of any chart with the helm show values <chart> command.

To override this value all we have to do is run the helm install command with a –set flag like this:

helm install --set wordpressBlogName='My Cloud Platform Journey!' wordpress bitnami/wordpress --version 22.3.1.

Tip

It’s always a good idea to escape your string properties with ‘single quotes’!

When your WordPress deployment is ready run curl --silent <your_wordpress_LoadBalancer_IP>/ | grep '<title>' again and you should see that your blog now has a different name!

Solution
<title>My Cloud Platform Journey!</title>

When you’re done with this exercise uninstall the wordpress deployment via helm uninstall wordpress (and possibly also remove the database storage once more via kubectl delete pvc data-wordpress-mariadb-0; yes, there are overrides available for affecting storage persistence but we have not made use of them now) and we can go on with the final exercise in this chapter.

Exercise - Using a values file to override values

While overriding parameters with the –set syntax can be very convenient for ad-hoc changes it may be desirable to be able to store and use a versioning control system for value overrides. Luckily helm offers a second possibility of overriding values by using a custom values file.

To get started simply create and edit a new values file called wordpress-overrides.yaml.

Solution

nano wordpress-overrides.yaml

Then go ahead and add the override for wordpressBlogName to this file:

Solution

Add this line to wordpress-overrides.yaml:

wordpressBlogName: "My Cloud Platform Journey!"

Once we have created our custom values file, all that’s left to do is to run

helm install --values <path to custom values file> wordpress bitnami/wordpress --version 22.3.1.

Solution

helm install --values wordpress-overrides.yaml wordpress bitnami/wordpress --version 22.3.1

NAME: wordpress
LAST DEPLOYED: Mon Jul 22 14:48:52 2024
NAMESPACE: <your_namespace>
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: wordpress
CHART VERSION: 22.3.1
APP VERSION: 6.5.3

** Please be patient while the chart is being deployed **

Your WordPress site can be accessed through the following DNS name from within your cluster:

    wordpress.<your_namespace>.svc.cluster.local (port 80)

To access your WordPress site from outside the cluster follow the steps below:

1. Get the WordPress URL by running these commands:

  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace <your_namespace> -w wordpress'

   export SERVICE_IP=$(kubectl get svc --namespace <your_namespace> wordpress --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}")
   echo "WordPress URL: http://$SERVICE_IP/"
   echo "WordPress Admin URL: http://$SERVICE_IP/admin"

2. Open a browser and access WordPress using the obtained URL.

3. Login with the following credentials below to see your blog:

  echo Username: user
  echo Password: $(kubectl get secret --namespace <your_namespace> wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode)

Run curl --silent <your_wordpress_LoadBalancer_IP>/ | grep '<title>' and you should again see that the blog’s name changed!

<title>My Cloud Platform Journey! &#8211; Just another WordPress site</title>
Tip

Similar to helm show values <chart> for charts we can use helm get values <release> to list the values of any given release.

Exercise - Wordpress cleanup

This concludes the templating chapter. Before we’re taking a look at dependencies of helm charts please uninstall the wordpress release and delete the corresponding database PVC again.

helm uninstall wordpress

kubectl delete pvc data-wordpress-mariadb-0