BackupSchedule CRD
The BackupSchedule Custom Resource Definition defines cron-based scheduled backups. Each run creates a Backup CR; retention is controlled by history limits.
Overview
- API Group:
retour.thebackup.company/v1
- Kind:
BackupSchedule
- Scope: Namespaced
- Cron format: Standard 5-field cron (minute, hour, day-of-month, month, day-of-week).
Spec
Required Fields
| Field |
Type |
Description |
schedule |
string |
Cron expression (5 fields). Example: 0 2 * * * (daily at 02:00). |
storageBackend |
string |
Name of the StorageBackend for backups. |
Optional Fields (with defaults)
| Field |
Type |
Default |
Description |
namespacedResources |
array |
[] |
Resources to backup (same as Backup). |
clusterResources |
array |
[] |
Cluster-scoped resources. |
excludePVs |
bool |
false |
Skip PV data. |
resourceFilter |
object |
nil |
Include/exclude filters. |
suspend |
bool |
false |
If true, pause subsequent runs. |
successfulBackupsHistoryLimit |
int32 |
3 |
Number of successful backups to retain. |
failedBackupsHistoryLimit |
int32 |
1 |
Number of failed backups to retain. |
concurrencyPolicy |
string |
Allow |
How to handle overlapping runs. |
ConcurrencyPolicy
| Value |
Behavior |
Allow |
Create new backup even if previous is still running. |
Forbid |
Skip the run if a backup is already in progress. |
Replace |
Cancel the running backup and start a new one. |
Retention
successfulBackupsHistoryLimit keeps a flat count. retention replaces it
with grandfather-father-son tiers, keeping the newest backup per period up to
each count:
| Field |
Type |
Description |
retention.keepHourly |
int32 |
Newest backup of each hour to keep. |
retention.keepDaily |
int32 |
Newest backup of each day. |
retention.keepWeekly |
int32 |
Newest backup of each week. |
retention.keepMonthly |
int32 |
Newest backup of each month. |
retention.keepYearly |
int32 |
Newest backup of each year. |
backupDeletionPolicy |
string |
Whether expiring a backup also purges its data from the backend. Object Lock retention still defers the purge. |
Backups are not owned by their schedule, so deleting the schedule leaves its
backups and their data in place.
Restore Drills
drill restores this schedule's newest successful backup into scratch
retour-drill-* namespaces on its own cron, optionally runs a check pod
against the result, and deletes the scratch namespaces afterwards.
| Field |
Type |
Description |
drill.schedule |
string |
Cron expression for drill runs. Independent of the backup cron. |
drill.check.image |
string |
Image the check container runs. |
drill.check.command |
[]string |
Command whose non-zero exit fails the drill. Restored claims are mounted at /data/<claimName>. |
drill.check.namespace |
string |
Original namespace whose scratch clone the check runs in. Defaults to the first restored namespace. |
drill.check.timeoutSeconds |
int32 |
Bounds the check run. Default 300. |
The outcome lands in status.lastDrill, a Kubernetes event, and the
retour_restore_drill_* metrics. A drill with no volumes to restore is
recorded as Skipped, not Failed.
Timing
| Field |
Type |
Default |
Description |
startingDeadlineSeconds |
int64 |
— |
How long after a missed fire time a run may still start, with CronJob semantics. Without it, a rollout or API blip that crosses the fire time drops the run. A skipped run is an event and a counter either way. |
suspend |
bool |
false |
Pause subsequent runs. |
Inherited by Every Backup
These are copied onto each Backup the schedule creates and behave exactly as
they do on Backup: scope, excludedNamespaces,
includedSystemNamespaces, includeWebhookConfigurations,
resourceDiscovery, namespaceSelector, hooks, databases, secrets,
volumeGroups, skipVerification and bandwidthLimit.
Status
| Field |
Type |
Description |
phase |
string |
Pending, Active, Suspended, or Failed. |
lastScheduleTime |
string |
When the last backup was created. |
lastBackupName |
string |
Name of the last Backup CR created. |
lastBackupStatus |
string |
Status of the last backup. |
nextScheduleTime |
string |
When the next backup will run. |
activeBackups |
[]string |
Names of backups currently running. |
error |
string |
Error message if schedule failed. |
lastDrill |
object |
Outcome of the last restore drill: phase, what was restored, and the check result. |
lastDrillTime |
string |
When the last drill ran. |
lastSelectedNamespaces |
[]string |
Namespaces the last run matched, for schedules that select by label. |
conditions |
array |
Standard Kubernetes conditions, including QuotaExceeded when a BackupQuota is holding this schedule back. |
Examples
Daily Backup at 02:00
apiVersion: retour.thebackup.company/v1
kind: BackupSchedule
metadata:
name: daily-backup
spec:
schedule: "0 2 * * *"
storageBackend: s3-production
namespacedResources:
- resourceType: Deployment
namespace: production
name: webapp
successfulBackupsHistoryLimit: 7
Hourly with Forbid (No Overlap)
apiVersion: retour.thebackup.company/v1
kind: BackupSchedule
metadata:
name: hourly-backup
spec:
schedule: "0 * * * *"
storageBackend: s3-production
concurrencyPolicy: Forbid
namespacedResources:
- resourceType: StatefulSet
namespace: production
name: database
successfulBackupsHistoryLimit: 24
failedBackupsHistoryLimit: 3
Weekly Full Namespace Backup
apiVersion: retour.thebackup.company/v1
kind: BackupSchedule
metadata:
name: weekly-namespace
spec:
schedule: "0 3 * * 0"
storageBackend: s3-production
clusterResources:
- resourceType: Namespace
name: production
successfulBackupsHistoryLimit: 4
Suspended Schedule
apiVersion: retour.thebackup.company/v1
kind: BackupSchedule
metadata:
name: paused-schedule
spec:
schedule: "0 2 * * *"
storageBackend: s3-production
suspend: true
namespacedResources:
- resourceType: Deployment
namespace: production
name: webapp
Manifests Only (No PV Data)
apiVersion: retour.thebackup.company/v1
kind: BackupSchedule
metadata:
name: manifests-schedule
spec:
schedule: "0 */6 * * *"
storageBackend: s3-production
excludePVs: true
clusterResources:
- resourceType: Namespace
name: production
successfulBackupsHistoryLimit: 28
GFS Retention with a Weekly Drill
apiVersion: retour.thebackup.company/v1
kind: BackupSchedule
metadata:
name: nightly
spec:
schedule: "0 3 * * *"
storageBackend: s3-production
startingDeadlineSeconds: 3600
clusterResources:
- resourceType: Namespace
name: production
retention:
keepDaily: 7
keepWeekly: 4
keepMonthly: 12
drill:
schedule: "0 5 * * 0"
check:
image: postgres:17
command: ["sh", "-c", "test -s /data/db-data/PG_VERSION"]