Add S3 backups to all CNPG Postgres clusters #298
Reference in New Issue
Block a user
Delete Branch "benvin/cnpg-backups"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
None of the 8 CNPG Postgres clusters in this repo had any backup configured. A
lost PVC, a fat-fingered migration, or a bad app deploy meant permanent, unrecoverable
data loss for authentik, litellm, artifactapi, woodpecker, puppet, encapi, paperclip
and grafana. This adds continuous WAL archiving + a nightly base backup to Ceph RGW for
every cluster, plus code-forward restore docs.
What
spec.backup.barmanObjectStoreon eachcnpg_cluster.yaml— turns on continuousWAL archiving to
s3://cnpg-<app>, WAL compressed with zstd, base backups with bzip2,30-day retention. TLS to
s3.ceph.unkin.netis trusted via the reflectedvault-ca-cert(endpointCA).cnpg_backup.yamlper app — a cephrgwObjectStoreUser+Bucket(operatorprovisions the bucket and mints the S3 key into
cnpg-<app>-backup-s3; nothing ishardcoded) and a staggered nightly
ScheduledBackup.schemas/ceph.unkin.net/*.json— the three cephrgw CRD schemas so kubeconform canvalidate the new CRs.
docs/— new docs folder (README index +cnpg-backups.md+cnpg-restore.md).Design decisions (answers to the open questions)
One bucket for all, or per-database? → Per-database (one bucket + owner user per
cluster). The cephrgw CRDs are namespace-scoped (
BucketRef/OwnerRefresolve onlywithin the same namespace), and CNPG reads its S3 credential Secret from its own
namespace. A single shared bucket would require either cross-namespace bucket refs
(unsupported) or hand-copying the S3 secret into all 8 namespaces (defeats "operator
mints the keys"). Per-namespace
s3://cnpg-<app>with a dedicated owner user is thesimplest correct topology and needs zero manual seeding. Each user owns exactly one
bucket, so owner-level (full) access is already tightly scoped — no extra
BucketAccessgrant needed.
Backup mechanism. The deployed CNPG operator is v1.28 (helm chart
cloudnative-pg-0.27.0, appVersion 1.28.0). 1.26+ deprecates the in-treebarmanObjectStorein favour of the Barman Cloud Plugin, but the plugin is notdeployed, and
barmanObjectStoreis still fully functional on 1.28. So this uses thein-tree mechanism. Migrating to the plugin is a follow-up (noted in
docs/cnpg-backups.md).Schedule / retention (defaults — Ben to adjust)
Retention is 30d across the board — flagged as a default to tune per cluster.
Schedules are staggered 20 min apart so 8 base backups don't hit RGW at once.
Validation
kustomize build --enable-helm+kubeconform(repo CI args, incl. the new cephschemas) pass on all 8 affected overlays (paperclip validated at base — it has no
overlay yet). ceph CRs resolve their schemas (
Skipped: 0).pre-commit runpasses on all changed files (yamllint, no-plain-secrets, etc.).ci/validate-apps.shrun aborts locally on the unrelatedcattle-systemoverlay (chart requires kubeVersion < 1.35 vs host helm v1.36.0) —pre-existing, reproduces on
origin/main, unrelated to this change.Notes / caveats
PR (#296) beyond the three identical generated
schemas/ceph.unkin.net/*.jsonfiles, which merge cleanly whichever lands first.
only prerequisite is the operator being healthy (it is, in
cephrgw-system).Follow-ups
ObjectStoreCRs).https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv