Menjalankan Liquibase dengan Docker
Penggunaan aplikasi untuk migrasi database bukanlah sesuatu yang asing. Di website ini saja sudah ada beberapa artikel, yaitu:
Di ArtiVisi, kita saat ini sudah tidak lagi menggunakan Liquibase, beralih ke FlywayDB
Praktek yang biasanya kita lakukan di ArtiVisi adalah menggabungkan file migrasi dengan aplikasi. Sehingga ketika aplikasi dideploy, tools migrasi akan mengecek ke database, script mana yang belum dijalankan, dan mana yang sudah dijalankan. Kemudian dia akan menjalankan script-script yang belum pernah dieksekusi.
Akan tetapi, sebetulnya tools migrasi tidak harus dijalankan bersamaan dengan deployment. Kita juga bisa jalankan secara standalone melalui command line atau docker. Ini dibutuhkan diantaranya ketika aplikasi kita menggunakan replication, aplikasi dijalankan menjadi beberapa instance. Misalnya kalau kita deploy di Kubernetes. Skenarionya kira-kira seperti yang dijelaskan di artikel ini.
Untuk itu, kita perlu menjalankan database migration tools secara terpisah. Sehingga bisa dieksekusi terlepas dari kapan kita mendeploy aplikasi. Tentunya kita harus mendesain aplikasi kita sedemikian rupa sehingga kompatibel dengan skema database before dan after script migrasi dijalankan.
Liquibase bisa dijalankan melalui Docker, seperti dijelaskan di dokumentasi resminya. Berikut kita bahas langkah-langkahnya.
Struktur Folder
Semua aplikasi migrasi database memiliki file-file migration yang akan dieksekusi untuk mengubah skema database. Kemudian kita juga membutuhkan folder untuk konfigurasi Liquibase. Sehingga struktur foldernya menjadi seperti ini
Folder tersebut berisi script migrasi dan konfigurasi.
Script Migrasi
Script migrasi adalah file yang akan dieksekusi untuk mengubah isi database. Liquibase mendukung beberapa format file, diantaranya:
- SQL
- XML
- JSON
- YAML
Saya biasanya menggunakan format SQL, supaya lebih familiar bagi programmer dan database administrator. Kekurangan format SQL adalah, kita harus membuat script berbeda untuk tiap merek database. Ini tidak menjadi masalah bila kita tidak berencana berganti-ganti merek database.
Untuk database kosong, biasanya kita membuat file skema awal seperti ini
--liquibase formatted sql
--changeset endy:1
create table customer (
id varchar(36),
customer_name varchar(200) not null,
email varchar(100) not null,
mobile_phone varchar(50) not null,
primary key (id)
);
create table merchant (
id varchar(36),
merchant_name varchar(20) not null,
primary key (id)
);
Ada beberapa hal yang harus diperhatikan pada file tersebut:
- Tiap script harus diawali dengan
--liquibase formatted sql
. Ini untuk memberi tahu Liquibase bahwa scriptnya berbentuk SQL, bukan JSON, YAML, atau XML. - Author dan ID changeset. Informasi ini digunakan Liquibase untuk menentukan apakah file tersebut sudah pernah dijalankan. Liquibase akan melihat variabel
author
,id
, dan nama file script. Bila kombinasi tersebut sudah ada di database, maka script tidak akan dijalankan lagi.
Sebetulnya masih banyak atribut lain seperti failOnError
, runInXxx
, dan sebagainya. Informasi lengkapnya bisa dibaca di dokumentasi resminya
Kemudian, bila kita ingin melakukan perubahan lanjutan pada versi berikutnya, kita bisa buat file baru di dalam folder migrations
lagi seperti ini
--liquibase formatted sql
--changeset endy:2
alter table customer
rename column mobile_phone to phone_number;
Konfigurasi
Konfigurasi pertama adalah informasi koneksi ke database. Isinya seperti ini, kita simpan di file bernama liquibase.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://host.docker.internal:33061/belajardb
username=belajar
password=belajar123
searchPath=/liquibase/changelog
changelogFile=changelog.xml
Penjelasannya sebagai berikut:
driver
: library koneksi database yang digunakan. Isinya berbeda antar merek. Programmer Java biasanya sudah paham apa itu database driver. Programmer non-Java, bisa googling dengan keyword jdbc driver merek-database, misalnya jdbc driver postgresqlurl
: informasi tentang alamat/nama server database, port, dan nama databaseusername
danpassword
: credential untuk connect ke databasesearchPath
: lokasi tempat mencari file script migrasichangelogFile
: menunjukkan lokasi file changelog. Changelog adalah file yang berisi daftar changeset. Changeset secara sederhana adalah file migrasi berisi instruksi perubahan database. Jadi changelog file, adalah file daftar isi changeset.
Driver Database
Driver database adalah library yang digunakan Liquibase untuk terhubung ke database. Karena Liquibase dibuat dengan Java, maka library ini juga dibuat dengan Java, yang disebut dengan JDBC (Java DataBase Connectivity) Driver. Untuk produk database yang fully open source seperti PostgreSQL, kita bisa langsung menjalankan Liquibase Docker Container. Akan tetapi, ada juga driver opensource yang hanya mengijinkan redistribusi dalam bentuk source code, tidak boleh membagikannya dalam bentuk binary, misalnya MySQL dan MongoDB. Untuk kedua database ini, docker image Liquibase tidak menyertakannya dalam image. Sehingga kita harus membuat image baru yang berisi Liquibase ditambah driver MySQL / MongoDB.
Caranya tidak sulit, cukup buat Dockerfile
berisi dua baris berikut ini
FROM liquibase
RUN lpm add mysql --global
Setelah itu, kita build imagenya dengan perintah berikut
docker build --platform linux/amd64 -t liquibase-mysql .
Saya menggunakan opsi --platform linux/amd64
karena saya jalankan di laptop Apple M1 yang platformnya arm64
. Sehingga kalau tidak pakai opsi tersebut, imagenya tidak akan bisa jalan di server linux.
Docker Compose
Untuk mengetes image tersebut, kita bisa jalankan database MySQL menggunakan docker compose
. File konfigurasinya seperti ini
services:
db-belajar:
image: mysql:8
platform: linux/x86_64
environment:
- MYSQL_RANDOM_ROOT_PASSWORD=yes
- MYSQL_DATABASE=belajardb
- MYSQL_USER=belajar
- MYSQL_PASSWORD=belajar123
ports:
- 33061:3306
volumes:
- ./db-belajar:/var/lib/mysql
Pastikan nama database, port, username, dan passwordnya sesuai dengan konfigurasi di liquibase.properties
. Kemudian jalankan dengan perintah berikut
docker compose up
Buka terminal baru, kemudian periksa apakah container sudah berjalan dengan perintah berikut
docker ps
Outputnya seperti ini, perhatikan kolom NAMES
di paling kanan:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e40e7531eeeb mysql:8 "docker-entrypoint.s…" 16 minutes ago Up 16 minutes 33060/tcp, 0.0.0.0:33061->3306/tcp db-migration-liquibase-db-belajar-1
Setelah database MySQL up, kita bisa login ke dalam MySQL dengan perintah berikut
docker exec -it db-migration-liquibase-db-belajar-1 mysql -u belajar belajardb -p
Outputnya seperti ini
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.4.3 MySQL Community Server - GPL
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
Setelah login, cek isi database dengan perintah berikut:
show tables;
Outputnya seperti ini
mysql> show tables;
Empty set (0.01 sec)
Itu menunjukkan bahwa tidak ada tabel dalam database. Memang seharusnya begitu, karena databasenya baru saja dibuat.
Menjalankan Migrasi Database
Buka terminal baru lagi (saat ini sudah ada 2 : docker compose dan mysql console), kemudian jalankan docker image berisi Liquibase + driver MySQL dengan perintah berikut
docker run --rm -v ${PWD}/changelog:/liquibase/changelog liquibase-mysql --defaults-file=/liquibase/changelog/liquibase.properties update
Outputnya seperti ini
####################################################
## _ _ _ _ ##
## | | (_) (_) | ##
## | | _ __ _ _ _ _| |__ __ _ ___ ___ ##
## | | | |/ _` | | | | | '_ \ / _` / __|/ _ \ ##
## | |___| | (_| | |_| | | |_) | (_| \__ \ __/ ##
## \_____/_|\__, |\__,_|_|_.__/ \__,_|___/\___| ##
## | | ##
## |_| ##
## ##
## Get documentation at docs.liquibase.com ##
## Get certified courses at learn.liquibase.com ##
## ##
####################################################
Starting Liquibase at 14:38:42 using Java 17.0.13 (version 4.29.2 #3683 built at 2024-08-29 16:45+0000)
Liquibase Version: 4.29.2
Liquibase Open Source 4.29.2 by Liquibase
Running Changeset: migrations/changelog-2024101701.sql::1::endy
Running Changeset: migrations/changelog-2024101702.sql::1::endy
UPDATE SUMMARY
Run: 2
Previously run: 0
Filtered out: 0
-------------------------------
Total change sets: 2
Liquibase: Update has been successful. Rows affected: 2
Liquibase command 'update' was executed successfully.
Liquibase sudah berhasil menjalankan kedua script migrasi kita. Kembali ke terminal yang berisi mysql console, dan cek lagi isi databasenya. Outputnya seharusnya seperti ini
mysql> show tables;
+-----------------------+
| Tables_in_belajardb |
+-----------------------+
| customer |
| databasechangelog |
| databasechangeloglock |
| merchant |
+-----------------------+
4 rows in set (0.14 sec)
Kita bisa melihat daftar changeset yang sudah dijalankan dengan melakukan query select
ke tabel databasechangelog
. Outputnya seperti ini
mysql> select * from databasechangelog \G
*************************** 1. row ***************************
ID: 1
AUTHOR: endy
FILENAME: migrations/changelog-2024101701.sql
DATEEXECUTED: 2024-11-06 14:38:43
ORDEREXECUTED: 1
EXECTYPE: EXECUTED
MD5SUM: 9:969a320fb9ed60b12739fca9f32b775c
DESCRIPTION: sql
COMMENTS:
TAG: NULL
LIQUIBASE: 4.29.2
CONTEXTS: NULL
LABELS: NULL
DEPLOYMENT_ID: 0903923765
*************************** 2. row ***************************
ID: 2
AUTHOR: endy
FILENAME: migrations/changelog-2024101702.sql
DATEEXECUTED: 2024-11-06 14:38:43
ORDEREXECUTED: 2
EXECTYPE: EXECUTED
MD5SUM: 9:03057b5f64f2e1359b2453a1a77422f1
DESCRIPTION: sql
COMMENTS:
TAG: NULL
LIQUIBASE: 4.29.2
CONTEXTS: NULL
LABELS: NULL
DEPLOYMENT_ID: 0903923765
2 rows in set (0.01 sec)
Demikianlah cara menjalankan Liquibase secara standalone tanpa dibundel ke dalam aplikasi. Bila ingin mencoba, source code bisa didapatkan di repo Github.
Semoga bermanfaat.