Software Development

Explore Using Liquibase in Kubernetes

This article provides a comprehensive guide on using Liquibase, a popular database version control tool, in Kubernetes environments.

1. Introduction to Liquibase and Kubernetes

1.1 What is Liquibase

Liquibase is an open-source database schema change management solution that enables developers to manage database changes. It allows developers to release and revise database changes faster from development to production.

1.2 What is Kubernetes

Kubernetes is an open-source container orchestration tool that automates the deployment, scaling, and management of containerized applications.

1.3 Benefits of Using Liquibase in Kubernetes

Using Liquibase in Kubernetes brings version control, rollback capabilities, and automation to your database schema management process for containerized applications running on Kubernetes. The list below outlines and explains some benefits of using Liquibase in Kubernetes.

  • Version Control for Database Changes: Liquibase allows developers to version control their database schema changes, just like with code changes.
  • Automated Database Schema Management: Liquibase allows developers to define database schema changes in a declarative manner using XML, YAML, or JSON formats. By integrating Liquibase with Kubernetes, developers can automate the application of these changes to their database, reducing the manual effort required to manage database schemas.
  • Rollback Support: Kubernetes enable easy rollback to previous versions. If a database schema change causes issues, developers can easily roll back to a previous version of the schema.
  • Continuous Deployment and CI/CD Integration: Integrating Liquibase with Kubernetes allows developers to include database schema changes as part of their continuous deployment process, ensuring that both application and database changes are deployed in sync.

2. Setting up a Kubernetes Cluster

Kubernetes runs in containers. To set up a Kubernetes cluster, firstly, we will need to install Docker Desktop and have it running. To get a Kubernetes cluster running on a Mac, Click on the whale Docker logo in the menu bar and select Preferences. A screen opens with the Docker Desktop configuration options. Next, Click on Kubernetes and check the Enable Kubernetes checkbox and click on the Apply and Restart button. Docker Desktop will download all the Kubernetes images and get everything started up. After everything is started up and ready, there would be a green light at the bottom of the screen settings indicating that Kubernetes is running as shown in the image below

Fig 1.0 Screenshot of Kubernetes running on Docker Desktop
Fig 1.0 Screenshot of Kubernetes running on Docker Desktop

2.1 Verify Kubernetes Cluster

Kubernetes uses kubectl to manage apps and containers. Docker Desktop installs kubectl and to check the state of the Docker Desktop Kubernetes cluster, run the following command below on a terminal

kubectl get nodes

The result of running the command outputs a single node called docker-destop which is a full Kubernetes cluster that runs the Kubernetes API server as shown below


Fig 1.1 Output from running kubectl get nodes on a terminal
Fig 1.1 Output from running kubectl get nodes on a terminal

3. Deploying a Database in Kubernetes

In this section, we will deploy a MySQL database to the Kubernetes cluster we set up in our local host machine. We will create a MySQL deployment, add persistent storage, and expose the deployment with a service. We will be using YAML/YML files to define our Kubernetes resources. The list below provides detailed explanations of some Kubernetes terminologies that would be used to accomplish this.

  • PersistentVolume: A Kubernetes object that is a piece of storage in the cluster.
  • PersistentVolumeClaim: A request for storage by a user.
  • Pod: Small deployable units that encapsulate applications that you can create and manage in Kubernetes.
  • Service: A Kubernetes Object that provides a way to access a pod or container.
  • Deployment: A Kubernetes Object that monitors a set of pods and ensures that these pods are running and also makes sure to restart them if they are down.
  • Kubernetes Config File: A file that is written in YAML or YML that tells Kubernetes about the different objects to be created.

3.1 Create a PersistentVolume

First, create a folder named javacodegeeks or any name of your choice and navigate into the folder. Next, create a YAML/YML file named mysql-persistentvolume.yml to create a PersistentVolume with the following content

## YAML Template.
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-persistentvolume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"

3.2 Create a PersistentVolumeClaim

Create a file name mysql-persistentvolumeclaim.yml that would be used to create the PersistentVolumeClaim. This will add persistent storage to the MySQL pod which will request for 1GB of storage with ReadWriteOnce access mode. Below is the content of the mysql-persistentvolumeclaim.yml file

## YAML Template.
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-persistentvolumeclaim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

3.3 Create MySQL Deployment Pod

Next, we will create a deployment object to manage the pod running a MySQL container with the necessary configuration and also with a reference to the PersistentVolumeClaim. Create a YAML/YML file called mysql-deployment.yml in the same folder with the following content

## YAML Template.
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - image: mysql:8.0.23
          name: mysql
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: password
          ports:
            - containerPort: 3306
              name: mysql
          volumeMounts:
            - name: mysql-persistent-storage
              mountPath: /var/lib/mysql
      volumes:
        - name: mysql-persistent-storage
          persistentVolumeClaim:
            claimName: mysql-persistentvolumeclaim

3.4 Create a Service to Expose MySQL

Next is to create a service object that will permit other pods to access the MySQL database pod. We will create a service object that will expose port 3306 for the MySQL database. Create a YML/YAML file named mysql-service.yml with the following contents

## YAML Template.
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-service
spec:
  ports:
    - port: 3306
  selector:
    app: mysql
  clusterIP: None

3.5 Apply Config Files

