🗺️ What is Velero?

Velero (formerly Ark) is a CNCF open-source tool for backing up and restoring Kubernetes cluster resources and persistent volumes. It supports disaster recovery, data migration between clusters, and pre-upgrade snapshots.

Velero works by integrating with your cloud provider's object storage (e.g. S3, GCS, Azure Blob) for resource manifests and with volume snapshot APIs for PV data.

Kubernetes Cluster Velero Server Deployment Node Agent DaemonSet Velero CRDs Backup Restore Schedule BackupStorageLocation VolumeSnapshotLocation Object Storage S3 / GCS / Azure Blob manifests + metadata Volume Snapshots CSI / cloud snapshots or filesystem backup manifests PV data

🛡️ Disaster Recovery

Scheduled backups to object storage. Restore entire namespaces or targeted resources.

🚚 Cluster Migration

Move workloads between clusters or cloud providers by backup + restore.

📸 Pre-change Snapshots

Snapshot before upgrades or risky changes. Roll back to a known-good state.

🔌 Plugin Architecture

Cloud-provider plugins for object stores and volume snapshots. Extensible with hooks.

🧩 Core Concepts

Key CRDs

CRDPurpose
BackupPoint-in-time backup — what to include/exclude, TTL, hooks
RestoreRestore from a backup — namespace mapping, label selectors
ScheduleCron-triggered recurring Backup creation
BackupStorageLocationObject-store bucket + credentials (multiple supported)
VolumeSnapshotLocationWhere volume snapshots are stored (cloud zone/region)
DownloadRequestUsed internally by CLI to stream backup logs

Backup Approaches

CSI Snapshots

Uses the CSI VolumeSnapshot API. Fast, storage-native, preferred on modern clusters.

File-System Backup

Node Agent DaemonSet streams volume data to object storage using Kopia. Works without CSI support.

Cloud-native Snapshots

Provider plugin calls cloud snapshot APIs (EBS, GCP PD, Azure Disk) directly. Very fast.

⚠️ File-system backup is slower Use CSI snapshots when possible. File-system backup is a fallback for volumes CSI cannot snapshot (e.g. hostPath, NFS).

Installing Velero (AWS example)

# Install Velero CLI (macOS)
brew install velero

