Skip to main content
RunBook Academy

KubernetesXCVI · Workload BackupWorkload backup

CSI volume snapshots — the API and lifecycle

Advanced⏱ ~17 minkubectlcsi-snapshotter

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

Not yet marked complete on this device.

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 a spec.source pointing to either a PVC or another VolumeSnapshot, and a spec.volumeSnapshotClassName.
  • VolumeSnapshotContent (snapshot.storage.k8s.io/v1) is the cluster-scoped materialised snapshot. It carries the CSI driver’s snapshotHandle (the cloud-side snapshot ID) and the status.snapshotHandle is set after the CSI driver returns success.
  • VolumeSnapshotClass (snapshot.storage.k8s.io/v1) is the policy — equivalent to StorageClass but for snapshots. It carries driver (which CSI driver to use) and parameters (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 CreateSnapshot RPC, but it has not returned.
  • Ready — the CSI driver returned success and status.snapshotHandle is 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:

  1. Delete the VolumeSnapshot — the external-snapshotter sidecar observes and calls the CSI driver’s DeleteSnapshot RPC. The VolumeSnapshotContent is also removed.
  2. 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. Check kubectl get csidrivers for the snapshot capabilities before relying on the API.
  • Class name mismatch. The volumeSnapshotClassName does not exist; the snapshot stays Provisioning forever. Verify with kubectl 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

  1. Q1. What is the relationship between VolumeSnapshot, VolumeSnapshotContent, and VolumeSnapshotClass?

  2. Q2. Deleting the VolumeSnapshotContent directly before deleting the VolumeSnapshot orphans the snapshot in the CSI backend.

  3. 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.

  4. 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 csidrivers and 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.