Wave 9 — Backups¶
Three different jobs. Do not mix them.
| What | Tool | Where bytes go |
|---|---|---|
| Kubernetes API objects | talosctl etcd snapshot |
Workstation → NAS/S3 file |
| Longhorn volume contents | Longhorn backupstore | MinIO bucket |
| Postgres | Barman Cloud plugin + ObjectStore |
MinIO prefix per database |
MinIO install: Unraid extras. Seal keys: secrets. Skip this wave until the endpoint exists. The Applications are harmless idle if you never create an ObjectStore or a backup target.
Validation
Do not point Longhorn or Barman at MinIO until a worker can reach the API:
# from the workstation, then from a debug pod on a worker:
curl -sI http://10.0.0.2:9000/minio/health/live
mc ls nas/longhorn-backups
Timeout or 403 with the app key (not root) means stop. The cluster masquerades as the node IP; Unraid must allow .21–.29.
Longhorn → MinIO¶
Set a backup target. Helm 1.12 uses defaultBackupStore (not only the old defaultSettings.backupTarget).
- Bucket
longhorn-backupson MinIO. Dedicated access key. - Seal Secret
longhorn-backup-s3in namespacelonghorn:
# keys (stringData before you seal)
AWS_ACCESS_KEY_ID: CHANGEME
AWS_SECRET_ACCESS_KEY: CHANGEME
AWS_ENDPOINTS: http://10.0.0.2:9000
AWS_REGION: us-east-1
- In
values/longhorn/values.yaml:
defaultBackupStore:
backupTarget: s3://longhorn-backups@us-east-1/
backupTargetCredentialSecret: longhorn-backup-s3
pollInterval: "300"
The @us-east-1 is the S3 region token Longhorn expects. MinIO ignores region as long as AWS_ENDPOINTS points at the API. Trailing slash on the URL matters; copy the docs form.
- Sync. Longhorn UI → Backup: target should be Ready.
Validation
Do not trust this for real volumes until: target Ready in the UI, a throwaway PVC snapshot → Backup → Restore to a new volume, file is still there. Unavailable target = endpoint, Secret keys, or trailing slash on backupTarget.
Workers must reach 10.0.0.2:9000. This is not off-site unless MinIO is.
plugin-barman-cloud¶
Barman Cloud plugin (usage). The Application only installs the plugin in cnpg-system. Each database needs its own ObjectStore + Secret + ScheduledBackup in the app namespace. Example: day-2.
etcd-backup¶
Talos: do not mount kubeadm hostPath certs. Use talosctl etcd snapshot. The Application ships a suspended CronJob and a ConfigMap with the workstation command:
talosctl --nodes 10.0.0.11 etcd snapshot ./etcd-$(date -u +%Y%m%dT%H%M%SZ).snapshot
# then: copy to the NAS, or:
mc cp ./etcd-*.snapshot nas/etcd-snapshots/
Automate with a systemd timer on the workstation or a small always-on box that has talosctl + TALOSCONFIG. Do not unsuspend the in-cluster CronJob and expect it to speak the Talos API — that pod does not have your talosconfig.
Restore: Talos day-2. Snapshot ≠ Longhorn bytes.
kubeadm / kubespray: you would snapshot with etcdctl and host-mounted etcd certs. That path is cluster-specific and is not in this repo.
Skip: delete applications/etcd-backup.yaml.