# Create static credentials file (use IRSA in production)
cat > credentials-velero <<EOF
[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
EOF

# Deploy Velero into the cluster
velero install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.9.0 \
  --bucket my-velero-backups \
  --secret-file ./credentials-velero \
  --backup-location-config region=us-east-1 \
  --snapshot-location-config region=us-east-1 \
  --use-node-agent
💡 Use IRSA / Workload Identity in production On AWS use IRSA, on GCP use Workload Identity, on Azure use pod-managed identity. Avoid static credentials.

Verify Installation

kubectl get deployment velero -n velero
velero backup-location get
# NAME      PROVIDER   BUCKET/PREFIX         PHASE
# default   aws        my-velero-backups     Available
kubectl get daemonset node-agent -n velero
# NAME PROVIDER BUCKET/PREFIX PHASE # default aws my-velero-backups Available kubectl get daemonset node-agent -n velero

💾 Backups & Restores

Creating a Backup

# Ad-hoc backup of a single namespace
velero backup create my-app-backup \
  --include-namespaces my-app \
  --ttl 720h    # retain for 30 days

# Backup with label selector
velero backup create api-backup \
  --selector app=api \
  --include-namespaces production

# Backup entire cluster (all namespaces)
velero backup create full-cluster-backup

# Check status
velero backup describe my-app-backup
velero backup logs my-app-backup

Backup YAML manifest

apiVersion: velero.io/v1
kind: Backup
metadata:
  name: my-app-backup
  namespace: velero
spec:
  includedNamespaces:
    - my-app
  excludedResources:
    - events
    - events.events.k8s.io
  ttl: 720h0m0s
  storageLocation: default
  volumeSnapshotLocations:
    - default
  hooks:
    resources:
      - name: freeze-db
        includedNamespaces: [my-app]
        labelSelector:
          matchLabels: {app: postgres}
        pre:
          - exec:
              container: postgres
              command: ["/bin/bash", "-c", "psql -c 'CHECKPOINT;'"]
              onError: Fail
              timeout: 30s
ℹ️ Hooks for application consistency Pre-backup hooks let you quiesce applications (flush DB buffers, freeze filesystems) before the snapshot. Post-backup hooks resume them. Essential for consistent backups of stateful apps.

Restoring from a Backup

# Restore everything from a backup
velero restore create --from-backup my-app-backup

# Restore to a different namespace
velero restore create \
  --from-backup my-app-backup \
  --namespace-mappings my-app:my-app-restored

# Restore only specific resources
velero restore create \
  --from-backup my-app-backup \
  --include-resources deployments,services,configmaps

# Monitor restore status
velero restore describe my-app-backup-20240101
velero restore logs my-app-backup-20240101

Scheduled Backups

# CLI shorthand
velero schedule create daily-app-backup \
  --schedule="0 2 * * *" \
  --include-namespaces my-app \
  --ttl 168h   # 7 days

# As a YAML manifest
apiVersion: velero.io/v1
kind: Schedule
metadata:
  name: daily-app-backup
  namespace: velero
spec:
  schedule: "0 2 * * *"   # 2 AM daily
  template:
    includedNamespaces:
      - my-app
    ttl: 168h0m0s
    storageLocation: default

Backup Retention Strategy

ScheduleFrequencyTTLUse case
Hourly@every 1h24hHigh-change workloads, short-term undo
Daily0 2 * * *7dStandard production namespaces
Weekly0 3 * * 030dCompliance / long-term retention
Monthly0 4 1 * *365dRegulatory / audit archives

🚚 Cluster Migration

Velero's most powerful use case: move workloads from one cluster to another — across regions, cloud providers, or on-prem to cloud.

Migration Workflow

  1. Install Velero on source cluster pointing to shared object storage bucket.
  2. Run velero backup create cluster-migration --include-namespaces app1,app2 on source.
  3. Verify backup is Completed: velero backup describe cluster-migration.
  4. Install Velero on destination cluster pointing to the same object storage bucket (read-only is fine).
  5. Run velero restore create --from-backup cluster-migration on destination.
  6. Validate workloads, update DNS/load-balancer endpoints, drain source.
⚠️ Storage class differences If the destination cluster uses different StorageClass names, use --restore-option flags or a ConfigMap to map old → new storage classes before restoring PVCs.
# Map storage classes during restore
velero restore create \
  --from-backup cluster-migration \
  --storage-class-name standard=premium-ssd

# Or use a ConfigMap
kubectl apply -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
  name: change-storage-class-config
  namespace: velero
  labels:
    velero.io/plugin-config: ""
    velero.io/change-storage-class: RestoreItemAction
data:
  gp2: gp3
  standard: premium-ssd
EOF

Multiple Backup Storage Locations

You can configure secondary BSLs for cross-region redundancy:

velero backup-location create secondary \
  --provider aws \
  --bucket my-velero-backups-eu \
  --config region=eu-west-1

# Mark a BSL as read-only (for migration destination)
velero backup-location set secondary --access-mode ReadOnly

Production Best Practices

Test Restores Regularly

Schedule monthly restore drills to a staging cluster. A backup you've never restored from is not a backup.

Encrypt Backups

Enable server-side encryption on your S3 bucket (SSE-KMS). Velero does not encrypt independently.

Monitor Backup Status

Expose velero_backup_success_total and velero_backup_failure_total Prometheus metrics. Alert on failures.

Exclude Ephemeral Data

Exclude events, cache PVCs, and scratch volumes from backups to reduce size and cost.

📝 Knowledge Check

Q1. What component enables file-system (Kopia-based) PV backups without CSI support?
  • A) Velero Server Deployment
  • B) Node Agent DaemonSet
  • C) VolumeSnapshotLocation CRD
  • D) BackupStorageLocation plugin
B) Node Agent DaemonSet. The node-agent DaemonSet (formerly restic/Kopia daemon) runs on every node and streams volume data directly to object storage, bypassing the CSI snapshot API.
Q2. You need to quiesce a PostgreSQL database before taking a backup snapshot. Which Velero feature do you use?
  • A) Schedule TTL
  • B) Label selectors
  • C) Backup hooks (pre/post exec)
  • D) VolumeSnapshotLocation
C) Backup hooks. Pre-backup hooks execute commands inside containers before the snapshot (e.g. CHECKPOINT in Postgres). Post-backup hooks resume after the snapshot completes.
Q3. During a cluster migration, the destination cluster uses a different StorageClass name (gp2gp3). How do you handle this in Velero?
  • A) Manually edit every PVC manifest after restore
  • B) Apply a change-storage-class ConfigMap in the velero namespace before restoring
  • C) Delete and re-create all PVCs after restore
  • D) Velero handles it automatically with no configuration
B) Apply a change-storage-class ConfigMap. Velero's change-storage-class RestoreItemAction plugin reads this ConfigMap and rewrites StorageClass references during restore.