Kubernetes Backup with Velero

Velero is an open-source Kubernetes backup and restore solution that enables disaster recovery, migration, and compliance for Kubernetes clusters. This guide covers installation, backup scheduling, restore operations, volume snapshots, cluster migration, and configuring S3-compatible object storage backends for your VPS and baremetal Kubernetes infrastructure.

Table of Contents

Velero Overview

What is Velero?

Velero is a backup and restore solution for Kubernetes that:

  • Backs up cluster resources and persistent volumes
  • Schedules automated backups
  • Restores to original or different clusters
  • Migrates resources between clusters
  • Enables disaster recovery workflows

Components

Velero Server: Runs in the cluster, manages backups/restores

Velero CLI: Command-line tool for backup operations

Plugins: Integration with storage backends (S3, Azure, vSphere, AWS, etc.)

Restores: Apply backed-up resources to clusters

Installation

Prerequisites

  • Kubernetes v1.16+
  • kubectl configured
  • Object storage (S3, MinIO, S3-compatible)
  • AWS account or MinIO setup (optional)

Installing Velero CLI

On Linux:

wget https://github.com/vmware-tanzu/velero/releases/download/v1.12.1/velero-v1.12.1-linux-amd64.tar.gz
tar -xzf velero-v1.12.1-linux-amd64.tar.gz
sudo mv velero-v1.12.1-linux-amd64/velero /usr/local/bin/
velero version

On macOS:

brew install velero
velero version

Installing Velero in Kubernetes

Create credentials file for S3:

cat << EOF > credentials-velero
[default]
aws_access_key_id=AKIAIOSFODNN7EXAMPLE
aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
EOF

Install Velero:

velero install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.8.1 \
  --bucket velero-backups \
  --secret-file ./credentials-velero \
  --use-volume-snapshots=true \
  --snapshot-location-config snapshotLocation=us-east-1 \
  --use-mutatingleiamingestaddin=true \
  --wait

Verify installation:

kubectl get pods -n velero
velero version

Storage Backend Configuration

AWS S3 Backend

Configure for AWS S3:

velero install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.8.1 \
  --bucket velero-backups \
  --secret-file ./credentials-velero \
  --use-volume-snapshots=true \
  --snapshot-location-config snapshotLocation=us-east-1 \
  --prefix production \
  --wait

MinIO Backend

For on-premises S3-compatible storage:

# Create credentials file
cat << EOF > minio-credentials
[default]
aws_access_key_id=minioadmin
aws_secret_access_key=minioadmin
EOF

# Install Velero with MinIO
velero install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.8.1 \
  --bucket velero-backups \
  --secret-file ./minio-credentials \
  --use-volume-snapshots=false \
  --backup-location-config s3Url=https://minio.example.com:9000 \
  --wait

Multiple Backup Locations

Create backup locations programmatically:

apiVersion: velero.io/v1
kind: BackupStorageLocation
metadata:
  name: aws-us-east-1
  namespace: velero
spec:
  provider: aws
  objectStorage:
    bucket: velero-backups-east
  config:
    region: us-east-1
---
apiVersion: velero.io/v1
kind: BackupStorageLocation
metadata:
  name: aws-us-west-2
  namespace: velero
spec:
  provider: aws
  objectStorage:
    bucket: velero-backups-west
  config:
    region: us-west-2

Azure Backend

Configure Azure Blob Storage:

velero install \
  --provider azure \
  --plugins velero/velero-plugin-for-microsoft-azure:v1.8.0 \
  --bucket velero \
  --secret-file ./azure-credentials \
  --use-volume-snapshots=true \
  --snapshot-location-config snapshotLocation=eastus \
  --wait

Backup Operations

On-Demand Backup

Create immediate backup:

velero backup create production-backup-$(date +%Y%m%d-%H%M%S)

With include/exclude filters:

velero backup create full-backup \
  --include-namespaces production,monitoring \
  --exclude-namespaces kube-system,velero

Backup specific resources:

velero backup create app-backup \
  --include-resources deployments,services,configmaps \
  --exclude-namespaces kube-system

Scheduled Backups

Create a backup schedule:

velero schedule create daily-backup \
  --schedule "0 2 * * *" \
  --include-namespaces production \
  --ttl 720h

List schedules:

velero schedule get
velero schedule describe daily-backup

Backup Configuration

Full backup example with scheduling:

velero schedule create production-daily \
  --schedule "0 2 * * *" \
  --include-namespaces production,monitoring \
  --exclude-namespaces kube-system,kube-public \
  --ttl 2160h \
  --wait

Viewing Backups

List all backups:

velero backup get

Get backup details:

velero backup describe production-backup-20240101-120000

View backup logs:

velero backup logs production-backup-20240101-120000

Restore Operations

Basic Restore

Restore latest backup:

velero restore create --from-backup production-backup-20240101-120000

Restore with filtering:

velero restore create production-restore \
  --from-backup production-backup-20240101-120000 \
  --include-namespaces production \
  --include-resources deployments,services,configmaps

Selective Namespace Restore

Restore to different namespace:

velero restore create restore-to-staging \
  --from-backup production-backup-20240101-120000 \
  --namespace-mappings production:staging

Restore with Resource Modification

Restore and modify resources:

