Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild

Kubernetes Backup: An etcd Snapshot Is Not a Backup of Your App

Sean

Platform Writer

Jul 14, 2026
8 min read

The most common Kubernetes backup mistake is believing you have one. A team snapshots etcd, ticks the box, and discovers during an actual incident that they have backed up the cluster’s intentions - the YAML - and none of the data. Your persistent volumes are not in etcd. Your database is not in etcd. What is in etcd is a description of the pods that were supposed to be running, which is the part you could have regenerated from Git anyway. A real Kubernetes backup strategy has three separate layers, and most teams have only the least useful one.

Kubernetes Backup: An etcd Snapshot Is Not a Backup of Your App

Table of contents

The three things that need backing up

Split the problem before you pick a tool.

1. Cluster state - the YAML. Deployments, Services, ConfigMaps, Secrets, Ingresses. This is what etcd holds. Here is the thing: if you practise GitOps, this is already backed up, in Git, with history and code review. An etcd snapshot is a worse copy of something you have.

2. Persistent volume data. The contents of every PVC - your database files, uploaded objects, anything on disk. This is not in etcd. Etcd knows a PVC exists and which volume it binds to. It knows nothing about the bytes inside. Losing this is losing your data.

3. External state. Your managed database, your object storage, your DNS. Not in the cluster at all, and not covered by any Kubernetes backup tool. It needs its own backup regime.

The hierarchy of value is the inverse of the hierarchy of attention. Layer 1 gets all the tooling discussion and is the easiest to recreate. Layer 2 is where the irreplaceable data lives. Layer 3 is where the actual irreplaceable data usually lives, and it is frequently not thought of as a Kubernetes problem at all - right up until the incident.

Why the etcd snapshot is not the answer

You will find a lot of instructions for this:

ETCDCTL_API=3 etcdctl snapshot save snapshot.db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

This is a legitimate thing to do if you run your own control plane, and it will save you when you have destroyed the control plane but the storage is intact.

It will not save you when:

  • A PVC was deleted and its underlying volume reclaimed. Etcd will happily tell you the PVC existed. The data is gone.
  • You need to restore a single namespace. Etcd restore is all-or-nothing at the cluster level.
  • You want to move workloads to a different cluster. The snapshot is tied to this cluster’s identity.
  • You are on a managed service - EKS, GKE, AKS, DOKS - where you have no access to etcd at all. Which is most people.

Etcd snapshots protect the control plane. Almost nobody’s disaster scenario is “the control plane’s data is corrupt but every persistent volume is fine.” The realistic scenarios are somebody deleted the wrong namespace, a bad migration corrupted the database, or an entire region went away.

Velero: back up the objects and the volumes together

Velero is the standard answer, and the reason it is the standard answer is that it handles both the API objects and the volume data in one operation.

velero install \
  --provider aws \
  --bucket my-cluster-backups \
  --secret-file ./credentials \
  --use-node-agent

A namespace backup, with volumes:

velero backup create prod-20260714 \
  --include-namespaces production \
  --default-volumes-to-fs-backup

On a schedule:

velero schedule create daily-prod \
  --schedule="0 2 * * *" \
  --include-namespaces production \
  --ttl 720h

And the restore, which is the only part anybody actually cares about:

velero restore create --from-backup prod-20260714

Velero has two mechanisms for volumes, and the difference matters. CSI snapshots ask the storage layer for a snapshot - fast, efficient, but tied to that storage provider, so it does not help you migrate between clouds. File-system backup (the --default-volumes-to-fs-backup flag) copies the files into object storage - slower and heavier, but portable. Use snapshots for speed within a cloud, file-system backup when you need to restore somewhere else.

Your database still needs its own backup

This is the part that gets skipped, and it is the part that ends companies.

A volume snapshot of a running database is a crash-consistent copy. It is the equivalent of pulling the power cord: whatever was in flight is in an indeterminate state. Postgres and MySQL are generally robust enough to recover from this - they will replay their write-ahead log on startup - but “generally robust enough” is a phrase you do not want between you and your customers’ data.

What you actually want is a logical backup, taken by the database itself, which is internally consistent by construction:

pg_dump -Fc -d appdb > appdb-20260714.dump

Run it as a CronJob, ship the output to object storage, and keep it out of the cluster.

