KubernetesXCVI · Workload BackupWorkload backup
CSI volume snapshots — the API and lifecycle
What you'll learn
- Use the CSI snapshot API (VolumeSnapshot, VolumeSnapshotContent, VolumeSnapshotClass)
- Trace the snapshot lifecycle from request to ready
- Restore a PVC from a snapshot
- Apply the deletion ordering to avoid orphan snapshots
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
The CSI snapshot API is a first-class Kubernetes
extension. Three objects cooperate: VolumeSnapshot
(the user request), VolumeSnapshotContent (the
materialised snapshot, cluster-scoped), and
VolumeSnapshotClass (the policy, equivalent to
StorageClass for snapshots). This lesson walks the
API, the lifecycle, restoration, and the operational
discipline.
The three snapshot objects
flowchart LR
A[VolumeSnapshot] --> B[VolumeSnapshotClass]
A --> C[Source PVC]
D[external-snapshotter] -->|creates| E[VolumeSnapshotContent]
E -->|references| F[CSI snapshot handle]
A -.->|binds to| E
- VolumeSnapshot (
snapshot.storage.k8s.io/v1) is the user-facing object. It is namespaced. It carries aspec.sourcepointing to either a PVC or another VolumeSnapshot, and aspec.volumeSnapshotClassName. - VolumeSnapshotContent (
snapshot.storage.k8s.io/v1) is the cluster-scoped materialised snapshot. It carries the CSI driver’ssnapshotHandle(the cloud-side snapshot ID) and thestatus.snapshotHandleis set after the CSI driver returns success. - VolumeSnapshotClass (
snapshot.storage.k8s.io/v1) is the policy — equivalent toStorageClassbut for snapshots. It carriesdriver(which CSI driver to use) andparameters(driver-specific knobs like retention or tier).
The snapshot lifecycle
stateDiagram-v2
[*] --> Provisioning: VolumeSnapshot created
Provisioning --> Pending: external-snapshotter bound
Pending --> Ready: CSI CreateSnapshot succeeded
Pending --> Error: CSI CreateSnapshot failed
Ready --> [*]: bound to restore PVC
Error --> [*]: status.error.message set
The states:
- Provisioning — the user submitted the VolumeSnapshot but no VolumeSnapshotContent has been bound yet.
- Pending — a VolumeSnapshotContent has been bound
and the external-snapshotter sidecar has called the
CSI driver’s
CreateSnapshotRPC, but it has not returned. - Ready — the CSI driver returned success and
status.snapshotHandleis populated. - Error — the CSI driver returned an error; the
message is in
status.error.message.
The duration of Pending is driver-dependent. EBS snapshots typically take seconds; some SAN snapshots take minutes; copy-on-write snapshots are instant.
Creating a snapshot
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: postgres-daily-2026-08-16
namespace: prod-data
spec:
volumeSnapshotClassName: csi-aws-vsc
source:
persistentVolumeClaimName: postgres-data
The snapshot controller watches VolumeSnapshot objects
and asks the CSI driver to create a snapshot of the
named PVC. The CSI driver returns a snapshot handle,
which becomes the VolumeSnapshotContent’s
snapshotHandle.
kubectl get volumesnapshot -n prod-data
NAME READYTOUSE SOURCEPVC SNAPSHOTCLASS AGE
postgres-daily-2026-08-16 true postgres-data csi-aws-vsc 2m
Restoring from a snapshot
Restoration is a new PVC whose dataSource points to
the VolumeSnapshot:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data-restored
namespace: prod-data
spec:
storageClassName: csi-aws-sc
dataSource:
name: postgres-daily-2026-08-16
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
The PVC, when bound, is provisioned as a new volume from the snapshot. The bytes of the new volume are a copy of the snapshot at the time of creation. Future writes to the new volume do not affect the snapshot; future changes to the snapshot do not affect the new volume. The two are independent after creation.
The deletion ordering
flowchart TD
A[VolumeSnapshot] --> B[VolumeSnapshotContent]
B --> C[CSI snapshot handle]
D[Restore PVC] --> B
E[Delete VolumeSnapshot] -->|calls CSI DeleteSnapshot| C
F[Delete VolumeSnapshotContent directly] -.->|orphan| C
The deletion order matters:
- Delete the VolumeSnapshot — the external-snapshotter
sidecar observes and calls the CSI driver’s
DeleteSnapshotRPC. The VolumeSnapshotContent is also removed. - If you delete the VolumeSnapshotContent first, the
external-snapshotter sidecar has nothing to watch
and does not call
DeleteSnapshot. The CSI snapshot handle becomes an orphan — still consuming storage in the backend but invisible to Kubernetes.
Always delete the VolumeSnapshot, never the VolumeSnapshotContent directly. The exception is unbinding a stuck VolumeSnapshotContent during a recovery, where orphan cleanup is part of the run.
The operational failure modes
CSI snapshots fail in production for predictable reasons:
- Driver does not support snapshots. Older CSI
drivers, some hostPath drivers, and some in-tree
drivers do not implement
CreateSnapshot. Checkkubectl get csidriversfor thesnapshotcapabilities before relying on the API. - Class name mismatch. The
volumeSnapshotClassNamedoes not exist; the snapshot stays Provisioning forever. Verify withkubectl get volumesnapshotclasses. - CSI timeout. The CSI driver takes longer than the default 30-second RPC timeout. The snapshot moves to Error with a timeout message; retrying often succeeds because the snapshot may have been created in the backend anyway.
- Quota exceeded. Some cloud providers cap snapshots per volume or per account. A snapshot that succeeds but the underlying cloud API rejects the request fails silently; check the cloud console.
- Deletion race. Deleting a VolumeSnapshot while a restore PVC is still bound to it removes the snapshot. The restore PVC continues to work but its source is gone.
Quiz
Knowledge check · 4 questions
Q1. What is the relationship between VolumeSnapshot, VolumeSnapshotContent, and VolumeSnapshotClass?
Q2. Deleting the VolumeSnapshotContent directly before deleting the VolumeSnapshot orphans the snapshot in the CSI backend.
Q3. An operator creates a VolumeSnapshot of a PVC. The snapshot is Provisioning for ten minutes. Diagnosis and recovery?
The PVC is bound to a CSI volume on a managed Kubernetes service. The VolumeSnapshot is in Provisioning. The CSI driver logs show no CreateSnapshot call. The VolumeSnapshotClass exists but its `driver` field is set to an older in-tree driver name, not the CSI driver.
Q4. Name the three lifecycle states of a VolumeSnapshot and what each means.
Passing score: 75%. Answers are checked in this browser.
Production discipline
CSI volume snapshots in production rest on five non-negotiable elements:
- Verify the CSI driver supports snapshots. Check
kubectl get csidriversand the driver’s documentation before relying on the API. Older and in-tree drivers often do not. - Validate the VolumeSnapshotClass. The class references a CSI driver that actually runs in the cluster. A class with a stale driver name sends requests to nowhere.
- Always delete VolumeSnapshot, never VolumeSnapshotContent. The sidecar only cleans up in response to VolumeSnapshot deletion.
- Monitor snapshot lifecycle. Alert on snapshots that sit in Provisioning or Pending beyond the expected duration.
- Test restore quarterly. A snapshot that the CSI driver reports as Ready may still fail on restore if the driver is misconfigured or the cloud-side snapshot is corrupted. The restore test is the proof.
CSI snapshots are a powerful primitive, but they depend on driver implementation, class configuration, and sidecar health. A backup program that relies on them without monitoring the lifecycle is operating on hope.