luminare.infra_edge · v0.2.1
0016. Logical dumps per database with a systemd timer instead of physical backups or cron
- Status: accepted
- Date: 2026-10-22
Context
An edge host keeps a few small databases next to its applications. Each night the data must end
up in files that a backup tool can copy off the host later in the night, that can be restored
one database at a time, and whose creation shows a failure clearly. MariaDB offers logical dumps
(mariadb-dump) and physical backups (mariadb-backup). The root account logs in with
unix_socket, so a job that runs as root needs no password file.
Considered options
- A script that dumps every database into its own zstd file plus one file with the accounts
(
mariadb-dump --system=users), run by a sandboxed oneshot service and a timer, with a retention in days. - One
mariadb-dump --all-databasesfile per night. mariadb-backup(physical backup of the data directory).- A cron job.
Decision
Option 1. The script (/usr/local/sbin/mariadb-dump-all) lists the databases, skips the system
databases and dumps each one with --single-transaction --routines --events --triggers --databases into <database>-<UTC time>.sql.zst, then the accounts and grants with
--system=users --insert-ignore into system-users-<UTC time>.sql.zst. Each file is written as
.partial and renamed when the dump and the compression succeeded (set -o pipefail); files older
than mariadb_dump_retention_days are deleted only after a run in which every dump succeeded.
mariadb-dump.service runs it as root with UMask=0077, no capabilities, no network
(PrivateNetwork; the socket is a file) and a read-only system except the dump folder;
mariadb-dump.timer starts it at mariadb_dump_oncalendar with Persistent=true.
Option 2 restores everything or nothing. Option 3 needs the same server version for the restore
and a prepare step, and its files are larger than compressed SQL for small databases. Option 4
has no sandbox, loses a run missed while the host was off, and reports a failure only by e-mail;
a failed systemd unit shows in systemctl --failed and the journal.
Tested on 2026-10-22 in the Molecule scenario on Debian 13 (MariaDB 11.8) and Ubuntu 24.04
(MariaDB 10.11): a run of the service writes one file per database and the accounts file
(mode 0600, folder 0700), deletes a planted dump that is three days old and keeps one from the
day before; a dropped table comes back from its dump and a dropped account from the accounts
dump. A unit test runs the script with stand-ins for the MariaDB tools and checks that a failed
dump keeps the old files and leaves no .partial file.
Consequences
- Good: one database can be restored with
zstd -dc <file> | mariadb, on another MariaDB version too. - Good: no password file on the host; the dumps are readable by root only.
- Bad: a logical dump and its restore take longer than a physical backup for large databases, and tables of other engines than InnoDB are not part of the consistent snapshot.
- Bad: the dumps stay on the host until a backup tool copies them; two days of dumps need disk space for two compressed copies of every database.
docs/adr/0016-logical-dumps-per-database-with-a-systemd-timer.md on GitHub
Licensed under Apache-2.0. Source: luminare-dev/ansible-collection-infra_edge at v0.2.1.