Skip to main content
RunBook Academy

KubernetesXCVII · Kubernetes Backup ToolsKubernetes backup tools

Velero Restic vs Kopia vs native CSI snapshots — the consistency trade-off

Advanced⏱ ~17 minvelerokubectl

What you'll learn

  • Distinguish Restic, Kopia, and CSI snapshot backends
  • Choose the right backend for each workload
  • Apply Velero annotations to override the default per-Pod
  • Identify the operational failure modes of each backend

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.

Velero supports three volume backup strategies, and the choice between them is one of the most consequential operational decisions in a backup program. This lesson walks the trade-offs — crash-consistent vs application-consistent, performance, deduplication, restore granularity — and the per-Pod annotation mechanism that lets operators mix strategies within a single Velero backup.

The three backends

flowchart LR
    A[Pod volume] --> B{Backend}
    B -->|CSI snapshot| C["Crash-consistent, fast, driver-dependent"]
    B -->|Restic| D["File-level, application-consistent, deprecated"]
    B -->|Kopia| E["File-level, dedup, encryption, recommended"]
    C --> F[CSI driver]
    D --> G[Object storage]
    E --> G

The three backends:

  • CSI native snapshot — Velero calls the CSI driver’s CreateSnapshot RPC via the external-snapshotter sidecar. The snapshot is crash-consistent (whatever was in flight at snapshot time). For databases, you must pair with PRE/POST hooks (covered in the previous part) to quiesce the application.
  • Restic — Velero deploys a DaemonSet (Restic daemon) that walks the Pod’s filesystem and pushes files to Restic’s repository in object storage. File-level; can be application-consistent with PRE hooks that freeze the database. Deprecated in newer Velero; replaced by Kopia.
  • Kopia — Velero deploys a node-agent DaemonSet that uses Kopia’s snapshot algorithm (similar to Restic but with content-addressable deduplication and client-side encryption). File-level; application-consistent with hooks. The recommended file-level backend in Velero 1.10+.

The trade-offs

PropertyCSI snapshotResticKopia
Consistencycrash-consistentapp-consistent with hooksapp-consistent with hooks
Speedfast (seconds to minutes)slow (proportional to file count)faster than Restic (dedup)
Restore granularityfull PVC onlyfile-levelfile-level
Compressiondriver-dependentyes (Restic)yes (Kopia)
Encryptiondepends on driverclient-side (Restic)client-side (Kopia)
Deduplicationnonenonecontent-addressable
Driver dependencyrequires CSI driver with snapshot supportnonenone
Statusstabledeprecatedstable

Choosing the right backend per workload

The right backend depends on the workload:

flowchart TD
    A[Workload] --> B{Database?}
    B -->|Yes| C{Driver supports snapshot?}
    C -->|Yes| D["CSI snapshot + PRE/POST hooks"]
    C -->|No| E["Kopia + PRE/POST hooks"]
    B -->|No| F{Application-consistent needed?}
    F -->|Yes| G[Kopia with hooks]
    F -->|No| H[CSI snapshot]
  • Transactional database on a CSI driver with snapshot support. CSI snapshot + Velero PRE/POST hooks. The snapshot is crash-consistent at the storage layer but the application is quiesced at the application layer. The combination is the most efficient and consistent option.
  • Transactional database on a driver without snapshot support. Kopia with PRE/POST hooks. Slower than CSI snapshot but achieves application-consistent state through the file-level copy.
  • Application with custom quiesce. Kopia with hooks. The application freezes itself during the copy.
  • Stateless workload. CSI snapshot. No need for hooks because there is no in-Pod state to quiesce.
  • Fileserver or large static data. CSI snapshot, fast. Application consistency is irrelevant for static data.
  • Workload that does not tolerate long quiesce. CSI snapshot. Restic/Kopia’s file copy can take long enough that the quiesce window blocks writes.

Per-Pod annotations

