Enabling DB Migrations Using Kubernetes Init
Learn how to use Kubernetes init in order to migrate your database, with a helping hand from Liquibase.
Join the DZone community and get the full member experience.
Join For FreeLiquibase is an open-source database-independent library for tracking, managing, and applying database changes. It allows developers to version control their database changes and easily roll them out in a controlled and predictable manner.
Kubernetes, on the other hand, is an open-source container orchestration system that automates the deployment, scaling, and management of containerized applications.
When deploying a containerized application on Kubernetes, it is common to use an init container to perform any necessary setup tasks before the main application container starts. This can include tasks such as installing dependencies, configuring environment variables, or running database migrations.
In this article, we will show you how to set up an init container in Kubernetes to run Liquibase migrations on your database.
Liquibase Setup
To use Liquibase in an init container, we first need to create a Docker image that contains the Liquibase tool and any necessary dependencies, such as a JDBC driver for the database. The following Dockerfile can be used to create an image that includes Liquibase and the MySQL JDBC driver:
FROM openjdk:8-jdk-alpine
RUN apk add --update bash curl
ENV LIQUIBASE_VERSION=4.1.1
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.22/mysql-connector-java-8.0.22.jar \
-o /opt/mysql-connector-java-8.0.22.jar
Before we begin, make sure that you have the following prerequisites:
- A Kubernetes cluster set up and running
- A database running in a separate container or on a separate host
- A Liquibase project set up for your application
Here are the steps you need to follow:
- Create a new Kubernetes deployment for your application. In the deployment definition, specify the init container and the main application container.
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
initContainers:
- name: liquibase
image: liquibase/liquibase:latest
env:
- name: LIQUIBASE_URL
value: jdbc:postgresql://my-database:5432/my-database
- name: LIQUIBASE_USERNAME
value: my-user
- name: LIQUIBASE_PASSWORD
value: my-password
command: ["liquibase", "update"]
volumeMounts:
- name: liquibase-config
mountPath: /liquibase/
- name: my-app
image: my-app:latest
ports:
- containerPort: 8080
env:
- name: DATABASE_URL
value: jdbc:postgresql://my-database:5432/my-database
- name: DATABASE_USERNAME
value: my-user
- name: DATABASE_PASSWORD
value: my-password
volumes:
- name: liquibase-config
configMap:
name: liquibase-config
- Create a configMap to store the Liquibase configuration files.
apiVersion: v1
kind: ConfigMap
metadata:
name: liquibase-config
data:
liquibase.properties: |
changeLogFile: /liquibase/changelog.xml
driver: org.postgresql.Driver
classpath: /liquibase/postgresql-42.2.18.jar
- Run the deployment on your Kubernetes cluster.
kubectl apply -f my-app-deployment.yaml
Validation
In Liquibase, you can use Liquibase changelog table to validate whether your DB migrations are successful.
In Liquibase, a changelog is a collection of changesets that describes the changes that need to be made to the database. Each changeset is a single, atomic change to the database, such as adding a new table, modifying an existing column, or running a SQL script.
When Liquibase runs, it keeps track of which changesets have been executed in the database by storing information in a special table called the DATABASECHANGELOG table. This table contains a record for each changeset that has been executed, including the change's unique ID, author, and execution date.
By default, the DATABASECHANGELOG table is created in the same schema as the rest of the database, but its name and schema can be customized.
Here is an example of the DATABASECHANGELOG table structure:
ID | VARCHAR(255) | NOT NULL
AUTHOR | VARCHAR(255) | NOT NULL
FILENAME | VARCHAR(255) | NOT NULL
DATEEXECUTED | TIMESTAMP | NOT NULL
ORDEREXECUTED | INT | NOT NULL
EXECTYPE | VARCHAR(10) | NOT NULL
MD5SUM | VARCHAR(35) |
DESCRIPTION | VARCHAR(255) |
COMMENTS | VARCHAR(255) |
TAG | VARCHAR(255) |
LIQUIBASE | VARCHAR(20) |
You can query the DATABASECHANGELOG table to see which changesets have been executed, and in what order. Additionally, you can also use the Liquibase command-line tool to generate reports on the current state of the database, including a list of all executed changesets and any pending changes that have not yet been applied.
Liquibase Rollback
In Liquibase, it is possible to revert a specific changeset that has already been applied to the database. This can be useful in cases where a mistake was made in a previous change or if you want to undo a change in a development or testing environment.
To revert a changeset in Liquibase, you can use the "rollback" command and specify the ID of the changeset that you want to revert. The rollback command will undo the changes made by the specified changeset and update the DATABASECHANGELOG table to reflect the change.
Here is an example of how to revert a changeset with ID "12345" using the Liquibase command-line tool:
liquibase rollback 12345
In Kubernetes, to revert a changeset, you will have to create a new deployment with the rollback command and apply it to the cluster.
Here is an example of how to revert a changeset with ID "12345" in Kubernetes:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-rollback
spec:
selector:
matchLabels:
app: my-app-rollback
template:
metadata:
labels:
app: my-app-rollback
spec:
initContainers:
- name: liquibase-rollback
image: liquibase/liquibase:latest
env:
- name: LIQUIBASE_URL
value: jdbc:postgresql://my-database:5432/my-database
- name: LIQUIBASE_USERNAME
value: my-user
- name: LIQUIBASE_PASSWORD
value: my-password
command: ["liquibase", "rollback", "12345"]
volumeMounts:
- name: liquibase-config
mountPath: /liquibase/
volumes:
- name: liquibase-config
configMap:
name: liquibase-config
It's worth noting that depending on the changes made by the changeset, reverting it might not be straightforward and can have an impact on other parts of the database, for example, if the changeset creates a table, reverting it will drop the table and all the data inside it. it's important to test the rollback in a development environment before applying it to production.
In conclusion, using an init container in Kubernetes to run Liquibase database migrations is a convenient and efficient way to manage and version database changes. It allows developers to track and roll back changes easily and ensures that the database is in the correct state before the main application starts.
Opinions expressed by DZone contributors are their own.
Comments