# Use restore hooks to modify resources during restore
cat << 'EOF' > restore-actions.yaml
apiVersion: velero.io/v1
kind: Restore
metadata:
  name: production-restore
spec:
  backupName: production-backup-20240101-120000
  hooks:
    resources:
    - name: update-database-config
      includedNamespaces:
      - production
      includedResources:
      - configmaps
      labelSelector:
        matchLabels:
          app: database
      postHooks:
      - exec:
          container: config-updater
          command: ["/scripts/update-db-config.sh"]
          waitTimeout: 5m
EOF

kubectl apply -f restore-actions.yaml

Monitor Restore Progress

velero restore get
velero restore describe production-restore --details
velero restore logs production-restore

Volume Snapshots

EBS Volume Snapshots

Configure snapshot locations:

apiVersion: velero.io/v1
kind: VolumeSnapshotLocation
metadata:
  name: aws-snapshot-location
  namespace: velero
spec:
  provider: aws
  config:
    region: us-east-1
    snapshotLocation: us-east-1a

Enable for backups:

velero backup create volume-backup \
  --snapshot-locations aws-snapshot-location \
  --volume-snapshot-locations aws-snapshot-location

Snapshot Retention

Set retention policy:

velero backup create data-backup \
  --ttl 720h \
  --snapshot-move-data=false

List Snapshots

velero snapshot-location get

Cluster Migration

Pre-Migration Steps

  1. Backup source cluster
  2. Prepare target cluster
  3. Configure same backup location

Migration Process

On source cluster, create full backup:

velero backup create migration-backup \
  --include-namespaces "*" \
  --exclude-namespaces kube-system,kube-public,kube-node-lease

On target cluster:

  1. Install Velero with same backup location
  2. Wait for backup to be available
velero backup get

Restore from backup:

velero restore create migration-restore \
  --from-backup migration-backup \
  --wait

Migrating to Different Storage Class

Use restore transformation:

velero restore create storage-upgrade \
  --from-backup migration-backup \
  --skip-api-validation-crds

Or use patch during restore:

apiVersion: velero.io/v1
kind: Restore
metadata:
  name: storage-class-migrate
spec:
  backupName: migration-backup
  hooks:
    resources:
    - name: change-storage-class
      includedResources:
      - persistentvolumeclaims
      postHooks:
      - exec:
          container: kubectl
          command: ["/bin/sh", "-c"]
          args:
          - "kubectl patch pvc --all -p '{\"spec\":{\"storageClassName\":\"fast-ssd\"}}'"

Advanced Configuration

Custom Velero Configuration

Create custom Velero deployment:

apiVersion: v1
kind: ConfigMap
metadata:
  name: velero-config
  namespace: velero
data:
  enable-restic: "true"
  restic-timeout: "24h"
  restore-only: "false"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: velero
  namespace: velero
spec:
  template:
    spec:
      containers:
      - name: velero
        args:
        - server
        - --features=EnableCSI
        env:
        - name: VELERO_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: AWS_SHARED_CREDENTIALS_FILE
          value: /credentials/cloud

Backup Retention Policies

Implement automatic cleanup:

# Set TTL (time to live) for backups
velero schedule create daily-backups \
  --schedule "0 2 * * *" \
  --ttl 720h \
  --include-namespaces production

Restic for PV Backup

Enable Restic for volume backups:

velero install \
  --use-restic \
  --restic-timeout 24h

Specify which volumes to backup:

apiVersion: v1
kind: Pod
metadata:
  name: app-with-volume
  annotations:
    backup.velero.io/backup-volumes: data,logs
spec:
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: data-pvc
  - name: logs
    persistentVolumeClaim:
      claimName: logs-pvc

Practical Examples

Example: Production Backup and Restore Strategy

# Daily incremental backups
velero schedule create production-daily \
  --schedule "0 2 * * *" \
  --include-namespaces production \
  --exclude-namespaces kube-system \
  --ttl 2160h \
  --wait

# Weekly full backups with longer retention
velero schedule create production-weekly \
  --schedule "0 3 * * 0" \
  --include-namespaces "*" \
  --exclude-namespaces kube-system,kube-public \
  --ttl 4320h \
  --wait

# View schedules
velero schedule get

# Test restore process monthly
velero backup create monthly-test-backup
velero restore create monthly-test-restore --from-backup monthly-test-backup --wait

Example: Disaster Recovery Workflow

# Production cluster backup
velero backup create dr-backup-$(date +%Y%m%d) \
  --include-namespaces production,monitoring,ingress-nginx \
  --snapshot-volumes \
  --wait

# Verify backup completion
velero backup describe dr-backup-20240101

# If disaster occurs, restore to new cluster
# 1. Install Velero on new cluster with same storage location
# 2. Restore backup
velero restore create disaster-recovery \
  --from-backup dr-backup-20240101 \
  --wait

# Monitor restore
velero restore describe disaster-recovery --details

Conclusion

Velero is essential for Kubernetes disaster recovery, migration, and compliance on VPS and baremetal infrastructure. By implementing automated backup schedules, regularly testing restore procedures, and leveraging volume snapshots, you create a robust backup and recovery strategy. Start with simple daily backups of production namespaces, progressively add scheduled snapshots for faster recovery, and regularly test restore procedures to ensure backup integrity. Maintain clear documentation of your backup strategy and recovery procedures for your operations team.