Scheduled Backup Retention#
The ScheduledBackup controller in CloudNativePG creates Kubernetes Backup resources on a cron schedule. Over time these objects accumulate. Retention β pruning both the actual backup data in object storage and the corresponding Backup CRs β is handled at two independent levels:
- Object-store data retention β configured on the
ClusterorObjectStore, enforced by the instance manager. - Kubernetes
BackupCR cleanup β a catalog-reconciliation step that deletes CRs whose backup IDs are no longer present in the object-store catalog.
There is no numeric history-limit field on ScheduledBackup itself. The full ScheduledBackupSpec exposes only scheduling, cluster reference, owner-reference, method, target, and volume-snapshot options.
The retentionPolicy field (in-tree Barman path)#
Cluster.spec.backup.retentionPolicy accepts a recovery-window string (60d, 8w, 2m). It applies only to the barmanObjectStore method and governs which base backups the Barman catalog considers obsolete.
When a backup completes, backupMaintenance runs two steps in sequence:
- Calls
barmanCommand.DeleteBackupsByPolicywith the configured policy string to prune expired data from object storage . - Fetches the updated catalog and calls
deleteBackupsNotInCatalogto delete completedBackupCRs whoseBackupIDno longer appears in the catalog.
The CR cleanup is catalog-driven, not count-driven: it deletes a CR only if its BackupID is absent from the catalog after the retention policy was applied . Only completed CRs that share the same Barman endpoint/path/credentials as the cluster are considered .
Plugin path (plugin-barman-cloud)#
The Barman Cloud plugin uses an equivalent mechanism via CatalogMaintenanceRunnable. A background goroutine in the instance sidecar runs the cycle method periodically . On each cycle it:
- Applies
objectStore.Spec.RetentionPolicyusingbarmanCommand.DeleteBackupsByPolicy. - Calls
deleteBackupsNotInCatalogwith the same catalog-reconciliation logic as the in-tree path.
The check interval defaults to 5 minutes and is otherwise controlled by objectStore.Spec.InstanceSidecarConfiguration.RetentionPolicyIntervalSeconds . Only the current primary runs maintenance .
Volume-snapshot backups#
retentionPolicy has never been enforced for volumeSnapshot-method backups. The operator has no built-in retention controller for volume-snapshot Backup CRs or their underlying VolumeSnapshot/VolumeSnapshotContent objects. Community workarounds use a CronJob that deletes old Backup resources by age or label, relying on snapshotOwnerReference: backup so Kubernetes garbage-collection cascades to the VolumeSnapshot .
The backupOwnerReference field and Kubernetes GC#
ScheduledBackupSpec.backupOwnerReference (none | self | cluster, default none) determines whether the generated Backup resources carry an owner reference . When set to self or cluster, deleting the owning object cascades deletion of all child Backup resources via standard Kubernetes garbage collection. This is not a rolling history limit; it doesn't prune old backups while the owner still exists.
Known issue: terminal error: Backup not found after retention#
When a Backup CR is deleted by the retention process while the backup controller still has it in its work queue, backup_controller.go returns reconcile.TerminalError(err) on the NotFound case β a regression introduced in PR #9353. PR #11484 fixes this by converting the NotFound return to a no-op, matching the behaviour of the scheduledbackup_controller.go . The practical impact is a permanently incrementing controller_runtime_reconcile_total{result="error"} metric for the backup controller .
Key entry points#
| Concern | File | Lines |
|---|---|---|
| ScheduledBackup controller (no retention logic) | internal/controller/scheduledbackup_controller.go | full file |
| In-tree retention + CR cleanup | pkg/management/postgres/backup.go | 227β396 |
| Plugin retention + CR cleanup | internal/cnpgi/instance/retention.go | full file |
retentionPolicy API field | api/v1/cluster_types.go | |
ScheduledBackupSpec (no history limit) | api/v1/scheduledbackup_types.go |