Longhorn Volume Backups
Overview
Longhorn provides native backup functionality for persistent volumes. This ensures your application data is protected independently of the cluster state. Longhorn backups capture the actual data stored in your persistent volumes and store them in object storage (Cloudflare R2).
Configuration Files
The Longhorn backup system consists of three components that you need to create:
- Secret - R2 credentials
- BackupTarget - Backup destination configuration
- RecurringJob - Scheduled backup job
Setup Steps
-
Create the R2 Secret:
Create a file named
longhorn-r2-secret.yamlwith the following content:apiVersion: v1
kind: Secret
metadata:
name: r2-longhorn-secret
namespace: longhorn-system
type: Opaque
stringData:
AWS_ACCESS_KEY_ID: 'YOUR_R2_ACCESS_KEY_ID'
AWS_SECRET_ACCESS_KEY: 'YOUR_R2_SECRET_ACCESS_KEY'
AWS_ENDPOINTS: 'https://<YOUR_ACCOUNT_ID>.r2.cloudflarestorage.com'Apply the secret:
kubectl apply -f longhorn-r2-secret.yaml -
Configure the Backup Target:
Create a file named
backup-target.yamlwith the content shown in the "Backup Target Configuration" section below, then apply it:kubectl apply -f backup-target.yaml -
Create the Daily Backup Job:
Create a file named
daily-backup-job.yamlwith the content shown in the "Recurring Job Configuration" section below, then apply it:kubectl apply -f daily-backup-job.yaml
Backup Target Configuration
The BackupTarget resource configures where backups are stored:
apiVersion: longhorn.io/v1beta2
kind: BackupTarget
metadata:
name: default
namespace: longhorn-system
spec:
backupTargetURL: 's3://k3s-backup-repository@auto/'
credentialSecret: 'r2-longhorn-secret'
Backup Target URL Format
For Cloudflare R2:
s3://<bucket-name>@auto/<optional-path>
@autois the region (R2 doesn't use regions, soautoworks)- Optional path can be added for organization (e.g.,
s3://bucket@auto/longhorn-backups/)
Recurring Job Configuration
The RecurringJob defines the backup schedule:
apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
name: daily-volume-backups
namespace: longhorn-system
spec:
task: 'backup'
cron: '0 2 * * *' # Daily at 2:00 AM
retain: 7 # Keep 7 backups
concurrency: 1 # One job at a time
Recurring Job Parameters
task: Type of task (backup,snapshot, orsnapshot-cleanup)cron: Cron expression for scheduleretain: Number of backups to keepconcurrency: How many jobs can run simultaneously
Volume Labeling
For volumes to be included in the daily backup, they must have the appropriate label. There are several ways to ensure your volumes are backed up:
Option 1: Label PVCs at Creation Time (Recommended)
When creating PVCs via Helm charts or manifests, add the backup label:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-app-data
namespace: my-app
labels:
recurring-job.longhorn.io/daily-volume-backups: enabled
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 10Gi
Option 2: Label Existing PVCs
For existing PVCs, add the label manually:
# Label a specific PVC
kubectl label pvc <pvc-name> -n <namespace> recurring-job.longhorn.io/daily-volume-backups=enabled
# Label all PVCs using Longhorn storage class
kubectl get pvc --all-namespaces -l storageClassName=longhorn -o name | \
xargs -I {} kubectl label {} recurring-job.longhorn.io/daily-volume-backups=enabled
Option 3: Label Longhorn Volumes Directly
If PVC labels don't propagate to Longhorn volumes, label them directly:
kubectl label volume <volume-name> -n longhorn-system recurring-job.longhorn.io/daily-volume-backups=enabled
Option 4: Apply to All Volumes
To apply the recurring job to all volumes (not recommended for production),
leave the groups and labels fields empty in the RecurringJob spec.
Verification
-
Check volume labels:
kubectl get volumes -n longhorn-system --show-labels | grep recurring-job -
Monitor backup jobs:
kubectl get jobs -n longhorn-system -
Check backup logs:
kubectl logs job/<backup-job-name> -n longhorn-system -
Verify backups in R2 bucket:
- Check your Cloudflare R2 bucket for backup files
-
Check recurring jobs:
kubectl get recurringjobs -n longhorn-system -
Check backup status in Longhorn UI:
kubectl port-forward -n longhorn-system svc/longhorn-frontend 8080:80Navigate to
http://localhost:8080→ Backups
Restore from Longhorn Backup
Via Longhorn UI
-
Access Longhorn UI:
kubectl port-forward -n longhorn-system svc/longhorn-frontend 8080:80Open
http://localhost:8080in your browser -
Navigate to Backups in the Longhorn UI
-
Select the backup you want to restore
-
Create a new volume from the backup:
- Click on the backup
- Click "Create Volume"
- Choose a name for the restored volume
-
Update your PVC to use the restored volume:
- Delete the old PVC (if needed)
- Create a new PVC pointing to the restored volume
- Or update your application to use the restored volume
Via kubectl
-
List available backups:
kubectl get backups -n longhorn-system -
Create a volume from backup:
kubectl create -f - <<EOF
apiVersion: longhorn.io/v1beta2
kind: Volume
metadata:
name: restored-volume
namespace: longhorn-system
spec:
fromBackup: "s3://bucket@auto/path/to/backup"
EOF
Manual Backup
You can trigger a manual backup for a specific volume:
-
Via Longhorn UI:
- Navigate to Volumes
- Select the volume
- Click "Backup Now"
-
Via kubectl:
kubectl create job --from=cronjob/<recurring-job-name> manual-backup-$(date +%s) -n longhorn-system
Troubleshooting
Backups Not Running
-
Check recurring job status:
kubectl get recurringjobs -n longhorn-system
kubectl describe recurringjob daily-volume-backups -n longhorn-system -
Verify volume labels:
kubectl get volumes -n longhorn-system --show-labels -
Check Longhorn manager logs:
kubectl logs -n longhorn-system -l app=longhorn-manager | grep backup
Backup Target Not Configured
-
Check backup target:
kubectl get backuptarget -n longhorn-system
kubectl describe backuptarget default -n longhorn-system -
Verify secret exists:
kubectl get secret r2-longhorn-secret -n longhorn-system -
Test backup target connection:
- Use Longhorn UI → Settings → Backup
- Click "Test" to verify connection
Backup Failures
-
Check backup job logs:
kubectl get jobs -n longhorn-system
kubectl logs job/<backup-job-name> -n longhorn-system -
Verify R2 credentials:
kubectl get secret r2-longhorn-secret -n longhorn-system -o yaml -
Check network connectivity:
- Verify R2 endpoint is reachable
- Check firewall rules
Volume Not Backing Up
-
Verify volume has the label:
kubectl get volume <volume-name> -n longhorn-system --show-labels -
Check if volume is attached:
kubectl get volume <volume-name> -n longhorn-system -o yaml | grep attached -
Verify recurring job matches:
kubectl get recurringjob daily-volume-backups -n longhorn-system -o yaml
Best Practices
- Label Strategy: Use consistent labeling for all production volumes
- Retention Policy: Adjust retention based on your R2 storage costs and needs
- Test Restores: Regularly test restoring volumes from backups
- Monitor Costs: Keep an eye on R2 storage usage and costs
- Backup Verification: Set up monitoring to alert on backup failures
- Separate Environments: Use different backup targets or paths for dev/prod
References
- Longhorn documentation: https://longhorn.io/docs/
- Longhorn backup guide: https://longhorn.io/docs/1.5.3/snapshots-and-backups/