Skip to content

Capability reference

The tutorials cover a first backup and a first restore. This page lists what Retour grew after that: what each capability does, the field that turns it on, and nothing you have to read twice. docs/PRODUCT.md in the repository carries the full reference for every one of them.

Proving backups restore

BackupSchedule.spec.drill restores the schedule's newest successful backup into scratch retour-drill-* namespaces on its own cron. A check pod can run against the result, with every restored claim mounted at /data/<claimName>; the scratch namespaces are then deleted. The outcome lands in status.lastDrill, a Kubernetes event, and the retour_restore_drill_* metrics.

spec:
  drill:
    schedule: "0 5 * * 0"
    check:
      image: postgres:17
      command: ["sh", "-c", "test -s /data/db-data/PG_VERSION"]

Verification is separate and runs by default at both ends. After upload the carrier compares the destination against the still-mounted source and decodes the stored metadata document. After a restore, the restored volume is checked back against the backup it came from, using the same filters the restore copied with, so a truncated download is not reported as a successful recovery. A failure fails the operation; on the backup side success lands as a Verified condition. Turn either off with spec.skipVerification on the Backup or the Restore. Kopia-written operations verify themselves: a content-addressed repository cannot hand back a corrupt file without failing.

Retention, immutability, and cost

BackupSchedule.spec.retention keeps the newest backup per hour, day, week, month, and year up to each keep* count, instead of the flat successfulBackupsHistoryLimit. A standalone backup can carry spec.ttl, which expires it through the same deletion path.

StorageBackend.spec.s3.immutability (mode: GOVERNANCE|COMPLIANCE, retainDays) stamps S3 Object Lock retention on every uploaded object. Deletion waits for the lock to expire, and a lock that cannot be applied fails the backup.

StorageBackend.spec.engine: kopia stores deduplicated, compressed snapshots in a repository instead of copying files path-addressed, so a run uploads only what changed. It works on s3, azureblob, and gcs.

spec.transfer governs the pipe itself: bandwidthLimit (rclone timetable syntax, which gives you backup windows for free), transfers, and checkers, set per backend and overridable per backup or schedule.

What gets captured

Backup.spec.scope: Cluster sweeps every namespace and the cluster-scoped resources. System namespaces are excluded by default, and both excludedNamespaces and the retour.io/exclude-from-backup annotation are honored.

resourceDiscovery: Dynamic enumerates every namespaced resource the API server actually serves, so operator CRs are captured rather than missed by a fixed registry. The sensitive-resource deny-list still filters first.

Backup.spec.secrets.mode: EncryptedOptIn adds the Secrets stream. It needs three things: an operator-level admin switch, a crypt backend, and a passphrase of its own that differs from the main one.

Raw volumeMode: Block claims are streamed as one image, with a SHA-256 recorded at backup and enforced at restore. VirtualMachine and DataVolume are in the resource registry for KubeVirt; pair them with hooks for guest-filesystem consistency.

Hooks hold one exec session across the snapshot window, with profiles shipped for PostgreSQL, MySQL, MongoDB, Redis, and qemu-guest freeze. For CloudNativePG, spec.databases.cnpg.mode: Delegate hands protection to the database operator and records the backup id and LSNs in the metadata.

spec.volumeGroups cuts label-grouped CSI VolumeGroupSnapshots so several volumes are captured at one instant. Where the cluster has no VolumeGroupSnapshot API, the fallback is recorded rather than assumed.

Restoring with control

  • namespaceMapping, storageClassMapping, and imageRewrites retarget a restore at a different namespace, storage class, or registry.
  • resourceModifiers applies selector-scoped RFC 6902 JSON patches or RFC 7386 merge patches to manifests before they are created.
  • existingResourcePolicy: Keep|Update|Replace decides what happens to objects that already exist. PVCs are exempt; spec.targetPVC is how data is restored into an existing claim.
  • dryRun: true renders the plan, patches and collisions included, without applying anything.
  • pathFilters restores selected files instead of whole volumes. The UI browses the catalog and builds the CR for you.
  • scaleWorkloadsToZero lands workloads stopped, so nothing races the data.

Continuity and migration

Nothing in the stored format is tied to a vendor: the data goes through rclone or kopia and the manifests are plain YAML, so a backup taken in one data center restores in another. On-premise Ceph to a cloud provider, one region to the next, or between two providers that share nothing but the network. namespaceMapping and storageClassMapping handle the differences, so the target cluster does not have to look like the source, and Disaster Recovery covers restoring with no Backup CR present.

A RestoreSync on a standby cluster polls the shared storage backend, works out what the primary wrote from the metadata documents alone, and creates Restores from a template. mode: Latest replays the newest qualifying backup; Continuous replays every new one, oldest first. The standby never connects to the primary.

apiVersion: retour.thebackup.company/v1
kind: RestoreSync
metadata:
  name: shop-dr
spec:
  storageBackendRef: shared-dr-bucket
  pollInterval: 15m
  selector:
    scheduleName: nightly
  restoreTemplate:
    namespaceMapping:
      shop: shop
    scaleWorkloadsToZero: true

Restore.spec.veleroImport reads an existing Velero backup out of object storage: manifests always, and volume data for the backups kopia wrote (volumeData.enabled: true, plus the source cluster's repository password as a Secret). The Velero repository is connected read-only, and imported content passes the same deny-list, mappings, modifiers, and dry run as a native restore.

Governance

The cluster-scoped BackupQuota CR caps active backups, backups per day, schedules, schedule frequency, and total size per namespace. A backup over quota is held in Pending rather than failed, and proceeds once the pressure clears. Full field reference: BackupQuota.

A schedule that stops firing is exported rather than left to be noticed: last-success, next-run, missed-runs and suspended gauges per schedule, with shipped alerts on all of them. startingDeadlineSeconds lets a run that missed its window by a rollout or an API blip still start, with CronJob semantics, and a genuinely skipped run is an event and a counter. Deleting a schedule leaves its backups and their data alone, and retention will not purge a backup while a restore is reading it.

Every mutating request through the UI server is recorded append-only with the actor taken from the verified identity. Admins can query and export it, and the CRs the server creates are stamped with retour.io/requested-by.

The operator writes a periodic protection report (backups and restores by phase, schedules out of SLA, unprotected namespaces, drill outcomes) as ConfigMaps, and uploads it to a storage backend when one is configured.

spec.encryption.keySource (aws-kms or vault-transit) wraps the encryption material so only ciphertext is stored. Each job unwraps it just in time into a short-lived secret, and rotation is a rewrap.