Now we will use the kubectl apply command to tell Kubernetes to use the config files to create a Persistent Volume, a Persistent Volume Claim, a Deployment that manages a Pod containing MySQL and a Service that allows access to the Pod. Note that this command should be applied in sequential order.

3.5.1 STEP 1: Apply the PersistentVolume

Create the PersistentVolume with the following command

kubectl apply -f mysql-persistentvolume.yml 

3.5.2 STEP 2: Apply the PersistentVolumeClaim

Create the PersistentVolumeClaim with the following command

kubectl apply -f mysql-persistentvolumeclaim.yml 

3.5.3 STEP 3: Create the Deployment

Create the deployment with the following command

kubectl apply -f mysql-deployment.yml

3.5.4 STEP 4: Create the Service

Create the service with the following command

kubectl apply -f mysql-service.yml

The output on a terminal from applying the above commands is shown below

Fig 2.0 Output from applying kubectl command on config files
Fig 2.0 Output from applying kubectl command on config files

3.5.5 Confirm Kubernetes Objects

To check if the Kubernetes objects were created successfully, use the commands from the table below

Kubernetes Get CommandsDescription
kubectl get deploymentsChecks if the Deployment was created
kubectl get podsList all pods in the namespace
kubectl get serviceList all services in the namespace

4. Installing Liquibase in Kubernetes

From the research done, the best method to use Liquibase in Kubernetes is to make use of init containers. There is an official Liquibase base image to use in Kubernetes. An initContainer runs before the main container which means that the init container will run Liquibase to update the database schema before our main application container starts.

4.1 Liquibase Set up

Liquibase needs Java to run. First, create an independent Dockerfile for the initContainer. This file would contain the Liquibase tool and the dependencies needed such as the JDBC driver for MySQL mysql-connector-java-8.0.23.jar .

In the project folder, create a file named Dockerfile. The code below shows the content of the Dockerfile.

FROM openjdk:8-jdk-alpine

RUN apk add --update bash curl

ENV LIQUIBASE_VERSION=4.22.0

RUN curl -L https://github.com/liquibase/liquibase/releases/download/v${LIQUIBASE_VERSION}/liquibase-${LIQUIBASE_VERSION}.tar.gz \
    | tar -xz -C /opt \
    && ln -s /opt/liquibase-${LIQUIBASE_VERSION}/liquibase /usr/local/bin/liquibase

RUN curl -L https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.23/mysql-connector-java-8.0.23.jar \
    -o /opt/mysql-connector-java-8.0.23.jar

4.2 Create a Kubernetes Deployment for the Application

Next, create a new Kubernetes deployment for the application.

4.2.1 Use Init Containers to run Migration

Let’s configure Kubernetes to use the Dockerfile as an initContainer. Create the deployment definition YAML/YML file named new-app-deployment.yml in the same folder and add the following content

## YAML Template.
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      initContainers:
      - name: liquibase
        image: liquibase/liquibase:latest
        env:
        - name: LIQUIBASE_URL
          value: jdbc:mysql://mysql-database:3306/database-name
        - name: LIQUIBASE_USERNAME
          value: user
        - name: LIQUIBASE_PASSWORD
          value: password
        command: ["liquibase", "update"]
        volumeMounts:
        - name: liquibase-config
          mountPath: /liquibase/
      - name: mysql
        image: mysql:latest
        ports:
        - containerPort: 8080
        env:
        - name: DATABASE_URL
          value: jdbc:mysql://mysql-database:3306/database-name
        - name: DATABASE_USERNAME
          value: user
        - name: DATABASE_PASSWORD
          value: password
      volumes:
      - name: liquibase-config
        configMap:
          name: liquibase-config

4.3 Create a ConfigMap to Store Liquibase ChangeLogs

ConfigMaps are components of Kubernetes that are used to maintain container images by separating the configuration settings. It is recommended to store the Liquibase ChangeLog file in Kubernetes using ConfigMaps. Now, let’s create a ConfigMap to store our Liquibase configuration settings. Create a YAML/YML file named config-map.yml and add the following content

## YAML Template.
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: liquibase-config
data:
  liquibase.properties: |
    changeLogFile: /liquibase/changelog/changelog.xml
    driver: com.mysql.cj.jdbc.Driver
    classpath: /liquibase/mysql-connector-java-8.0.23.jar

To create the ConfigMap , run the following command from a terminal

kubectl create configmap liquibase-config --from-file=conf=config-map.yml 

4.4 Run the Deployment

To run the deployment in the Kubernetes cluster, run the following command

kubectl apply -f new-app-deployment.yml

5. Conclusion

In this article, we learned how to use Liquibase in Kubernetes to perform database migrations. We have seen how to enable a Kubernetes cluster using Docker Desktop and also learned about how to deploy a Database in Kubernetes. In conclusion, Using initContainers in Kubernetes to run database migrations with Liquibase is an efficient way to manage database changes.

6. Download the Project

This was a blog post on Using Liquibase in Kubernetes.

Download
You can download the full source code of this example here: Explore Using Liquibase in Kubernetes

Omozegie Aziegbe

Omos holds a Master degree in Information Engineering with Network Management from the Robert Gordon University, Aberdeen. Omos is currently a freelance web/application developer who is currently focused on developing Java enterprise applications with the Jakarta EE framework.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button