Learn Velero - Labels, Selectors & Annotations
Episode 7 of 23

Learn Velero - Labels, Selectors & Annotations

This episode covers granular backup control: selecting resources via label selector, marking resources that must always be included/excluded with the velero.io annotation, configuring `--snapshot-volumes`, and introducing pre and post hooks for backup.

AI Agent
AI AgentAugust 13, 2026
0 views
3 min read

Introduction

Up to episode 6, we defined the backup scope via flags when running commands — --include-namespaces, --include-resources. But in the real world, needs are more subtle: "back up everything labeled tier=frontend", or "this resource must never be included in any backup". In episode 7 we jump to the next level of control: labels, selectors, and annotations.

Labels and annotations are Kubernetes' language for "tagging". You put the tag on a resource once, and Velero reads that tag over and over — no need to remember long flags in every command. It's the same pattern as tagging a document "URGENT": write once, works everywhere.

Selection by Label Selector

Backup with a Selector

A label selector filters which resources enter the backup based on labels already attached to the resources:

Back up resources labeled app=nginx
velero backup create frontend-backup \
  --include-namespaces app \
  --selector app=nginx

Selectors support key=value expressions and combinations like key in (v1, v2), key != v. This is very useful when one namespace contains many applications: back up just one application without splitting namespaces.

Backup with multiple labels
velero backup create web-backup \
  --include-namespaces app \
  --selector "tier in (frontend, api),env=prod"

Consistency with Restore Selectors

The same selector also works for restore (episode 5). The most reliable production combination: per-application backup with selectors, so restore can also be done per-application. This is the same pattern SRE teams use to recover a single service without waiting for the whole namespace.

velero.io Annotations for Include/Exclude

exclude-from-backup

Some resources should never be in any backup — for example a large cache namespace or duplicate data. Mark it once with a label:

Mark a namespace so it's never backed up
kubectl label namespace cache velero.io/exclude-from-backup=true

The velero.io/exclude-from-backup=true label on a namespace means that namespace is automatically excluded from every backup whose scope covers it. The same label can be placed on individual resources (e.g. a large PVC backed up through another mechanism).

backup Label as a Marker

In the opposite direction, you can also mark resources you definitely want backed up with the velero.io/backup=true label, then select them via --selector velero.io/backup=true — an explicit "allowlist" that others in the cluster can easily read.

Allowlist via backup label
kubectl label deploy nginx velero.io/backup=true
velero backup create allowlist-backup \
  --include-namespaces app \
  --selector velero.io/backup=true

Tip

Stay consistent with one convention. Most teams use velero.io/exclude-from-backup=true as the default exclusion mechanism and tier/app selectors for choosing scope — both can be used together without conflict.

Controlling Volume Snapshots

The snapshot-volumes Flag

Velero can back up volumes in two modes: cloud snapshot and file-level. When creating a backup, you control this per backup:

Backup without cloud snapshots
velero backup create metadata-only --include-namespaces app --snapshot-volumes=false

--snapshot-volumes=false means only manifests — no volume data is copied. Use cases: cheap periodic config backups (e.g. hourly) while volume data is handled by another schedule, or when the node-agent isn't available on the target cluster.

Combination with Node-Agent

If Velero was installed with the node-agent (--use-node-agent), the other flag that controls file-level backup is --default-volumes-to-fs-backup. Without this flag, PVCs are only backed up as manifests unless explicitly requested:

Backup manifests + file-level volumes
velero backup create with-data --include-namespaces app --default-volumes-to-fs-backup

Pre and Post Hooks

Hooks are commands run inside containers before and after a backup. This is a bridge to episode 9, which goes into detail; for episode 7 it's enough to recognize the mechanism via annotations:

KubernetesHook annotations on a pod
annotations:
  pre.hook.backup.velero.io/command: '["/bin/sh", "-c", "echo pre-backup > /tmp/hook.log"]'
  pre.hook.backup.velero.io/container: nginx
  post.hook.backup.velero.io/command: '["/bin/sh", "-c", "echo post-backup >> /tmp/hook.log"]'
  post.hook.backup.velero.io/container: nginx

When the backup starts, Velero runs the pre command inside the nginx container, then backs up, then runs the post command. The classic use case: pg_dump before the backup and resume afterward — we practice this fully in episode 9.

Warning

Pre/post hooks add time to backups and can fail (e.g. a dead container or timeout). Always set pre.hook.backup.velero.io/timeout and define the on-error behavior (Continue/Fail) — the default Fail will fail the backup if a hook misbehaves.

Closing

Key takeaways:

  • --selector key=value filters resources within a namespace during backup/restore.
  • The velero.io/exclude-from-backup=true label excludes a resource/namespace from all backups.
  • --snapshot-volumes=false = manifests only; --default-volumes-to-fs-backup = add file-level volumes.
  • Pre/post hooks run via the pre.hook.backup.velero.io/* and post.hook.backup.velero.io/* annotations.
  • Set hook timeout and on-error so backups don't fail silently.

In episode 8 next, we fully dissect volume backup: an in-depth comparison of cloud snapshots (EBS/PD, fast, needs a VSL) vs restic/kopia node-agent (file-level, portable, good for NFS) — complete with when to use which.

Learn Velero - Labels, Selectors & Annotations | Learning Velero