The stronger argument: a volume snapshot gives you point-in-time recovery only to the moments you snapshotted. A database with continuous WAL archiving gives you recovery to any second. When a bad migration corrupts a table at 14:32, “restore to 14:31” is what you need, and no volume-snapshot regime will give you that.

And the honest conclusion most teams eventually reach: this is a strong reason to run the database as a managed service outside the cluster, where continuous backup and point-in-time recovery are somebody else’s problem and are already correct.

Test the restore, or you do not have a backup

The uncomfortable truth of this entire discipline: an untested backup is a hypothesis, not a backup.

The failures are mundane and they are only ever discovered during a real incident:

  • The backup has been silently failing for six weeks because the object-storage credential expired, and nobody was alerting on backup success.
  • The restore works but takes eleven hours, and your stated RTO is two.
  • The backup captured the namespace but not the CRDs the operator needs, so the restore produces a namespace full of objects nothing knows how to reconcile.
  • The Secrets restored, but they reference an external secrets operator that is not installed on the new cluster.
  • The PVCs restored, but the new cluster has a different StorageClass name and every claim is stuck in Pending.

Schedule a quarterly restore drill: take a real backup, restore it into a fresh namespace or a scratch cluster, and time it. The first time you do this, something will be broken. That is the entire point of doing it on a Tuesday afternoon rather than at 3am during an outage.

Also alert on backup success, not just on failure. A cron job that stops running produces no failures at all, and silence is the most dangerous possible signal.

The strategy that actually works

Put together, the shape most teams should land on:

Cluster state: GitOps. Every manifest in Git, applied by Argo CD or Flux. The cluster is rebuildable from the repository, which makes the etcd snapshot largely redundant.

Volume data: Velero on a daily schedule, to object storage in a different region or account from the cluster. A backup that lives in the same blast radius as the thing it protects is decoration.

Databases: Native logical backups (pg_dump, mysqldump) plus continuous WAL archiving, run by the database and shipped off-cluster. Or, better, a managed database where this is already handled.

Secrets: In a real secret store - Vault, or a cloud secrets manager - not in etcd, and therefore not dependent on the cluster backup at all.

Verification: A quarterly restore drill with a stopwatch.

Notice how little of this is Kubernetes-specific. The hard part of backup was never the cluster - it was always the data, and the data does not care what orchestrator is in front of it.

How this fits the rest of the stack

Whatever you decide here, the cost of the decision only shows up as a bill. The RunxBuild hosting calculator is the right place to model that before committing: the compute, the database, the storage, the bandwidth, the worker - each one is a separate line item, and the real cost of a platform is the sum, not the headline number. The RunxBuild dashboard is where the team sees the actual usage once it is running.

Useful related references:

FAQ

Is an etcd snapshot enough to back up Kubernetes?

No. Etcd holds the API objects - your Deployments, Services and ConfigMaps - but not the contents of persistent volumes. It knows a PVC exists; it knows nothing about the bytes inside it. If you practise GitOps, the manifests are already in Git, which makes the etcd snapshot the least valuable layer of the three.

What does Velero actually back up?

Both the Kubernetes API objects and, if configured, the persistent volume data. CSI snapshots are fast but tied to the storage provider; file-system backup copies files into object storage and is portable across clouds. Without the volume flag you get objects only, which is a common and expensive misconfiguration.

Can I back up a database with a volume snapshot?

You can, but it is crash-consistent - equivalent to pulling the power cord. Postgres and MySQL usually recover by replaying the write-ahead log, but you also lose point-in-time recovery: you can only restore to the moments you snapshotted, not to the second before a bad migration. Use native logical backups plus WAL archiving instead.

Where should Kubernetes backups be stored?

In object storage in a different region or account from the cluster. A backup sitting in the same blast radius as the thing it protects will be lost by the same event. Cross-account is preferable, because it also protects against a compromised cluster credential deleting the backups.

How often should I test a Kubernetes restore?

Quarterly, with a stopwatch. Untested backups fail for mundane reasons - expired credentials, missing CRDs, a renamed StorageClass leaving every PVC in Pending. You want to find those on a Tuesday afternoon, not during an outage. Alert on backup success too, since a cron job that silently stops running generates no failure alerts at all.

#kubernetes#backup#velero#disaster-recovery#dev-infra