Home / Stories / Backup health
Story · Reliability Live

A backup you have never restored is a hope. A failing one is a finding.

Backups fail quietly. The nightly run of Velero, a Kubernetes backup tool, reports PartiallyFailed because one volume could not be snapshotted. The database backup has been failing since someone rotated a credential. Nobody looks until the day a restore is needed. The assistant checks every few hours and opens one issue per broken schedule, with the evidence and the likely cause.

Starts fromVelero Backup objects and CloudNativePG (CNPG, a database operator) Backup objects in the cluster.
Looks atBackup phase and errors, and the Velero Schedule or CNPG Cluster behind them. It also reads the matching Schedule, BackupStorageLocation or Cluster manifests in git.
You getOne issue per failing schedule or database: what failed, since when, the probable cause, and the steps to fix and verify it.
01 · Every six hours

Read the backups, not the dashboards.

The backup scan lists Velero Backup objects and CloudNativePG Backup objects created in the last 48 hours (both configurable). It reads them straight from the cluster API, read-only.

Here: 14 Velero runs and 8 database backups in the window.

02 · Failed and partially failed

"Partially" failed is still failed.

Velero runs in Failed or PartiallyFailed count. A partial failure often means Velero saved the Kubernetes objects but not a volume. The volume is exactly the part you need for a restore.

The assistant groups runs by their Schedule, so seven failed nights become one finding, not seven.

03 · Gather the evidence

Errors, the schedule, and what git says it should be.

For each failing schedule the scan collects the error messages of the most recent runs and the Schedule's spec and status from the cluster. It also collects the Schedule and BackupStorageLocation manifests from your repository.

The error usually names the layer: storage credentials, bucket, snapshot permissions, a node agent.

04 · Databases too

CloudNativePG backups, grouped per database cluster.

The assistant groups failed CNPG backups by the Cluster that owns them. It attaches the Cluster's status and its spec.backup block (object store, credentials reference, retention) as context.

05 · Diagnose

A probable cause and concrete next steps.

An AI model (LLM) reads the evidence and writes a short diagnosis. It gives the most likely cause, what to check first and how to confirm the fix. If the analysis is unavailable, the assistant still opens the issue with the raw phase and error. It never drops the finding.

06 · An issue, not an MR

Backup fixes are too context-dependent to guess.

The assistant opens backup findings as issues, not draft merge requests (MRs). The issues carry the labels reliability and high risk. The fix is often outside git: a cloud permission, a bucket policy or a rotated key. A wrong storage change can make things worse.

That caution is earned. Once, removing a storage-location prefix to fix one error made the whole location invalid, because the bucket was shared. The full issue is below.

07 · When nothing fails Roadmap

No failed backup can also mean no backup.

If the BackupStorageLocation is Unavailable, Velero attempts nothing, so there is no failed backup to find. We plan to check the storage location itself and the age of the newest successful backup per schedule. Then silence no longer reads as health.

We also plan to flag runs whose volume snapshot list is empty when the schedule includes volumes.

08 · From finding to fix Roadmap

MRs where the fix does live in git.

We plan draft MRs for schedule and retention changes, and for a missing BackupStorageLocation. The assistant will first check the actual layout of the bucket before it touches a prefix.

When an upgrade bumps a backup plugin, the assistant will also compare the cloud permissions that each version documents. Then a new required permission shows up in the upgrade MR, not in next month's failed restore.

velero.io/v1 Backuplast 48 h · 14 runs
backup scanevery 6 h · read-only
postgresql.cnpg.io/v1 Backuplast 48 h · 8 runs
schedule "0 */6 * * *" · lookback 48h · no write access to anything
velero backups · last 48 h
  • hourly-config-20260923… ×12 Completed
  • daily-full-20260923040012 PartiallyFailed · 3 errors
  • daily-full-20260922040009 PartiallyFailed · 3 errors
evidence · schedule daily-full
phase: PartiallyFailed
errors: 3
error: snapshot shop/data-orders-db-0: 403 permission denied
       (create snapshot not allowed for the backup identity)
volumeSnapshotsAttempted: 3   completed: 0
# Schedule (cluster)
spec.template: { includedNamespaces: [shop, payments], snapshotVolumes: true, ttl: 720h }
status.lastBackup: 2026-09-23T04:00:12Z
# git: infrastructure/velero/schedule_daily-full.yaml · backupstoragelocation_default.yaml
cnpg · Cluster payments/billing-pg
  • billing-pg-20260923000000 failed
  • billing-pg-20260922000000 failed
