Backups
A backup only counts if you’ve restored it. Every layer here has a written restore procedure, and the database restore checks its own result.
Overview
| What | How | Where | When |
|---|---|---|---|
| Kubernetes volumes | Longhorn backup | NAS over NFS | Daily |
| PostgreSQL (physical) | CNPG barmanObjectStore, WAL + base backups |
Garage S3 | Continuous + daily |
| PostgreSQL (logical) | pg_dump CronJob |
NAS over SSH | Daily |
| Garage S3 | rclone sync |
NAS | Daily |
| Gitea, Jenkins, Grafana, OpenBao | Ansible-managed backup scripts | NAS | Daily |
Garage runs on Proxmox VMs and the NAS is a separate box. The two database layers deliberately use different storage systems, so no single failure takes out both.
PostgreSQL in three layers
The CloudNative-PG cluster has three instances on Longhorn volumes. Each layer covers a different failure:
- Longhorn volume backup. Restores a whole volume at block level.
- Barman to S3. Continuous WAL archiving gives point-in-time recovery, for when the cluster itself is lost.
- Logical dumps. One portable
.sql.gzper database plus the global roles. Use these to restore a single database, or to move it somewhere else entirely.
The dumps use --no-owner --no-acl to stay portable. The catch is that after a restore everything is owned by the superuser.
Restoring a single database
The restore Job is deliberately not listed in kustomization.yaml. It’s destructive and should only run when I ask for it, never because ArgoCD synced. It:
- Pulls the chosen dump from the NAS
- Drops and recreates the database, owned by the app role
- Restores with
ON_ERROR_STOP=1 - Hands ownership of all tables, sequences and views back to the app role
- Checks that the database has tables, that nothing is still owned by the superuser and that the database owner is right, then prints
RESULT: PASS
Infrastructure recovery
Ansible has standalone recovery playbooks for Gitea, Jenkins, Grafana and OpenBao that restore from the NAS. They run without CI on purpose: if Gitea is gone, there is no CI to run them. See Lessons learned.