Satu Dump per Tag: Backup Database yang Bisa Dijawab
Cron harian nggak bisa jawab dump mana yang cocok sama versi yang live. Satu dump per tag rilis di folder .docs/BACKUPDB bikin rollback berhak nebak.
Ringkasan
Saya pernah apes restore dump harian cron ternyata skemanya nggak cocok sama kode. Sekarang tiap rilis bikin annotated tag dan dump mariadb-dump dengan nama sama jadi jelas pasangannya. Tiap dump dites restore ke container kosong biar yakin bisa dipake pas darurat.
Sempat kejadian di sebuah project portal warga yang saya rawat: saya butuh data mirip produksi buat ngetes fitur di staging, dan yang saya temukan cuma satu file raksasa bernama all_databases_20261001.sql dari cron harian. Isi lengkap. Tapi pas restore, tabel users nggak punya kolom yang dicari aplikasi. Skema di dump dan skema yang dibutuhkan kode beda versi, dan nggak ada satu petunjuk pun yang bilang dump itu cocok sama rilis mana.
Tuduhan pertama saya arahkan ke cron. Kupikir jadwalnya kurang rapat. Ternyata masalahnya bukan frekuensi, tapi pemicunya: waktu. Backup yang dipicu jam dinding nggak punya hubungan apa pun dengan versi aplikasi yang lagi jalan.
Jadi kontraknya saya ubah: satu dump dipasangkan dengan satu tag rilis. Tag memang dirancang buat menandai titik rilis [4], dan annotated tag nyimpan tanggal, penandai, plus pesan penjelasnya [3]. Mulai hari itu, backup database ikut tag rilis jadi aturan resmi di folder .docs/BACKUPDB. Cron tetap jalan buat kebutuhan harian, tapi dia nggak lagi diminta jadi titik pemulihan.
Tag itu keputusan sadar
Cron jalan sesuai jam, nggak peduli repo lagi tenang atau lagi panas-panasnya deploy. Tag beda: dia cuma ada kalau saya yang bikin. Membuat annotated tag itu pernyataan eksplisit bahwa kode di titik ini layak disebut versi.
Efek sampingnya nyemen: jejak auditnya beres sendiri. Pas produksi kena masalah, saya nggak nebak-nebak. Lihat tag rilis stabil terakhir, ambil dump dengan nama yang sama. Backup harian nggak bisa kasih kepastian kayak gini karena file cron nggak pernah ditanya versinya.
Yang suka ngurusin otomasi juga kebagian. GitHub Actions bisa disetel supaya workflow cuma jalan saat tag tertentu di-push [5], dan pembatasan trigger ke tag itu memang sintaks resmi di halaman workflow syntax-nya [6]. Saya tetap pilih jalan manual dulu: ritual restore-nya justru bagian yang mau saya rawat tangan, bukan disembunyikan di balik runner.
Cukup dump logis, ngapain yang fisik
Alatnya mariadb-dump, nama baru dari mysqldump yang symlinks-nya mulai dideprecasi sejak MariaDB 11.0 [1]. Satu perintah, keluar file SQL berisi perintah bikin ulang database dari nol, lengkap dengan datanya [1].
Backup fisik kayak mariadb-backup emang lebih kenceng. Tapi backup logis lebih fleksibel: bisa direstore di hardware lain, versi MariaDB beda, bahkan DBMS lain [2]. Kekurangannya jelas, lebih lambat pas backup dan restore [2]. Buat database berukuran belasan megabyte, selisih detik itu jauh lebih murah daripada kehilangan fleksibilitas.
Alasan praktisnya: yang melakukan restore nanti saya sendiri, beberapa kali setahun, dengan panik level sedang. Skenario itu paling cocok sama file SQL polos yang bisa dibuka pakai editor mana pun.
Struktur `.docs/BACKUPDB`
Semua aturan backup di project itu sekarang tinggal dalam satu folder. Ada file rule, ada index.md yang jadi daftar isi, dan ada tempat buang dump lokal. Foldernya di-commit, isinya dokumentasi mini yang ngajari siapa pun yang pegang project berikutnya.
Penamaan dump ngikutin tag. portal-warga-v1.2.0.sql buat tag v1.2.0. Tanpa akhiran -final atau -revisi, karena yang ngasih nama itu tag, bukan mood.
Satu hal yang bikin kaget orang: dump lokal nggak ikut ke Git. .gitignore di folder ini memblok semua .sql. Dump resmi dihasilkan waktu rilis lalu diarsipkan ke penyimpanan backup. Repo cuma nyimpen aturan, index, dan jejak auditnya, bukan salinan data tiap rilis.
Bukti backup: restore ke container bersih
Aturan secanggih apa pun nggak berarti kalau dump-nya gagal direstore pas dibutuhkan. Jadi tiap rilis lewat satu ritual singkat: dump, restore ke container MariaDB kosong, hitung isinya.
# tandai titik rilis yang valid
git tag -a v1.2.0 -m "rilis fitur notifikasi dan perubahan skema users"
git push origin v1.2.0
# dump logis: satu file per tag, ganti <DB_PASSWORD>
mariadb-dump -u root -p"<DB_PASSWORD>" --databases portal_warga > .docs/BACKUPDB/portal-warga-v1.2.0.sql
# restore uji ke container MariaDB kosong
docker run --name uji-restore -e MARIADB_ROOT_PASSWORD="<DB_PASSWORD>" -d mariadb:11
docker exec -i uji-restore mariadb -u root -p"<DB_PASSWORD>" portal_warga < .docs/BACKUPDB/portal-warga-v1.2.0.sql
# bukti dump hidup: daftar tabel harus muncul
docker exec uji-restore mariadb -u root -p"<DB_PASSWORD>" portal_warga -e "SHOW TABLES;"
Kalau SHOW TABLES keluar dan daftarnya masuk akal, dump itu berhak disebut backup. Perintah yang sama yang dipakai buat ngisi index.md: tag kapan, file apa, restore makan waktu berapa detik. Rilis berikutnya tinggal baca index, nggak perlu arkeologi digital.
Yang saya sadar setelah pindah ke pola ini: backup yang baik bukan perkara tools mahal, tapi perkara bisa jawab pertanyaan paling memalukan dengan cepat. Dump mana yang cocok buat versi yang lagi jalan? Sekarang jawabannya satu nama file, bukan sesi ekskavasi.
Sources
[1] dokumentasi resmi mariadb-dump
[2] ringkasan backup dan restore MariaDB
[4] buku resmi Git, bab tagging