ScheduledBackup architecture
ScheduledBackup is the scheduling layer for physical backups. It does not move
backup bytes itself. Instead, it creates ordinary Backup objects on a cron
cadence, and the existing Backup controller runs the XtraBackup-to-object-store
data path.
For one-off on-demand backups, skip the YAML and use the plugin:
kubectl cloudnative-mysql backup <cluster>
This page covers recurring scheduled backups.
Schedule format
spec.schedule is a six-field cron expression including seconds:
second minute hour day-of-month month day-of-week
Examples:
"0 0 2 * * *": every day at 02:00:00."0 */15 * * * *": every 15 minutes."30 0 */6 * * *": every six hours at minute 0, second 30.
Five-field Unix cron expressions are intentionally rejected because the leading seconds field is required.
Basic example
apiVersion: mysql.cloudnative-mysql.io/v1alpha1
kind: ScheduledBackup
metadata:
name: cluster-sample-daily
spec:
schedule: "0 0 2 * * *"
cluster:
name: cluster-sample
immediate: true
backupOwnerReference: self
method: xtrabackup
target: prefer-standby
online: true
The generated Backup inherits the cluster reference, method, target, and online
setting. The object store is resolved by the Backup controller, usually from
Cluster.spec.backup.objectStore.
Immediate backup
When spec.immediate is true, the scheduler creates one Backup as soon as it
first reconciles the ScheduledBackup, in addition to the cron cadence.
The immediate path has an adoption guard. If the operator creates the immediate Backup but restarts before patching status, the next reconcile finds the existing immediate child Backup by label and adopts it instead of firing a second one.
Concurrency guard
cloudnative-mysql never overlaps backups for the same ScheduledBackup. Before evaluating
the next cron slot, the controller lists child Backups for that schedule. If any
child Backup is not done, meaning its phase is neither completed nor failed,
the scheduler requeues and waits.
This protects the cluster and object store from accidental backup pileups when a backup takes longer than the schedule interval.
Deterministic names
Scheduled backups use deterministic names:
<scheduledbackup-name>-<YYYYMMDDHHMMSS>
The timestamp is the UTC scheduled time. Deterministic names make retries idempotent: if a previous reconcile created the Backup but missed the status update, the next reconcile observes and adopts the same child.
If another Backup already occupies the deterministic name and is not labelled as owned by this ScheduledBackup, cloudnative-mysql refuses adoption, emits a warning Event, skips that iteration, and resumes with the next schedule slot.
Owner reference modes
spec.backupOwnerReference controls owner references on generated Backup
objects:
self: the Backup is owned by the ScheduledBackup. Deleting the ScheduledBackup can garbage-collect its Backups.cluster: the Backup is owned by the referenced Cluster.none: the Backup has no owner reference and remains standalone.
Every generated Backup is labelled with:
mysql.cloudnative-mysql.io/scheduled-backup=<scheduledbackup-name>
Immediate Backups also receive:
mysql.cloudnative-mysql.io/immediate-backup=true
Labels are used for adoption and child lookup regardless of owner-reference mode.
Suspension
Set spec.suspend: true to pause scheduling:
spec:
suspend: true
Suspension prevents new Backup creation. It does not cancel a Backup that has already been created, and it does not delete completed Backups.
Status fields
ScheduledBackup.status records scheduler progress:
lastCheckTime: the last time the schedule was evaluated.lastScheduleTime: the last scheduled time that produced or adopted a Backup.nextScheduleTime: the next expected cron slot.
The generated Backups carry the actual backup phase, Job name, checksum, destination path, and error details.
Retention
The scheduler currently creates Backup objects only. Retention GC is a separate follow-on slice. Until retention is implemented, object-store lifecycle rules, manual cleanup, or external automation must preserve the recovery window you intend to keep.
For PITR, base-backup retention must be considered together with binlog archive retention. Deleting a base backup can make older binlog segments unusable, and deleting binlogs can shorten the recovery window even when base backups remain.
Operational notes
- Choose a schedule interval longer than the normal backup duration to avoid constant concurrency deferral.
- Use
target: prefer-standbywhen replicas are available and can carry backup load. - Keep
immediate: truefor schedules where the first backup should exist without waiting for the first cron slot. - Use
backupOwnerReference: noneif backups must survive deletion of the schedule object. - Monitor both the ScheduledBackup status and the generated Backup statuses.
Verification coverage
Unit tests cover schedule parsing, defaults, deterministic names, Backup field propagation, suspended schedules, immediate creation and adoption, first-check status stamping, due-slot creation, owner-reference modes, concurrency guarding, and name-collision skips. The live Kind + MinIO e2e for scheduled backups is planned with the same backup harness used by one-shot backups.