Velero lets operators override the default per-Pod with annotations:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  annotations:
    # Force Kopia for this Pod's volumes
    velero.io/backup-volumes: data
    # Skip the default volume for this Pod
    velero.io/exclude-from-backup: "true"
spec:
  template:
    metadata:
      annotations:
        # Run a PRE hook before the backup
        pre.hook.backup.velero.io/container: db
        pre.hook.backup.velero.io/command: '["/scripts/quiesce.sh", "freeze"]'
        # Run a POST hook after the backup
        post.hook.backup.velero.io/container: db
        post.hook.backup.velero.io/command: '["/scripts/quiesce.sh", "thaw"]'

The annotation overrides the install-wide default. Mixing strategies within a single backup is the norm: databases with hooks, stateless workloads with CSI snapshots, log-shippers excluded entirely.

Restore granularity

CSI snapshots restore full PVCs. Restic and Kopia restore file-level:

# Substitute your own values before running. KOPIA_POD is the velero
# node-agent pod on the node holding the repository cache; SNAPSHOT_ID comes
# from `kopia snapshot list`:
KOPIA_POD=node-agent-2xk9p
SNAPSHOT_ID=k0f5b1c3a9e2d7460b8c1d4e7f0a2b5c8

# Restic
velero restore create --from-backup daily \
  --include-resources persistentvolumeclaims \
  --selector velero.io/restic-volume=postgres-data

# Kopia file-level restore
kubectl exec -n velero "$KOPIA_POD" -- \
  kopia snapshot restore "$SNAPSHOT_ID" --target /restore/path

File-level restore is invaluable when the operator needs one file from a large volume — for example, a single config file from a 1Ti database backup. CSI snapshots force a full PVC restore.

The operational failure modes

Each backend fails in characteristic ways:

  • CSI snapshot. Driver does not support snapshots (returns Unavailable); class name typo (snapshot sits in Provisioning); cloud-side quota exceeded (snapshot fails silently).
  • Restic. DaemonSet not running on a node (Pods on that node are silently skipped); repository password rotated and not updated in Velero’s Secret; large file counts cause long backup windows.
  • Kopia. Repository password rotated (same as Restic); node-agent OOMs on very large volumes (increase memory limits); client-side encryption key lost (backups become unreadable).

Quiz

Knowledge check · 4 questions

  1. Q1. What is the recommended volume backup backend in Velero 1.10+ for a Postgres StatefulSet on a StorageClass that does not support CSI snapshots?

  2. Q2. Restic is deprecated in newer Velero; new installs should use Kopia.

  3. Q3. A backup of a StatefulSet is configured with the Velero default (CSI snapshot) but the StorageClass does not support snapshots. The backup is `PartiallyFailed` — manifests are saved but PVCs are not. Diagnosis and fix?

    The StatefulSet uses a StorageClass backed by an NFS CSI driver that does not implement CreateSnapshot. The backup completes for the manifests but reports zero persistent volume backups. The operator expected CSI snapshots; the result is that PVC data is not backed up.

  4. Q4. Name the three Velero volume backup backends and one advantage of each.

Passing score: 75%. Answers are checked in this browser.

Production discipline

Choosing the right Velero volume backup backend in production rests on five non-negotiable elements:

  • Match the backend to the workload. Databases with hooks; stateless workloads with CSI; large files with Kopia dedup. A single backend for every workload is rarely correct.
  • Validate the choice with a restore test. A backup that completes is not a backup until the restore works. Test the worst workload.
  • Document the per-workload choice. A runbook that lists which workload uses which backend, with the annotations applied, prevents the next operator from guessing.
  • Monitor the volume plugin’s health. The Kopia DaemonSet’s Pods are the diagnostic chain. Alert on their absence or OOMs.
  • Migrate off Restic. Restic is deprecated; new installs use Kopia. The migration should be planned and tested, not done under pressure.

The choice between backends is consequential. A workload backed up with the wrong backend is not backed up — it is just taking up space in the object store.