Skip to content

Velero Backup and Restore

Learn Kubernetes disaster recovery with Velero and MinIO as S3-compatible storage.

Time: ~20 minutes Difficulty: Intermediate

  • Velero architecture: backup and restore workflow
  • S3-compatible storage for backup data (MinIO)
  • Creating on-demand backups of namespace resources
  • Simulating disaster scenarios and restoring from backup
  • Scheduled backups for regular backup policies
  • Backup with label selectors to target specific resources

To verify Velero CLI:

Terminal window
velero version --client-only

Navigate to the demo directory:

Terminal window
cd demos/velero

MinIO provides an S3-compatible API that Velero uses as a backup target.

Terminal window
kubectl apply -f manifests/namespace.yaml
kubectl apply -f manifests/minio.yaml

Wait for MinIO to be ready:

Terminal window
kubectl wait --for=condition=ready pod -l app=minio -n velero-demo --timeout=120s

Port-forward to MinIO console and create a bucket:

Terminal window
kubectl port-forward -n velero-demo svc/minio 9001:9001 &

Open http://localhost:9001 in your browser, log in with credentials minio / minio123, and create a bucket named velero.

Alternatively, use kubectl exec to create the bucket:

Terminal window
kubectl exec -n velero-demo deployment/minio -- mkdir -p /data/velero

Install Velero using the CLI and point it to MinIO:

Terminal window
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.9.0 \
--bucket velero \
--secret-file manifests/credentials-velero \
--use-volume-snapshots=false \
--backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://minio.velero-demo.svc:9000

Velero creates its own namespace (velero) and installs the server components.

Check Velero is running:

Terminal window
kubectl get pods -n velero
velero version
Terminal window
kubectl apply -f manifests/sample-app.yaml

Verify the sample app is running:

Terminal window
kubectl get pods -n velero-demo
kubectl get svc -n velero-demo
Terminal window
velero backup create demo-backup --include-namespaces velero-demo

Check backup status:

Terminal window
velero backup describe demo-backup
velero backup logs demo-backup

Wait for the backup to complete (status should be Completed):

Terminal window
velero backup get

Delete the sample app resources (but keep MinIO running, since it holds the backups):

Terminal window
kubectl delete deployment sample-app -n velero-demo
kubectl delete service sample-app -n velero-demo
kubectl delete configmap sample-config -n velero-demo

Note: Don’t delete MinIO. Since MinIO stores the backups in this demo, deleting it would destroy the backup data. In production, backup storage lives outside the cluster (AWS S3, GCS, Azure Blob) so this circular dependency doesn’t exist.

Verify everything is gone:

Terminal window
kubectl get all -n velero-demo
Terminal window
velero restore create --from-backup demo-backup

Check restore status:

Terminal window
velero restore get
velero restore describe demo-backup-<TAB>

Verify resources are back:

Terminal window
kubectl get all -n velero-demo
kubectl get configmap -n velero-demo

The deployment, service, and configmap should all be restored.

manifests/
namespace.yaml # velero-demo namespace
minio.yaml # MinIO deployment, service, PVC for S3-compatible storage
sample-app.yaml # Sample nginx app with ConfigMap (what we back up)
credentials-velero # AWS-format credentials for Velero to access MinIO

Velero workflow:

  1. Backup: Velero server watches for backup requests, queries the Kubernetes API for resources in the target namespace, serializes them to JSON, and uploads to S3 (MinIO).
  2. Storage: MinIO stores the backup tarball in the velero bucket.
  3. Restore: Velero downloads the backup from MinIO, extracts the JSON manifests, and creates resources in the cluster.

Key concepts:

  • BackupStorageLocation: Tells Velero where to store backups (S3, GCS, Azure Blob).
  • VolumeSnapshotLocation: For PV snapshots (disabled in this demo for simplicity).
  • Backup scope: Can target specific namespaces, labels, or exclude certain resources.
  • Restore: Creates resources from backup data, can restore to same or different namespace.

MinIO runs in the same cluster for simplicity. In production, use external object storage (AWS S3, GCS, Azure Blob) for true disaster recovery.

  1. Scheduled backups: Create a backup schedule that runs every 6 hours.

    Terminal window
    velero schedule create daily-backup --schedule="0 */6 * * *" --include-namespaces velero-demo
    velero schedule get
  2. Backup with label selectors: Backup only resources with a specific label.

    Terminal window
    velero backup create app-only --selector app=sample-app
    velero backup describe app-only
  3. Restore to a different namespace: Restore the backup to a new namespace.

    Terminal window
    kubectl create namespace velero-restore-test
    velero restore create --from-backup demo-backup --namespace-mappings velero-demo:velero-restore-test
    kubectl get all -n velero-restore-test
  4. Exclude specific resources: Backup everything except ConfigMaps.

    Terminal window
    velero backup create no-configmaps --include-namespaces velero-demo --exclude-resources configmaps
    velero backup describe no-configmaps
  5. Backup hooks: Add pre and post backup hooks to your pods (see Velero docs).

Terminal window
# Delete Velero installation
velero uninstall
# Delete the demo namespace
kubectl delete namespace velero-demo
# Stop port-forward if still running
pkill -f "port-forward.*minio"

See docs/deep-dive.md for a detailed explanation of Velero architecture, backup storage locations, volume snapshots, disaster recovery strategies, and production best practices.

Move on to Sealed Secrets to learn safe GitOps secret management with encryption.