spec.backup:
  barmanObjectStore:
    destinationPath: s3://acme-backups/billing-pg
    s3Credentials: { accessKeyId: { name: billing-pg-s3, key: ACCESS_KEY_ID } }
  retentionPolicy: 30d
status.lastFailedBackup: 2026-09-23T00:00:04Z
G
gitops-assistant backup analysis
The Kubernetes objects are backed up; every volume snapshot fails with 403. The backup identity can read disks but may not create snapshots.
Check first: the snapshot permission on the backup identity's cloud role. Nothing in the Schedule or storage location changed.
G
gitops-assistant
Confirm with a one-off backup of shop and check that volumeSnapshotsCompleted equals volumeSnapshotsAttempted.
Velero backup failing: daily-full
issue · 2 runs PartiallyFailed · volume snapshots 0 / 3
category:reliabilitysource:backuprisk:high
↓ the full issue is below
planned checks · silence is not success
  • BackupStorageLocation default Unavailable · no backup attempted
  • newest Completed backup · daily-full 9 days old · schedule is daily
  • volume snapshots completed 0, schedule includes 3 volumes
0 failed backups in window · and still no usable backup
planned · infrastructure/velero/schedule_daily-full.yaml
  spec:
    schedule: "0 4 * * *"
    template:
-     ttl: 72h0m0s
+     ttl: 720h0m0s        # match the 30-day retention the runbook promises
      snapshotVolumes: true
planned · upgrade-time permission diff
backup plugin v1.7 → v1.9, documented cloud permissions
+ one permission added in v1.9, missing from the current role

The issue you get.

Illustrative, shaped like the real backup issue. It has the same title format, the same labels and the same evidence sections. Backup findings are issues today, not merge requests.

Issue

Velero backup failing: daily-full

opened by gitops-assistant · cluster prod · namespace velero
category:reliabilitysource:backuprisk:high
DiagnosisEvidenceNext steps
Summary

The Velero schedule daily-full has produced PartiallyFailed backups on the last 2 runs in the 48-hour window. Kubernetes objects are saved. No volume snapshot completed (0 of 3), so persistent data in shop and payments is not restorable from these backups.

Probable cause

Every snapshot error is a 403 on snapshot creation. The backup identity can list disks but lacks permission to snapshot them. The Schedule and BackupStorageLocation in git are unchanged in this period, which points at the cloud role rather than the manifests.

Blast radius

Velero schedule daily-full: 2 backup runs failed. Restores from these runs would bring back objects without their data.

RunPhaseError
daily-full-20260923040012PartiallyFailedsnapshot shop/data-orders-db-0: 403 permission denied
daily-full-20260922040009PartiallyFailedsnapshot shop/data-orders-db-0: 403 permission denied
Related manifests in git
  • infrastructure/velero/schedule_daily-full.yaml
  • infrastructure/velero/backupstoragelocation_default.yaml
  • Check the cloud role bound to the Velero identity for the snapshot-create permission your backup plugin version documents.
  • Grant the missing permission (outside this repository), then run a one-off backup: velero backup create verify-snapshots --include-namespaces shop.
  • Confirm volumeSnapshotsCompleted equals volumeSnapshotsAttempted in velero backup describe.
  • Leave the next scheduled run to confirm. This issue will not re-open while runs complete.

What keeps it honest.

A backup alert that cries wolf gets muted, and a muted backup alert is how data gets lost.

One finding per scheduleThe assistant groups failed runs per Velero Schedule or CNPG Cluster. It does not re-raise an open finding on every scan.
Partial countsThe assistant treats PartiallyFailed as a failure, because the missing part is usually the data.
Never droppedIf the analysis cannot be produced, the issue still opens with the raw phase and error.
No guessed storage editsAn AI model never rewrites storage locations, prefixes or credentials. The issue explains, and you make the change.
Read-onlyThe scan lists backups, schedules and clusters. It cannot create, delete or restore anything.
Evidence, not a verdictThe raw errors of up to five recent runs are attached, so you can check the diagnosis instead of trusting it.

Where this stands.

Live
  • Velero Failed and PartiallyFailed backups, grouped per Schedule
  • CloudNativePG failed backups, grouped per database cluster
  • Evidence from the cluster and git, diagnosis and next steps, as issues
  • Velero and backup-plugin chart upgrades through the upgrade lane
In development
  • Nothing as of October 2026. The roadmap items are designed and queued.
Roadmap
  • Stale-backup check: age of the newest successful backup per schedule
  • BackupStorageLocation availability and empty-snapshot detection
  • Draft MRs for schedule, retention and missing storage locations
  • Grounding storage-location prefix changes in the bucket's real layout
  • Cloud permission diff when a backup plugin is upgraded
← Previous storySecrets hygiene