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
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
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 inYAML 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
3.5.5 Confirm Kubernetes Objects
To check if the Kubernetes objects were created successfully, use the commands from the table below
Kubernetes Get Commands | Description |
---|---|
kubectl get deployments | Checks if the Deployment was created |
kubectl get pods | List all pods in the namespace |
kubectl get service | List 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.
You can download the full source code of this example here: Explore Using Liquibase in Kubernetes