Backing Up AKS with Velero
Prerequisites
- AKS cluster running
- Azure CLI installed
- kubectl configured
- Helm installed
Step 1: Create Azure Storage Account & Blob Container
# Set variablesRESOURCE_GROUP="myResourceGroup"LOCATION="eastus"STORAGE_ACCOUNT="velerobackupstorage"BLOB_CONTAINER="velero-backups"AKS_CLUSTER="myAKSCluster"# Create resource group (if not exists)az group create --name $RESOURCE_GROUP --location $LOCATION# Create storage accountaz storage account create \ --name $STORAGE_ACCOUNT \ --resource-group $RESOURCE_GROUP \ --location $LOCATION \ --sku Standard_LRS \ --encryption-services blob# Create blob containeraz storage container create \ --name $BLOB_CONTAINER \ --account-name $STORAGE_ACCOUNT
Step 2: Create Service Principal for Velero
# Create service principalAZURE_SUBSCRIPTION_ID=$(az account show --query id -o tsv)AZURE_TENANT_ID=$(az account show --query tenantId -o tsv)# Create SP and assign contributor roleAZURE_CLIENT_SECRET=$(az ad sp create-for-rbac \ --name velero-sp \ --role Contributor \ --scopes /subscriptions/$AZURE_SUBSCRIPTION_ID \ --query password \ -o tsv)AZURE_CLIENT_ID=$(az ad sp list \ --display-name velero-sp \ --query '[0].appId' \ -o tsv)echo "Client ID: $AZURE_CLIENT_ID"echo "Client Secret: $AZURE_CLIENT_SECRET"
Step 3: Create Velero Credentials File
# Create credentials filecat << EOF > ./credentials-veleroAZURE_SUBSCRIPTION_ID=${AZURE_SUBSCRIPTION_ID}AZURE_TENANT_ID=${AZURE_TENANT_ID}AZURE_CLIENT_ID=${AZURE_CLIENT_ID}AZURE_CLIENT_SECRET=${AZURE_CLIENT_SECRET}AZURE_RESOURCE_GROUP=${RESOURCE_GROUP}AZURE_CLOUD_NAME=AzurePublicCloudEOF
Step 4: Install Velero on AKS
# Add Velero Helm repohelm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-chartshelm repo update# Get storage account access keySTORAGE_ACCOUNT_KEY=$(az storage account keys list \ --account-name $STORAGE_ACCOUNT \ --resource-group $RESOURCE_GROUP \ --query '[0].value' \ -o tsv)# Install Velero with Azure pluginvelero install \ --provider azure \ --plugins velero/velero-plugin-for-microsoft-azure:v1.8.0 \ --bucket $BLOB_CONTAINER \ --secret-file ./credentials-velero \ --backup-location-config \ resourceGroup=$RESOURCE_GROUP,\ storageAccount=$STORAGE_ACCOUNT,\ storageAccountKeyEnvVar=AZURE_STORAGE_ACCOUNT_ACCESS_KEY \ --snapshot-location-config \ resourceGroup=$RESOURCE_GROUP,\ apiTimeout=5m \ --use-volume-snapshots=true \ --wait
Step 5: Verify Velero Installation
# Check Velero pods are runningkubectl get pods -n velero# Check backup storage location is availablevelero backup-location get# Expected output:# NAME PROVIDER BUCKET/PREFIX PHASE LAST VALIDATED# default azure velero-backups Available ...
Step 6: Create Backups
Manual Backup (Full Cluster)
# Backup entire clustervelero backup create full-cluster-backup \ --include-cluster-resources=true \ --wait# Check backup statusvelero backup describe full-cluster-backupvelero backup logs full-cluster-backup
Backup Specific Namespace
# Backup a single namespacevelero backup create my-app-backup \ --include-namespaces my-app-namespace \ --wait# Backup multiple namespacesvelero backup create multi-ns-backup \ --include-namespaces namespace1,namespace2 \ --wait
Backup with Labels
# Backup resources matching a labelvelero backup create label-backup \ --selector app=my-application \ --wait
Exclude Specific Resources
# Exclude secrets and specific namespacesvelero backup create selective-backup \ --exclude-namespaces kube-system,velero \ --exclude-resources secrets \ --wait
Step 7: Schedule Automated Backups
# Daily backup at 2am UTC (keep 30 days)velero schedule create daily-backup \ --schedule="0 2 * * *" \ --ttl 720h \ --include-cluster-resources=true# Weekly backup every Sunday at midnight (keep 90 days)velero schedule create weekly-backup \ --schedule="0 0 * * 0" \ --ttl 2160h# Namespace-specific daily backupvelero schedule create daily-app-backup \ --schedule="0 2 * * *" \ --include-namespaces production \ --ttl 168h# List all schedulesvelero schedule get
Step 8: Restore from Backup
Full Restore
# List available backupsvelero backup get# Restore full cluster backupvelero restore create \ --from-backup full-cluster-backup \ --wait# Check restore statusvelero restore getvelero restore describe <restore-name>
Restore Specific Namespace
# Restore a specific namespacevelero restore create \ --from-backup my-app-backup \ --include-namespaces my-app-namespace \ --wait
Restore to Different Namespace
# Restore namespace-A into namespace-Bvelero restore create \ --from-backup my-app-backup \ --namespace-mappings old-namespace:new-namespace \ --wait
Restore Specific Resources Only
# Restore only deployments and servicesvelero restore create \ --from-backup full-cluster-backup \ --include-resources deployments,services \ --wait
Step 9: Backup Hooks (Pre/Post Actions)
Useful for database consistency before backup:
# deployment-with-backup-hooks.yamlapiVersion: apps/v1kind: Deploymentmetadata: name: mysql annotations: pre.hook.backup.velero.io/command: '["/bin/bash", "-c", "mysqldump -u root -p$MYSQL_ROOT_PASSWORD mydb > /backup/dump.sql"]' pre.hook.backup.velero.io/timeout: "60s" post.hook.backup.velero.io/command: '["/bin/bash", "-c", "rm -f /backup/dump.sql"]'
kubectl apply -f deployment-with-backup-hooks.yaml
Step 10: Monitor & Troubleshoot
# View backup detailsvelero backup describe my-backup --details# View backup logsvelero backup logs my-backup# View restore logsvelero restore logs my-restore# Check Velero server logskubectl logs deployment/velero -n velero# List all backups with statusvelero backup get# Delete old backup manuallyvelero backup delete old-backup-name
Summary Cheat Sheet
| Task | Command |
|---|---|
| Full backup | velero backup create <name> --include-cluster-resources=true |
| Namespace backup | velero backup create <name> --include-namespaces <ns> |
| Schedule daily | velero schedule create <name> --schedule="0 2 * * *" |
| List backups | velero backup get |
| Restore backup | velero restore create --from-backup <name> |
| Check status | velero backup describe <name> |
| View logs | velero backup logs <name> |
Best Practices
- Test restores regularly – don’t wait for disaster to find out your backup is broken
- Use TTL to automatically expire old backups and save storage costs
- Backup before upgrades – always take a snapshot before AKS version upgrades
- Store credentials securely – use Azure Key Vault instead of plain credentials files
- Use hooks for databases to ensure data consistency
- Cross-region storage – store backups in a different Azure region for disaster recovery
- Combine with GitOps – use Velero for stateful data + Git for manifests