Backup CRD
The Backup Custom Resource Definition defines a one-off or on-demand backup of Kubernetes resources and persistent volumes. Retour discovers volumes automatically when you reference a Deployment, StatefulSet, or Namespace — no need to manually list PVCs.
Overview
- API Group:
retour.thebackup.company/v1
- Kind:
Backup
- Scope: Namespaced
- Default behavior: When
namespacedResources and clusterResources are empty, the Backup has no resources to back up. You must specify at least one resource.
Spec
Required Fields
| Field |
Type |
Description |
storageBackend |
string |
Name of the StorageBackend to use. Must exist in the same namespace as the Backup. |
Optional Fields (with defaults)
| Field |
Type |
Default |
Description |
namespacedResources |
array |
[] |
List of namespaced resources to backup (Deployment, StatefulSet, PersistentVolumeClaim, etc.). |
clusterResources |
array |
[] |
List of cluster-scoped resources (Namespace, PersistentVolume, StorageClass, etc.). |
excludePVs |
bool |
false |
If true, skip PV data — backup manifests only. Useful for configuration backup. |
resourceFilter |
object |
nil |
Include/exclude rules for discovered resources when backing up a Namespace or cluster. |
NamespacedResource
| Field |
Type |
Required |
Default |
Description |
resourceType |
string |
Yes |
— |
Resource type (e.g., Deployment, StatefulSet, PersistentVolumeClaim). |
name |
string |
Yes |
— |
Name of the resource. |
namespace |
string |
Yes |
— |
Namespace of the resource. |
apiGroup |
string |
No |
inferred |
API group (e.g., apps, storage.k8s.io). Omitted for core resources. |
pvFilters |
array |
No |
[] |
Path filters for PVCs attached to this resource. |
ClusterResource
| Field |
Type |
Required |
Default |
Description |
resourceType |
string |
Yes |
— |
Resource type (e.g., Namespace, PersistentVolume, StorageClass). |
name |
string |
Yes |
— |
Name of the resource. |
apiGroup |
string |
No |
inferred |
API group (e.g., storage.k8s.io). |
pvFilters |
array |
No |
[] |
Path filters for PVs. |
ResourceFilter
| Field |
Type |
Default |
Description |
excludeResourceTypes |
[]string |
[] |
Resource types to exclude (e.g., Secret, ConfigMap, Pod). |
excludeResourceNames |
[]string |
[] |
Regex patterns for resource names to exclude (e.g., ^debug-, ^test-). |
excludeResourceLabels |
LabelSelector |
nil |
Label selector for resources to exclude. |
PVFilter
| Field |
Type |
Required |
Default |
Description |
name |
string |
Yes* |
— |
Name of the PV/PVC. (*Not required when skip: true.) |
include |
[]string |
No |
[] |
Directories/files to include. |
exclude |
[]string |
No |
[] |
Directories/files to exclude. |
filterRules |
[]string |
No |
[] |
Glob patterns (e.g., /data/*, *.log). |
skip |
bool |
No |
false |
If true, skip this PVC entirely. |
Scope and Discovery
| Field |
Type |
Default |
Description |
scope |
string |
Namespaced |
Namespaced protects exactly what the resource lists name. Cluster sweeps every namespace plus cluster-scoped resources (CRDs, StorageClasses, PriorityClasses, IngressClasses), and is mutually exclusive with the explicit lists. |
excludedNamespaces |
[]string |
[] |
Namespaces to leave out of a Cluster sweep. kube-system, kube-public, kube-node-lease and the operator's own namespace are out by default, as is any namespace annotated retour.io/exclude-from-backup: "true". |
includedSystemNamespaces |
[]string |
[] |
System namespaces to sweep after all, one by one. |
includeWebhookConfigurations |
bool |
false |
Include Validating/MutatingWebhookConfigurations in a Cluster sweep. Off by default: a restored webhook whose backing service is not up yet, with failurePolicy: Fail, blocks the API writes the rest of the restore needs. |
resourceDiscovery |
string |
Registry |
Registry enumerates Retour's fixed kind registry. Dynamic also discovers every namespaced resource the API server serves, so operator CRs are captured instead of missed. Secrets, ServiceAccounts and RBAC objects are never captured either way. |
Data and Consistency
| Field |
Type |
Default |
Description |
skipVerification |
bool |
false |
Turns off the post-upload check of the stored data against the source and the decode of the stored metadata document. Verification is on by default and a failure fails the backup. |
bandwidthLimit |
string |
— |
Overrides the backend's transfer.bandwidthLimit for this run. Full rclone --bwlimit syntax, timetables included. |
volumeGroups |
array |
[] |
Label-selected groups of PVCs captured in one CSI VolumeGroupSnapshot, so several volumes share an instant. Where the cluster has no VolumeGroupSnapshot API the fallback to individual snapshots is recorded, not assumed. |
hooks |
object |
nil |
pre and post commands executed in application containers around the snapshot. A hook can hold one exec session across the whole snapshot window, which is what pg_backup_start / pg_backup_stop need. Profiles ship for PostgreSQL, MySQL, MongoDB, Redis and qemu-guest freeze. |
databases |
object |
nil |
databases.cnpg.mode: Delegate hands CloudNativePG clusters to the database operator's own backup, and takes their PVCs out of the snapshot set. Two systems protecting the same volume cannot agree on one consistent point. |
secrets |
object |
nil |
secrets.mode: EncryptedOptIn adds the encrypted Secrets stream. It needs three things: the operator-level admin switch, a crypt backend, and a passphrase of its own that differs from the main one. |
Lifetime
| Field |
Type |
Default |
Description |
ttl |
string |
— |
Deletes this Backup once it has been terminal for that long (72h, 720h). Standalone backups only; on schedule-owned backups retention governs and the TTL is ignored with a TTLIgnored condition. |
deletionPolicy |
string |
Retain |
What happens to the data on the backend when the Backup CR is deleted. Delete purges the backup's operation directories; Object Lock retention still defers the purge until the lock expires. |
Status
The worker pod writes status as the backup runs; the operator only writes a terminal phase if the worker dies without reporting (condition reason OperatorFallback).
| Field |
Type |
Description |
phase |
string |
Pending, Running, Completed, or Failed. |
backupUUID |
string |
Unique ID of this backup, assigned by the worker. |
jobUUID |
string |
Unique ID of the worker job that produced this backup. A Restore can reference it via spec.backupJobUUID. |
backendPath |
string |
Base path on the storage backend under which this backup's data was written. |
operations |
array |
Per-PVC operation references: operationID, pvcName, namespace, and the backend destination holding that PVC's data and metadata. |
startTime |
string |
When backup started. |
completionTime |
string |
When backup finished. |
backupSize |
int64 |
Total size in bytes. |
progress |
object |
Per-PV progress: totalPVs, completedPVs, and pvDetails with file and byte counters per volume. |
error |
string |
Error message if failed. |
conditions |
array |
Standard Kubernetes conditions (e.g., Complete). |
engine |
string |
Data plane that wrote this backup, rclone or kopia. A restore through a backend configured for the other engine is refused: the two store data in different layouts. |
retainedUntil |
string |
When Object Lock retention on this backup's objects expires. Deletion is deferred until then. |
secretsCaptured |
int |
How many Secrets the encrypted stream captured. Names and values appear nowhere in status, events or logs. |
hookStatuses |
array |
Per-hook outcome: which container ran what, and whether it succeeded. |
Examples
Minimal: Single Deployment
apiVersion: retour.thebackup.company/v1
kind: Backup
metadata:
name: webapp-backup
spec:
storageBackend: s3-production
namespacedResources:
- resourceType: Deployment
namespace: production
name: webapp
Full Namespace
apiVersion: retour.thebackup.company/v1
kind: Backup
metadata:
name: production-namespace-backup
spec:
storageBackend: s3-production
clusterResources:
- resourceType: Namespace
name: production
Manifests Only (No PV Data)
apiVersion: retour.thebackup.company/v1
kind: Backup
metadata:
name: manifests-only
spec:
storageBackend: s3-production
excludePVs: true
namespacedResources:
- resourceType: Deployment
namespace: production
name: webapp
With Resource Filter
apiVersion: retour.thebackup.company/v1
kind: Backup
metadata:
name: filtered-backup
spec:
storageBackend: minio
clusterResources:
- resourceType: Namespace
name: my-app
resourceFilter:
excludeResourceTypes:
- Secret
- Pod
excludeResourceNames:
- "^debug-"
- "^test-"
excludeResourceLabels:
matchLabels:
exclude-from-backup: "true"
With PV Path Filters
apiVersion: retour.thebackup.company/v1
kind: Backup
metadata:
name: selective-paths-backup
spec:
storageBackend: s3-production
namespacedResources:
- resourceType: StatefulSet
namespace: production
name: database
pvFilters:
- name: data-pvc
include:
- /var/lib/mysql
exclude:
- /var/lib/mysql/tmp
- /var/lib/mysql/logs
StatefulSet with Explicit API Group
apiVersion: retour.thebackup.company/v1
kind: Backup
metadata:
name: statefulset-backup
spec:
storageBackend: s3-production
namespacedResources:
- resourceType: StatefulSet
apiGroup: apps
namespace: production
name: redis
Whole Cluster, with Dynamic Discovery
apiVersion: retour.thebackup.company/v1
kind: Backup
metadata:
name: cluster-sweep
spec:
scope: Cluster
storageBackend: s3-production
resourceDiscovery: Dynamic
excludedNamespaces:
- staging
- sandbox
Application-Consistent Database Backup
apiVersion: retour.thebackup.company/v1
kind: Backup
metadata:
name: postgres-backup
spec:
storageBackend: s3-production
namespacedResources:
- resourceType: StatefulSet
namespace: production
name: postgres
hooks:
profiles:
- name: freeze-postgres
profile: postgres-backup-mode
namespace: production
podSelector:
app: postgres
The profile supplies the commands; you supply the pod targeting. mysql-flush,
mongodb-fsynclock, redis-bgsave and qemu-guest-freeze ship alongside it.
Session-shaped profiles hold one exec session open across the snapshot window;
the others expand to ordinary pre and post hooks.
Encrypted Secrets Stream
The operator gate operator.allowSecretsBackup must be on, and the backend must be crypt:
apiVersion: retour.thebackup.company/v1
kind: Backup
metadata:
name: app-with-secrets
spec:
storageBackend: s3-encrypted
clusterResources:
- resourceType: Namespace
name: my-app
secrets:
mode: EncryptedOptIn
Expiring Backup
apiVersion: retour.thebackup.company/v1
kind: Backup
metadata:
name: pre-upgrade-snapshot
spec:
storageBackend: s3-production
ttl: 168h
deletionPolicy: Delete
clusterResources:
- resourceType: Namespace
name: production