Skip to content

Containerized MariaDB/PostgreSQL/MongoDB backup tool - #1

Merged
cerebrate merged 1 commit into
masterfrom
feature/initial-implementation
Oct 8, 2026
Merged

cerebrate merged 1 commit into
masterfrom
feature/initial-implementation

Conversation

@cerebrate

Copy link
Copy Markdown
Member

Summary

A single image that makes logical disaster-recovery backups of any number of MariaDB, PostgreSQL and MongoDB servers onto an NFS share. It runs as a Kubernetes CronJob, or with Docker for testing. Retention is grandfather-father-son, and status goes out over MQTT.

  • Every database on each server, enumerated automatically with optional include/exclude lists, plus server-level objects:
    • PostgreSQL roles and tablespaces (pg_dumpall --globals-only)
    • MariaDB users and grants (mariadb-dump --system=users)
    • MongoDB users and roles (a whole-instance mongodump --oplog, consistent to a point in time)
  • Safe sets: each set is written to a .partial directory, verified, given a manifest with SHA-256 checksums, and renamed into place. Finished sets are never renamed or modified, so the off-site sync only ever uploads new files.
  • GFS retention (daily/weekly/monthly/yearly/last). A target is pruned only after its own backup succeeds, and its newest good set is always kept.
  • Isolation: each target has its own retries and lock. One failure never stops the others, but the run exits non-zero.
  • MQTT retained status, with Home Assistant discovery. docs/home-assistant.md sets up two Alert Redux generators: Backup failed, and Backup stale, which acts as a dead man's switch.
  • dbbackup restore leaves accounts that already exist on the destination untouched, including the restoring account and a fresh container's own root/healthcheck. docs/restore.md is a DR runbook that needs only stock tools.
  • Secrets come only from environment variables or files, and never appear on argv.
  • Deployment: a kustomize base (CronJob, NFS PV/PVC, ConfigMap), a compose test stack, and CI that runs lint, unit tests and integration tests, then pushes the image to GHCR.

Design notes from testing against real servers

  • pg_read_all_data can read pg_authid, so the PostgreSQL backup role saves role password hashes without being a superuser.
  • Replaying the user/role dumps resets the passwords of accounts that already exist on the destination. That changed the restoring account's own password mid-restore, and broke the MariaDB image's healthcheck. Restore now skips statements for existing accounts. The MariaDB parser handles the dump's version-conditional comments and both quote styles.
  • mongodump has no --nsExclude, so a MongoDB target with include/exclude gets per-database dumps without --oplog. The manifest records a warning about the lost point-in-time consistency.
  • mongorestore --drop also replaces existing users, and --oplogReplay can't be combined with namespace excludes. --force therefore drops the clashing databases through the driver and never passes --drop.

Test plan

  • make lint and make test: 76 unit tests
  • make integration on a fresh compose stack: 17 end-to-end tests covering backup, manifests, verify/list, MQTT and discovery, restores of all three engines (data, users, passwords, grants, routines/triggers/events, views, indexes), refusal without --force, same-day pruning, locking and corruption detection
  • The integration suite passes again when rerun on the same long-lived stack
  • kubectl apply --dry-run=client -k deploy/k8s
  • First run in the cluster: kubectl -n db-backup create job --from=cronjob/db-backup db-backup-manual
  • Alert Redux generators configured in Home Assistant

Phase 2, a local Docker-based restore test, comes later. The manifest inventory it will check against is already recorded.

🤖 Generated with Claude Code

A single image, run as a Kubernetes CronJob (or with Docker), that makes
logical backups of any number of MariaDB, PostgreSQL and MongoDB servers
onto a shared filesystem, with GFS retention and MQTT status reporting.

- Enumerates every database per server (with include/exclude), and saves
  server-level objects: PG roles/tablespaces, MariaDB users/grants,
  MongoDB users/roles (whole-instance mongodump --oplog).
- Sets are written to .partial, verified, checksummed into a manifest and
  renamed into place; finished sets are never modified, so off-site sync
  only sees new files.
- GFS retention (daily/weekly/monthly/yearly/last), applied only after a
  target's own backup succeeds; the newest good set is always kept.
- Per-target isolation, retries and locking; non-zero exit on any failure.
- MQTT retained status with Home Assistant discovery, for Alert Redux
  failure and staleness (dead man's switch) alerts.
- dbbackup restore, which leaves accounts that already exist on the
  destination untouched; plus a stock-tools DR runbook.
- Secrets only via env vars or files, never on argv.
- Kustomize base (CronJob, NFS PV/PVC, ConfigMap), compose test stack,
  unit and integration tests, and GitHub Actions CI with GHCR publishing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cerebrate
cerebrate merged commit 48b6113 into master Oct 8, 2026
3 checks passed
@cerebrate
cerebrate deleted the feature/initial-implementation branch October 8, 2026 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant