Velero, the Kubernetes backup and restore tool, is surprisingly effective at capturing the state of your cluster, not just the configuration.

Let’s see Velero in action. Imagine we have a simple application deployed:

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nginx-service
  namespace: default
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: LoadBalancer

We apply these:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

Now, let’s back up this namespace using Velero. First, ensure Velero is installed and configured with a storage location. Assuming you have a backup location named my-s3-location, you’d run:

velero backup create my-nginx-backup --include-namespaces default

This command initiates a backup named my-nginx-backup that specifically includes resources from the default namespace. Velero will:

  1. Query the Kubernetes API Server: It retrieves all objects within the specified namespace(s).
  2. Serialize Objects: These objects (Deployments, Services, Pods, ConfigMaps, Secrets, etc.) are converted into a JSON format.
  3. Store Configuration: The serialized object definitions are sent to your configured object storage (e.g., S3, GCS, Azure Blob Storage).
  4. Store Persistent Volume Snapshots (if configured): If you’ve integrated Velero with your cloud provider’s snapshot capabilities, it will also trigger snapshots of any Persistent Volumes associated with the backed-up resources.

After the backup completes, you can verify its status:

velero backup get my-nginx-backup

The output will show Status: Completed.

Now, let’s simulate a disaster. We’ll delete the default namespace:

kubectl delete namespace default

And to be thorough, we’ll wait a moment for all resources to be cleaned up.

To restore, we target the backup we created:

velero restore create --from-backup my-nginx-backup

Velero will:

  1. Fetch Backup Data: It retrieves the serialized object definitions from your object storage.
  2. Recreate Resources: It uses the Kubernetes API to create new versions of all the backed-up objects. For example, it will create the default namespace again, then the Deployment, and then the Service.
  3. Initiate Volume Restores: If PV snapshots were taken, it will create new Persistent Volumes from those snapshots and attach them to the restored Pods.

After the restore completes:

velero restore get

You’ll see Status: Completed. If you check your cluster:

kubectl get namespace default
kubectl get deployment my-nginx -n default
kubectl get service my-nginx-service -n default

You’ll find your default namespace, the my-nginx deployment, and the my-nginx-service are all back, in the exact state they were when the backup was taken. This includes the nginx:latest image and the Service type LoadBalancer.

The core problem Velero solves is state management for distributed systems. In Kubernetes, "state" encompasses not just the desired configuration of your applications (Deployments, Services) but also the actual data residing in Persistent Volumes. A simple kubectl apply -f only sets the desired state; it doesn’t capture the actual data or provide a disaster recovery mechanism for the control plane’s understanding of your cluster. Velero bridges this gap by providing atomic backups of both configuration and data, allowing for full cluster or namespace recovery.

The levers you control are primarily through Velero’s configuration and the backup/restore commands. You define what to back up (namespaces, resource types, labels, annotations), where to store it (backup storage locations), and how to snapshot volumes (volume snapshot locations). The commands then execute these policies.

What most people don’t realize is that Velero’s restore process is inherently idempotent. If you accidentally run a restore command twice for the same backup, Velero is smart enough to handle it gracefully. It checks if resources already exist and, based on its logic, either skips them, updates them, or applies specific conflict resolution strategies. This prevents accidental duplication or corruption during repeated restore attempts.

The next logical step is to explore how Velero handles resource filtering and exclusion for more granular backups.

Want structured learning?

Take the full Kubernetes course →