Skip to content

Volume Snapshots

A snapshot is a point-in-time copy of one volume's data, taken and restored entirely from inside your own cluster.

This is the mechanism for losing data you meant to keep — a migration that went wrong, a schema change that corrupted a database, a deletion you regret. It is not the mechanism for losing the cluster; see Cluster Backup & Restore for that, and below for the difference.

Everything on this page runs against your cluster's kubeconfig.

What you have

Your cluster ships with a VolumeSnapshotClass and the controller behind it, delivered by the platform:

$ kubectl get volumesnapshotclass
NAME                     DRIVER              DELETIONPOLICY   AGE
kubevirt-csi-snapclass   csi.kubevirt.io     Delete           47h

Snapshots are a supported feature of this platform rather than a maybe. The storage behind your cluster is required to support them — it is how your worker nodes are created in the first place, so a platform where snapshots do not work is one where clusters do not boot.

Take one

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: postgres-data-2026-08-20
spec:
  volumeSnapshotClassName: kubevirt-csi-snapclass
  source:
    persistentVolumeClaimName: postgres-data
$ kubectl apply -f snapshot.yaml
$ kubectl get volumesnapshot postgres-data-2026-08-20
NAME                       READYTOUSE   SOURCEPVC       RESTORESIZE   AGE
postgres-data-2026-08-20   true         postgres-data   20Gi          8s

Wait for READYTOUSE to be true before you rely on it. A snapshot that is not ready yet is not a copy of anything.

A snapshot is not automatically consistent

The snapshot is taken at the block level, while your application is still writing. For a filesystem that is usually survivable; for a database it can produce a copy that needs recovery on start, or one that will not start at all.

Quiesce the writer first for anything that keeps state in memory:

  • Use the application's own mechanism where it has one — pg_start_backup, FLUSH TABLES WITH READ LOCK, a fsfreeze.
  • Or scale the workload to zero, snapshot, and scale back up.

A snapshot of a stopped database is worth more than three snapshots of a running one.

Restore one

You do not restore into the existing volume. You create a new claim with the snapshot as its data source, and point your workload at that:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-data-restored
spec:
  dataSource:
    name: postgres-data-2026-08-20
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io
  accessModes: [ "ReadWriteOnce" ]
  storageClassName: kubevirt
  resources:
    requests:
      storage: 20Gi        # at least the snapshot's RESTORESIZE
kubectl apply -f restored-pvc.yaml
kubectl get pvc postgres-data-restored -w

Then repoint the workload — edit the Deployment's volume to the new claim, or for a StatefulSet, restore into the claim name its volumeClaimTemplates already generates.

Three things to get right:

Size resources.requests.storage must be at least the snapshot's RESTORESIZE. Smaller is rejected; larger provisions a bigger volume, which is legal and sometimes what you want.
The original is untouched Restoring creates a second volume. The one you snapshotted keeps its data and keeps consuming quota until you delete it — which is what lets you compare the two before committing.
Quota A restore is a new volume, so it needs headroom in your storage quota. A restore of a 20Gi snapshot needs 20Gi free, not zero.

That last one is the one that bites during an incident. Check before you need to:

kubectl get resourcequota -n dynamo-prod      # your Environment, not your cluster

What snapshots consume

Snapshots live on the platform's storage and count against your storage quota, the same as volumes do.

They are not free and they are not archives. A snapshot's deletion policy is Delete, so removing the VolumeSnapshot object removes the data behind it — and there is no retention mechanism, so a snapshot you took in March is still consuming budget today.

Prune them:

kubectl get volumesnapshot -A --sort-by=.metadata.creationTimestamp
kubectl delete volumesnapshot postgres-data-2026-03-01

A snapshot is not off-site, and does not survive the cluster

The snapshot sits on the same storage system as the volume it came from, inside the same platform. It protects you against a mistake. It does not protect you against losing the storage, the platform, or the cluster.

A snapshot also goes away with the cluster that owns it unless the volume behind it was set to Retain — see Volumes need Retain.

If the data matters beyond that, copy it somewhere else: a dump to object storage from inside a pod is unglamorous and is the thing that actually survives.

Which mechanism you actually need

The two are complementary, and neither substitutes for the other:

Losing Use Because
Data inside a volume VolumeSnapshot Restores the bytes, in place, in minutes. A ClusterBackup captures objects, not bytes.
The whole cluster ClusterBackup + Retain Rebuilds the API objects into a new cluster and re-binds the volumes. A snapshot cannot recreate a cluster to mount it.
The storage, or the platform Neither Copy the data out. Both mechanisms live on the platform you are trying to survive.

The realistic posture for something that matters: Retain on the volume, a ClusterBackup on a schedule, snapshots before anything risky, and a dump somewhere off-platform.


See Also: Cluster Backup & Restore · Persistent Storage