Amazon EKS — Volume Snapshots

2 minute read

EBS snapshots provide point-in-time backups of persistent volumes. The CSI snapshot controller and EBS CSI Driver work together to create, manage, and restore snapshots through native Kubernetes APIs.


Prerequisites

Install the Snapshot Controller

The CSI snapshot controller is not installed by default:

kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/rbac-snapshot-controller.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml

Verify:

kubectl get pods -n kube-system -l app=snapshot-controller
kubectl get crd | grep snapshot

VolumeSnapshotClass

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: ebs-snapshot-class
driver: ebs.csi.aws.com
deletionPolicy: Retain   # Keep EBS snapshot even if K8s VolumeSnapshot is deleted
Policy Behavior
Delete EBS snapshot is deleted when VolumeSnapshot is removed
Retain EBS snapshot persists — must be manually cleaned up

Creating a Snapshot

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: postgres-snapshot-2025-02-09
  namespace: production
spec:
  volumeSnapshotClassName: ebs-snapshot-class
  source:
    persistentVolumeClaimName: data-postgres-0
kubectl apply -f snapshot.yaml
kubectl get volumesnapshot -n production
kubectl describe volumesnapshot postgres-snapshot-2025-02-09 -n production

Restoring from a Snapshot

Create a new PVC from a snapshot:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-postgres-restored
  namespace: production
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: gp3
  resources:
    requests:
      storage: 50Gi
  dataSource:
    name: postgres-snapshot-2025-02-09
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io

Cross-AZ Restore

EBS snapshots are regional — you can restore a snapshot into any AZ in the same region:

  1. Create a snapshot from the source PVC
  2. Delete or stop the workload using the old PVC
  3. Create a new PVC from the snapshot (use WaitForFirstConsumer to bind to the correct AZ)

Backup Strategies

Scheduled Snapshots with CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: db-snapshot
  namespace: production
spec:
  schedule: "0 3 * * *"    # Daily at 3 AM
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: snapshot-sa
          containers:
            - name: snapshot
              image: bitnami/kubectl:latest
              command:
                - /bin/sh
                - -c
                - |
                  DATE=$(date +%Y-%m-%d)
                  cat <<SNAP | kubectl apply -f -
                  apiVersion: snapshot.storage.k8s.io/v1
                  kind: VolumeSnapshot
                  metadata:
                    name: postgres-snap-$DATE
                    namespace: production
                  spec:
                    volumeSnapshotClassName: ebs-snapshot-class
                    source:
                      persistentVolumeClaimName: data-postgres-0
                  SNAP
          restartPolicy: OnFailure

Velero for Full Cluster Backup

Velero backs up Kubernetes resources AND persistent volumes:

# Install Velero with AWS plugin
velero install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.9.0 \
  --bucket my-velero-backup-bucket \
  --backup-location-config region=us-east-1 \
  --snapshot-location-config region=us-east-1 \
  --use-node-agent

# Create a backup
velero backup create daily-backup --include-namespaces production

# Schedule daily backups
velero schedule create daily --schedule="0 3 * * *" --include-namespaces production

# Restore
velero restore create --from-backup daily-backup

Best Practices

  1. Use Retain deletion policy for production snapshot classes
  2. Automate snapshots — CronJobs or Velero schedules
  3. Test restores regularly — a backup that hasn’t been tested is not a backup
  4. Set retention policies — clean up old snapshots to control costs
  5. Use Velero for disaster recovery — backs up both K8s resources and volumes together
  6. Tag snapshots — include application, date, and environment for easy identification

Updated: