Skip to main content
  1. Posts/

Running database migrations in Helm chart

··584 words·3 mins
Author
Hairizuan Noorazman
Software engineering experiments, implementation notes, and lessons learned.

In many examples for helm charts, the general focus is on the “2nd” day operations of having applications running without too much issues. In the case for usual web developers, that would mean applications handled with kubernetes deployment objects which would run a set number of replicas (or handled via HPA) in the kubernetes cluster.

However, what if the application needs to rely on a database? The one important thing when it comes to applications that rely on database is that we need to have a way to do database migrations. The database migrations could be run via sql scripts or even binaries that run certain set of sql operations to set the initial scheme for the database that we would need to setup for our application.

Let’s say our database is in the kubernetes cluster (sometimes, a controversial choice). We can simply run the commands to do the migration from our “deployment” machine. The deployment machine could be some jenkins server that run some shell script that would then do the sql migration on the database. But this would mean that the database migration is something outside application upgrade lifecycle which eventually would mean a harder process to grasp for developers of the application to deal with application upgrades as well as updates to database schema.

Fortunately for us, Helm has a mechanism - lifecycle hook mechanisms. Reference: https://helm.sh/docs/topics/charts_hooks/. We can run certain application of kubernetes objects (e.g Kubernetes jobs) to do certain things that we need to do before our application properly start up - e.g. we can setup a lifecycle helm hook that would set up a Kubernetes job - which in our case would be a database migration job.

Here is an example that we can refer to for explaning an example of how we can do this: https://github.com/hairizuanbinnoorazman/Go_Programming/tree/master/Web/basicMigrate

The first part would be deploy a database - a Maria database (a MySQL compatible database)

helm install -f db-values.yaml mariadb oci://registry-1.docker.io/bitnamicharts/mariadb

That would set up a single replica database with a a set amount of resources which we can then have our application rely on.

Our application’s helm chart is in the basicMigrate folder in the reference url above. The important bit to tap for the helm hooks is the annotations on the Kubernetes job. Do note that the database credentials set via environment variables are only for example purposes. It would be better to rely on a proper secret management system to ensure that none of such credentials could be leaked out so easily.

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "basicMigrate.fullname" . }}-migrate
  labels:
    {{- include "basicMigrate.labels" . | nindent 4 }}
  annotations:
    "helm.sh/hook": pre-install,pre-upgrade
    "helm.sh/hook-weight": "0"
    "helm.sh/hook-delete-policy": before-hook-creation
spec:
  backoffLimit: 5
  activeDeadlineSeconds: 300
  template:
    labels:
      {{- include "basicMigrate.labels" . | nindent 6 }}
    spec:
      serviceAccountName: {{ include "basicMigrate.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      restartPolicy: Never
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          command:
            - "app"
            - "migrate"
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
          env:
            - name: DATABASE_USER
              value: "username"
            - name: DATABASE_PASSWORD
              value: "password"
            - name: DATABASE_HOST
              value: "mariadb.default.svc"
            - name: DATABASE_NAME
              value: "application"

For the above database migration jobs, we will set up the database migraiton job before the install or upgrade of our application. This is based off "helm.sh/hook": pre-install,pre-upgrade.

We can install the helm chart via the following command:

helm upgrade --install -f app-values.yaml basic ./basicMigrate

Related

Access Cloud SQL from Google Kubernetes Cluster without Cloud SQL Proxy

··673 words·4 mins
Introduction # Similar to my previous blog post, we would usually be connecting Google Kubernetes Engine (GKE) clusters to Cloud SQL databases by using the Cloud SQL Proxy. However, we can now use Private Service Connect, which allows for private communication between different Google Cloud services, similar to how we did for connecting our application in Google Compute Engine (VM) to a Cloud SQL instance.

Storing Helm in Docker Registries

··278 words·2 mins
We can apparently now store helm charts in Docker registries - this was made available via helm commands since v3.8.0. https://helm.sh/docs/topics/registries/ Now with that being available for use, we can now use it across a variety of storage mechanism (as compared in the past when the artifacts produced through it has to be managed in some of file system and would require some of index file to list all available helm charts available).

Deploy Golang Apps that interact with headless service in Kubernetes

In certain application scenarios - there is a need to have applications that need to do client side load balancing to a bunch of servers. Such cases are pretty rare - but we won’t be covering the exect reasons or scenarios or when these are needed. Instead, we will cover how we can do so with Golang applications in Kubernetes cluster.

Altering outputs of helm installations with post-renderer via kustomize

··976 words·5 mins
When one thinks of Kubernetes and deploying stuff into Kubernetes, one of the usual ways to get such stuff into Kubernetes is through the use of Kubernetes manifest files. Kubernetes manifest files describe various different resources in Kubernetes cluster - some primary examples that are often used are Deployment, Configmap, Secret, Service and even Ingress Kubernetes resources/objects.