Velero
Open-source backup, restore and migration for Kubernetes. A controller in the cluster turns Backup and Schedule objects into a tarball of Kubernetes objects in an S3-compatible bucket, and its node-agent copies pod volume data with Kopia into the same bucket. Apache 2.0 and free; the only costs are object storage and the CPU of the data movers. It fits any cluster that needs namespace-level restores, disaster recovery to a new cluster, or migration between clusters.
Velero backs up the objects in a Kubernetes cluster and the data in its persistent volumes, and restores both into the same cluster or a different one. It covers the gap that etcd snapshots leave: a restore of one namespace, a rebuild of a lost cluster from a bucket, or a move of workloads to new hardware. The official docs at velero.io/docs own the full API reference.
What it is
A Kubernetes controller (the Velero server, one Deployment in the velero namespace), an optional DaemonSet (the node-agent) for volume data, a set of CRDs in the velero.io API group, and a velero CLI. Storage providers come as plugins: AWS (any S3-compatible store), Azure and GCP are maintained by the project. Licence is Apache 2.0.
The current line is v1.18 (v1.18.4 shipped 2026-09-28). v1.18 added concurrent backup processing, cache volumes for data-mover pods on restore, glob wildcards in namespace filters, and a volume-policy condition on PVC phase. It runs on Kopia 0.22. The repository now lives under the velero-io GitHub organization; links to the old vmware-tanzu repo redirect, and the Helm chart is still published from vmware-tanzu/helm-charts.
The most recent breaking change came in v1.17: the Restic uploader is gone for new backups. --uploader-type=restic is no longer a valid install option, and Kopia is the only file-system backup path. Backups taken with Restic can still be restored until v1.19.
How it works
Every action is a custom resource. A Schedule creates Backup objects on a cron. A Backup names what to include (namespaces, resource types, label selectors) and how to handle volumes. A BackupStorageLocation (BSL) points at a bucket and prefix. A Restore names a backup to read from. The server watches these objects; the CLI only creates and reads them.
Volume data takes one of three routes. Volume snapshots call the storage provider's snapshot API. CSI snapshot data movement takes a CSI snapshot and copies it to the bucket. File-system backup (FSB) has the node-agent read the files of a mounted volume straight from the node and write them with Kopia into a backup repository in the bucket, one repository per namespace. FSB works on any volume type except hostPath, which is why it is the default choice on clusters with local-path storage and no snapshot support.
Step 1 of 6. At the cron time the schedule controller creates a Backup object from its template, with the TTL that decides when it expires.
File-system backup path. Snapshot-based backups replace the node-agent hops with calls to the storage provider.
Two background loops matter for operations. The garbage collector runs hourly and deletes expired backups: the Backup object, its files in the bucket, its snapshots and its Restore objects. The default TTL is 30 days. The bucket sync treats object storage as the source of truth: a valid backup in the bucket with no matching object in the cluster is re-created. That second loop is what makes disaster recovery work. Install Velero on an empty cluster, point it at the same bucket, and the old backups appear.
Backups are not atomic. Objects created or changed during a backup can be missed, and FSB reads a live filesystem, so files in one volume are not captured at the same instant.
When to use it
Reach for it when:
- A namespace, or a whole cluster, must come back after a bad deploy, a deleted resource or a lost node.
- Workloads have to move to a new cluster, a new distro or new hardware.
- Volumes live on local-path or other storage with no snapshot API, and file-level copies are acceptable.
- One tool should cover several clusters, each writing to its own prefix in a shared bucket.
Skip it when:
- The data is a database with its own backup tooling. Write-ahead-log archiving restores to a point in time; a file copy of a running data directory does not.
- The cluster is stateless and fully described in Git. Re-syncing from Git is the restore.
- Only etcd is at stake on a single-node control plane. The distro's own etcd snapshot covers that case.
At a glance
Core concepts
- Backup — one run. Holds the include/exclude filters, TTL, volume handling and storage location.
- Schedule — a cron expression plus a Backup template. Supports
CRON_TZ=<IANA zone>prefixes. - BackupStorageLocation — bucket, prefix, provider config and credentials.
ReadOnlymode is for restores during a migration. - Restore — reads one backup; supports namespace mapping, resource filters and an existing-resource policy.
- Resource policy — a ConfigMap with
volumePoliciesthat map conditions (storage class, CSI driver, volume type, PVC labels, PVC phase) to an action:skip,snapshotorfs-backup. The first match wins. - BackupRepository — the Kopia repository for one namespace. Needs periodic maintenance to free space.
Key facts (v1.18)
| Item | Value |
|---|---|
| Licence | Apache 2.0 |
| Latest release | v1.18.4 (2026-09-28) |
| Uploader | Kopia 0.22 (Restic removed for new backups in v1.17) |
| AWS plugin for v1.18 | v1.14.x |
| Default backup TTL | 30 days |
| GC interval | 1 hour |
| FSB timeout | 4 hours (--fs-backup-timeout) |
| Unsupported volume | hostPath |
| Metrics | Prometheus, velero_ prefix |
Scope compared
| Aspect | Velero | Rancher Backups | Database-native backup |
|---|---|---|---|
| Covers | Any objects and volumes | Rancher's own CRDs and secrets | One database |
| Volume data | Kopia file copy or snapshots | None | WAL and base backups |
| Point-in-time restore | No | No | Yes |
| Restore into new cluster | Yes, from the bucket | Yes, to migrate Rancher | Yes, new instance |
How to integrate
Helm values for an S3-compatible store
helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
helm install velero vmware-tanzu/velero -n velero --create-namespace -f values.yaml
initContainers:
- name: velero-plugin-for-aws
image: velero/velero-plugin-for-aws:v1.14.4 # match the Velero minor (1.18 -> 1.14.x)
volumeMounts:
- mountPath: /target
name: plugins
configuration:
backupStorageLocation:
- name: default
provider: aws
bucket: velero
prefix: cluster-a # one prefix per cluster in a shared bucket
default: true
config:
region: us-east-1 # required by the plugin, ignored by most S3-compatible stores
s3ForcePathStyle: "true"
s3Url: http://s3.example.svc:8333
volumeSnapshotLocation: []
uploaderType: kopia
defaultVolumesToFsBackup: true
snapshotsEnabled: false
deployNodeAgent: true
credentials:
existingSecret: velero-s3 # key "cloud" holds an AWS-style credentials file
A volume policy
version: v1
volumePolicies:
- conditions:
volumeTypes: [emptyDir]
action:
type: skip
- conditions:
pvcLabels:
backup: skip
action:
type: skip
kubectl -n velero create configmap volume-policy --from-file=policy.yaml
A nightly schedule
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: nightly
namespace: velero
spec:
schedule: "CRON_TZ=America/New_York 0 3 * * *"
template:
ttl: 336h # 14 days
includedNamespaces: ["*"]
excludedNamespaces: [velero]
defaultVolumesToFsBackup: true
resourcePolicy:
kind: configmap
name: volume-policy
Check and restore
velero backup get
velero backup describe nightly-20261017030000 --details
velero restore create --from-backup nightly-20261017030000 \
--include-namespaces app --namespace-mappings app:app-restored
velero restore describe <restore-name>
A restore into a scratch namespace with --namespace-mappings is the cheapest way to prove a backup works without touching the live copy.
In the GL stack
Velero v1.18.4 runs on all three clusters, with the AWS plugin and Kopia file-system backup. Each cluster has one schedule, velero-nightly, that fires at 02:00 Chicago time and keeps backups for 14 days. It covers every namespace except the one that holds the backup store itself, since a copy of the bucket written into the same bucket protects nothing.
A volume policy decides what is worth copying. It skips the CloudNativePG volumes (a file copy of a running Postgres is not a consistent backup), Prometheus data, caches and emptyDirs. What is left is the state that cannot be rebuilt from Git or re-scraped.
Backups go to an S3 bucket named velero on SeaweedFS, with one prefix per cluster, so any cluster can be rebuilt by pointing a fresh Velero at its prefix. Two alerts watch the result: VeleroBackupFailed for a failed run and VeleroBackupTooOld for a schedule that has stopped producing backups.
Gotchas
- Spring-forward skips the 02:00 run. The docs warn that jobs scheduled inside a daylight-saving leap-ahead do not run. In US zones the clocks jump from 02:00 to 03:00, so a 02:00 local schedule misses one night a year. An age alert catches it; a 03:00 slot avoids it.
- One shared encryption key. Velero uses a static, common key for every Kopia repository it creates, stored in the
velero-repo-credentialssecret. Change it before the first backup; changing it later makes older backups unreadable. Anyone with bucket access can decrypt the data, so lock down the bucket. - Deleted backups do not free space at once. Kopia space is reclaimed only after full repository maintenance jobs succeed. Watch that maintenance runs.
- Plugin and server versions are paired. AWS plugin v1.14.x goes with Velero v1.18.x. Upgrade both together.
- S3-compatible quirks. Since plugin v1.13 (AWS SDK v2), some stores (Ceph, Backblaze B2) need
checksumAlgorithm: ""in the BSL config to avoid checksum errors. Non-AWS stores also needs3ForcePathStyleands3Url. - Restores do not overwrite. Existing objects are skipped unless
--existing-resource-policy=updateis set, and even then PV data is not overwritten. Delete the namespace, or map to a new one, for a clean restore. - API versions must exist on the target. Each object is stored at the source cluster's preferred version. A restore fails for any resource whose group and version the target cluster does not serve.
- Restic leftovers. Clusters upgraded from older versions with
--uploader-type=resticmust switch to Kopia; old Restic backups stay restorable only until v1.19.
Risks
- Licence and stewardship. Apache 2.0 with no paid tier in the core project. The project moved from the
vmware-tanzuorganization tovelero-io; the code stays open and forkable, but release timing and plugin support depend on a small maintainer group. - Silent coverage gaps. A backup that completes is not a backup that restores. Excluded volumes, missed
hostPathdata and non-atomic captures only show up on a restore test. - Bucket is the single point of truth. Losing or corrupting the bucket loses every backup, and the bucket sync will then delete Completed backups from the cluster to match. Keep a copy of the store off the cluster it protects.
- Security. The node-agent mounts every pod's volumes from the host, and the BSL secret can read all backed-up data. Both deserve the same care as cluster-admin credentials.
Alternatives
- Kasten K10 (Veeam) — pick it for a commercial product with a policy UI and vendor support.
- KubeStash (AppsCode) — pick it for per-application backup CRDs and database add-ons; check its licence terms first.
- Database-native backup (CloudNativePG, pgBackRest) — pick it for Postgres; WAL archiving gives point-in-time recovery that a volume copy cannot.
- Rancher Backups — pick it only to protect or migrate a Rancher install; it does not touch workloads or volumes.
Related
- SeaweedFS — the S3 store the backups land in.
- CloudNativePG and Postgres — the databases the volume policy leaves to their own tooling.
- Rancher Backups — the narrower operator for Rancher's own state.
- Prometheus and Alertmanager — where the backup metrics and alerts live.
- K3s — the lightweight Kubernetes distro, where local-path volumes make file-system backup the natural choice.
- Official: Velero v1.18 docs, File System Backup, Releases, AWS plugin.
