--- # Velero — off-cluster backup/DR of cluster resources + PVC data (ADR-0003, R-STATE-03). LIVE. # # TARGET: the MinIO S3 endpoint ${S3_BACKUP_ENDPOINT} (cluster-vars; dev http://192.168.1.9:9000 on # Proxmox — plain HTTP, path-style), bucket # `velero`. region us-east-1 is a placeholder MinIO ignores (S3 clients still require one). # # WHY THIS SHAPE: # - provider aws + velero-plugin-for-aws (init container) drives the S3-compatible MinIO target. # - File System Backup (kopia) via the node-agent DaemonSet — storage-agnostic PVC backup that does # NOT depend on CSI VolumeSnapshots or a data-mover (the simplest path that still captures the # Longhorn PVC *data*). snapshotsEnabled:false → no VolumeSnapshotLocation is created/needed. # - Credentials: the `cloud` INI key of the SOPS Secret velero-cloud-credentials (ns velero) — the # SCOPED MinIO key limited to the velero+cnpg buckets. Kept in sync with the staging source of # truth platform/backup/minio-credentials.sops.yaml and the Proxmox host ansible-vault. # # VOLUME OPT-OUT (per the sizing decision) is implemented with TWO schedules (a single Backup has one # cluster-wide defaultVolumesToFsBackup, so per-namespace volume policy needs two): see `schedules`. # # NON-GATING TIER: reconciled by clusters/base/backup.yaml (dependsOn platform-config, wait:false). # A backup controller must NEVER gate the platform graph (mirror headlamp/oauth2-proxy). apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: velero namespace: velero spec: interval: 30m chart: spec: chart: velero version: ">=12.0.0 <13.0.0" # Velero v1.18.x line (k8s-1.36 catch-up). CRDs pre-applied server-side (upgradeCRDs:false). Renovate maintains sourceRef: kind: HelmRepository name: vmware-tanzu namespace: velero install: remediation: retries: 3 upgrade: remediation: retries: 3 values: # --- CRD install strategy. The chart's pre-install `velero-upgrade-crds` HOOK job runs # docker.io/bitnami/kubectl, whose public Docker Hub catalog Bitnami REMOVED (Aug 2025) — # `docker.io/bitnami/kubectl:1.31` now 404s, leaving the hook in Init:ImagePullBackOff so Velero # never installs. The hook exists ONLY to UPDATE CRDs on chart upgrades; it is NOT how CRDs are # first installed. The chart ships all 13 Velero CRDs (backups/restores/backupstoragelocations/ # schedules/podvolumebackups/…) in its native `crds/` directory, which Helm applies # UNCONDITIONALLY on install — before hooks — regardless of this flag. # Disabling the hook therefore drops the fragile external-kubectl-image dependency entirely while # the CRDs still install via Helm's crds/ handling. Trade-off: Helm never manages crds/ after the # initial install, so CRD *schema upgrades* on future chart bumps become a manual/Renovate step — # acceptable: Velero's CRDs are stable, and this is far less fragile than pinning a shell-bearing # kubectl mirror (rancher/kubectl is distroless → no /bin/sh for the hook's copy-binary step). --- upgradeCRDs: false # --- AWS object-store plugin (BSL provider=aws → MinIO S3-compatible), loaded as an init container. # Image minor MUST track the Velero minor (chart 12.x = Velero 1.18 → plugin v1.14.x). --- initContainers: - name: velero-plugin-for-aws image: velero/velero-plugin-for-aws:v1.14.2 imagePullPolicy: IfNotPresent volumeMounts: - mountPath: /target name: plugins # --- File System Backup (kopia): the node-agent DaemonSet mounts each pod's volumes and copies # the data into S3. Storage-agnostic; no CSI-snapshot / data-mover wiring. --- deployNodeAgent: true snapshotsEnabled: false # no VolumeSnapshotLocation — kopia FSB is the volume-data path configuration: uploaderType: kopia backupStorageLocation: - name: default provider: aws bucket: velero default: true config: region: us-east-1 # placeholder; MinIO ignores it (S3 clients require one) s3Url: ${S3_BACKUP_ENDPOINT} # on-Proxmox MinIO, plain HTTP (cluster-vars) s3ForcePathStyle: "true" # MinIO is path-style credentials: existingSecret: velero-cloud-credentials # SOPS Secret carrying the `cloud` INI key (ns velero) # --- Daily backups. TWO schedules implement the opt-out volume policy: capture every PVC's data # by default (opt-out), but skip the two reconstructable heavy volumes' DATA while still # capturing their Kubernetes resources. --- schedules: # (1) The whole cluster EXCEPT monitoring+unifi: all resources + all pod-volume data via kopia. # defaultVolumesToFsBackup:true is the OPT-OUT model — nothing with real data is forgotten. daily: disabled: false schedule: "${VELERO_BACKUP_SCHEDULE}" useOwnerReferencesInBackup: false template: ttl: "${VELERO_RETENTION}" storageLocation: default snapshotVolumes: false defaultVolumesToFsBackup: true excludedNamespaces: - monitoring # volume DATA excluded here; resources captured by schedule (2) - unifi # (2) monitoring + unifi: RESOURCES ONLY (defaultVolumesToFsBackup:false → no volume data). Their # PVCs are reconstructable and excluded from data backup per the sizing decision: # - monitoring: the Prometheus TSDB PVC (ephemeral/reconstructable) and the Loki 72h-log PVC # (Grafana/Alertmanager are emptyDir — no PVC). Grafana dashboards are GitOps-provisioned. # - unifi: the ~7.4 GiB KubeVirt VM disk (huge + reconstructable; UniFi is protected by its # own config export, not this disk). # Backing up their K8s objects (VM/DataVolume/Services/HelmRelease-owned CRs) still aids DR. daily-resources-only: disabled: false schedule: "${VELERO_BACKUP_SCHEDULE}" useOwnerReferencesInBackup: false template: ttl: "${VELERO_RETENTION}" storageLocation: default snapshotVolumes: false defaultVolumesToFsBackup: false includedNamespaces: - monitoring - unifi # Modest home-dev footprint (mirror the other platform components). resources: requests: cpu: 50m memory: 128Mi limits: memory: 512Mi nodeAgent: resources: requests: cpu: 50m memory: 128Mi limits: memory: 512Mi