KubernetesXCVII · Kubernetes Backup ToolsKubernetes backup tools
Velero Restic vs Kopia vs native CSI snapshots — the consistency trade-off
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
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
CreateSnapshotRPC 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
| Property | CSI snapshot | Restic | Kopia |
|---|---|---|---|
| Consistency | crash-consistent | app-consistent with hooks | app-consistent with hooks |
| Speed | fast (seconds to minutes) | slow (proportional to file count) | faster than Restic (dedup) |
| Restore granularity | full PVC only | file-level | file-level |
| Compression | driver-dependent | yes (Restic) | yes (Kopia) |
| Encryption | depends on driver | client-side (Restic) | client-side (Kopia) |
| Deduplication | none | none | content-addressable |
| Driver dependency | requires CSI driver with snapshot support | none | none |
| Status | stable | deprecated | stable |
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
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?
Q2. Restic is deprecated in newer Velero; new installs should use Kopia.
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.
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.