Config backups (Velero)
Velero backs up the *arr/Jellyfin/Seerr /config PVCs (Ceph RBD — SQLite state,
history, quality profiles) to an external S3 bucket, daily, retained 14 days. It uses
File System Backup (kopia via the node-agent) — no CSI snapshot CRDs required — and is
opt-in: only the config volume is copied, so the 100 Ti NFS /data is skipped.
| Piece | Where |
|---|---|
| Velero HelmRelease + node-agent | k8s/manifests/base/cluster-services/velero/ (ns velero, Flux cluster-services-velero) |
| S3 credentials | cloud-credentials — from Vault via vault-secrets-operator (velero-secrets role) |
| Backup target (BSL) | velero-helm.yaml → configuration.backupStorageLocation |
| Schedule | velero-schedules/schedule-media.yaml → media-config-daily (daily 02:00, ttl: 336h) — applied by a separate Flux Kustomization (cluster-services-velero-schedules) that dependsOn the install, so the velero.io CRD exists before the Schedule is applied |
| Opt-in marker | backup.velero.io/backup-volumes: config on each media pod |
Fill these in (once)
Section titled “Fill these in (once)”1. Point the BackupStorageLocation at your S3 — edit velero-helm.yaml
(bucket / region / s3Url are not secret). Current target is Backblaze B2:
backupStorageLocation: - name: default provider: aws default: true bucket: k8s-homelab-muehlena-de-velero-backup config: region: eu-central-003 s3Url: https://s3.eu-central-003.backblazeb2.com s3ForcePathStyle: "true" checksumAlgorithm: "" # non-AWS S3 (B2/MinIO/…) reject the x-amz-checksum header2. Create the Vault policy + role (once), then write the S3 credentials to Vault. The
velero-secrets role/policy are Terraform-managed like the other apps:
cd tf/application-parameters/hl-cluster-vault && terraform init -upgrade && terraform applyWrite the credentials as two readable fields — VSO’s transformation renders them into the
cloud INI that Velero expects:
bao kv put secrets/cluster/internal/ns/velero/backup \ access_key_id=AKIA... \ secret_access_key=...Commit the BSL edit. Flux installs Velero, VSO syncs cloud-credentials (the templated
cloud key only — the raw fields are excluded), and the BSL goes Available
(kubectl -n velero get secret cloud-credentials should have a cloud key).
Verify
Section titled “Verify”kubectl -n velero get backupstoragelocation default # PHASE=Availablekubectl -n velero get schedule media-config-dailyvelero backup create media-adhoc --from-schedule media-config-daily # or wait for 02:00velero backup describe media-adhoc --details # PodVolumeBackups = the config volumesRestore
Section titled “Restore”# list, then restore the whole media namespace from a backup:velero backup getvelero restore create --from-backup media-config-daily-20260712020000Restore recreates the <app>-config PVCs and kopia-restores their contents. The static
NFS media-data PV/PVC and the app manifests themselves come back from Git (Flux) — this
backup is specifically the stateful config that isn’t reproducible from the repo.
- DR scope: an external bucket means backups survive a full Ceph loss. Guard the bucket’s own credentials/retention accordingly.
- On first reconcile the
media-config-dailySchedule may error briefly until the Velero CRDs are installed by the HelmRelease — Flux retries, no action needed. - Bazarr/Seerr are included too (their
/configis annotated), so subtitle/request state is captured alongside the *arr DBs.