Velero
Kubernetes backup, restore, and migration tool. Velero saves cluster resource state (Deployments, Services, ConfigMaps, PVCs) and optionally PVC data to S3-compatible object storage. It supports recurring backup schedules, TTL-based expiration, and namespace-scoped or cluster-wide backup policies.
The default installation backs up Kubernetes resource manifests only. To include the contents of Persistent
Volumes (databases, uploads, application data), you must enable nodeAgent.enabled: true and set
configuration.defaultVolumesToFsBackup: true (or set defaultVolumesToFsBackup: true per schedule). Without
node-agent, restoring from backup will recreate empty PVCs — no data included.
Key Features
- Cluster-scoped backup — saves Kubernetes resources and optionally PVC data to S3
- Kopia filesystem backup —
uploaderType: kopia(modern replacement for Restic) - Scheduled backups —
Scheduleresources rendered directly from chart values - TTL-based expiration — backups expire automatically (default 7 days)
- Node-agent DaemonSet — optional filesystem backup for PVC data inclusion
- S3-compatible storage — validated with the AWS plugin for MinIO and AWS S3
- Restore-only mode — lock a cluster to restores only (useful for DR environments)
- Prometheus metrics — metrics Service enabled by default and optional ServiceMonitor
- Restricted server and plugin containers — non-root identities, read-only root filesystems, dropped capabilities, blocked privilege escalation, and RuntimeDefault seccomp
- NetworkPolicy enabled by default — ingress is limited to the metrics listener
- Configurable metrics listener — the process port, probes, and named Service target stay aligned
Installation
Velero requires cluster-wide permissions and is typically deployed in a dedicated namespace:
HTTPS repository:
helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install velero helmforge/velero -n velero --create-namespace -f values.yaml
OCI registry:
helm install velero oci://ghcr.io/helmforgedev/helm/velero -n velero --create-namespace -f values.yaml
Deployment Examples
# values.yaml — Velero backing up Kubernetes resources only (no PVC data)
# This is the default behavior. PVC contents are NOT included.
credentials:
existingSecret: velero-s3-credentials # must contain 'cloud' key with AWS-format credentials
configuration:
defaultBackupTTL: 720h # 30 days
backupStorageLocations:
- name: default
provider: aws
bucket: my-velero-backups
default: true
config:
region: minio
s3Url: http://minio.minio.svc.cluster.local:9000
s3ForcePathStyle: true
insecureSkipTLSVerify: true# values.yaml — Full cluster backup including PVC data via node-agent
# Requires node-agent DaemonSet and uses Kopia for filesystem-level backup.
credentials:
existingSecret: velero-s3-credentials
configuration:
defaultBackupTTL: 720h
defaultVolumesToFsBackup: true # include PVC data in all backups by default
uploaderType: kopia
backupStorageLocations:
- name: default
provider: aws
bucket: my-velero-backups
default: true
config:
region: minio
s3Url: http://minio.minio.svc.cluster.local:9000
s3ForcePathStyle: true
insecureSkipTLSVerify: true
nodeAgent:
enabled: true
resources:
requests:
memory: 128Mi
cpu: 100m
limits:
memory: 512Mi
cpu: 500m# values.yaml — Scheduled daily and weekly backups with different TTLs
credentials:
existingSecret: velero-s3-credentials
configuration:
defaultBackupTTL: 168h # 7 days default
backupStorageLocations:
- name: default
provider: aws
bucket: my-velero-backups
default: true
config:
region: us-east-1
# s3Url not needed for real AWS S3
nodeAgent:
enabled: true
schedules:
- name: daily
schedule: '0 3 * * *'
template:
ttl: 168h # 7 days
includedNamespaces:
- default
- apps
defaultVolumesToFsBackup: true
snapshotVolumes: false
- name: weekly
schedule: '0 2 * * 0'
template:
ttl: 720h # 30 days
includedNamespaces: [] # empty = all namespaces
defaultVolumesToFsBackup: true# values.yaml — DR environment: Velero locked to restore-only mode
# Use this on a secondary cluster that only receives restores, never creates backups.
credentials:
existingSecret: velero-s3-credentials
configuration:
restoreOnlyMode: true
backupStorageLocations:
- name: default
provider: aws
bucket: my-velero-backups
default: true
accessMode: ReadOnly # read-only on DR side
config:
region: minio
s3Url: http://minio.minio.svc.cluster.local:9000
s3ForcePathStyle: true
insecureSkipTLSVerify: trueS3 Credentials Format
Velero uses an AWS credentials file format regardless of the S3 provider (including MinIO). The
credentials.secretContents field contains the full file content:
[default]
aws_access_key_id=your-access-key
aws_secret_access_key=your-secret-key
For production, store credentials in a pre-created Kubernetes Secret and reference it with
credentials.existingSecret:
kubectl create secret generic velero-s3-credentials \
--from-literal=cloud='[default]
aws_access_key_id=your-access-key
aws_secret_access_key=your-secret-key' \
-n velero
For backup storage that requires cloud credentials, set credentials.useSecret=true and provide one of
credentials.existingSecret, credentials.name, or credentials.secretContents so the Velero pods mount
/credentials.
Dual-stack Networking
The metrics Service supports Kubernetes dual-stack
fields through service.ipFamilyPolicy and service.ipFamilies. Defaults omit both fields so the cluster default
remains authoritative.
service:
ipFamilyPolicy: PreferDualStack
Use PreferDualStack without service.ipFamilies when the same values file may run on both single-stack and dual-stack
clusters. Set service.ipFamilies only when the target cluster advertises the requested families.
Security Boundary
The Velero server and default AWS plugin run as the non-root identities declared by their official images. Their
containers use read-only root filesystems, drop every Linux capability, block privilege escalation, and use
RuntimeDefault seccomp. Writable emptyDir volumes are mounted at /scratch, /plugins, and /tmp; Velero uses
/tmp for plugin process files.
When the node-agent uses the default Kopia uploader, both the server and node-agent also receive ephemeral writable
volumes at /home/cnb/udmrepo and /home/cnb/.cache. This keeps the rest of each root filesystem read-only while
supporting filesystem backups activated globally, by schedule, or by annotation.
The node-agent is the intentional exception: filesystem backup needs kubelet host-path access, so it runs as UID 0. It remains unprivileged, drops all capabilities, blocks privilege escalation, and uses a read-only root filesystem. Enable it only after reviewing Pod Security admission, hostPath policy, and node isolation.
Velero needs its ServiceAccount token and cluster-wide API access to back up and restore Kubernetes resources. The
default ClusterRoleBinding targets cluster-admin. Set rbac.create: false only when equivalent, reviewed RBAC is
managed outside the chart.
The default NetworkPolicy selects only the server and allows inbound traffic only to the metrics port. Egress remains
open because Kubernetes API, DNS, and object-storage destinations are environment-specific. Set
networkPolicy.allowExternalEgress: false before adding a restrictive server egress policy; NetworkPolicy rules are
additive, so leaving the chart’s allow-all rule enabled defeats a second restrictive policy. Restrict node-agent
networking separately when it is enabled.
Operations
Changing metrics.containerPort changes the Velero --metrics-address argument, container port, and all three TCP
probes. metrics.service.port is independent and changes only the Service-facing port; the Service uses the named
metrics target port.
Charts before 1.6 used configuration.metricsAddress and extraObjects.
Retained values using those names remain supported: the legacy metrics address
controls the process listener and legacy objects render together with
extraManifests. Migrate to metrics.containerPort and extraManifests when
editing the configuration.
Before relying on backups, verify that the Deployment is ready and every configured backup storage location is available:
kubectl rollout status deployment/velero -n velero
kubectl get backupstoragelocations.velero.io -n velero
kubectl logs deployment/velero -n velero --since=15m
A successful backup is not a recovery test. Perform scheduled restores into an isolated namespace or cluster and verify application data there. Helm does not remove or roll back Velero CRDs automatically, so review CRD changes separately during upgrades.
Configuration Reference
Core
| Parameter | Type | Default | Description |
|---|---|---|---|
nameOverride |
string | "" |
Override the chart name. |
fullnameOverride |
string | "" |
Override the full release name. |
commonLabels |
object | {} |
Extra labels added to all resources. |
Image
| Parameter | Type | Default | Description |
|---|---|---|---|
image.repository |
string | docker.io/velero/velero |
Velero server image. |
image.tag |
string | "v1.18.4" |
Image tag. |
image.pullPolicy |
string | IfNotPresent |
Image pull policy. |
imagePullSecrets |
array | [] |
Pull secrets for private registries. |
Plugins
| Parameter | Type | Default | Description |
|---|---|---|---|
plugins.enabled |
boolean | true |
Enable the default AWS/S3-compatible plugin. |
plugins.aws.name |
string | velero-plugin-for-aws |
Init container name. |
plugins.aws.repository |
string | docker.io/velero/velero-plugin-for-aws |
AWS plugin image repository. |
plugins.aws.tag |
string | v1.14.0 |
AWS plugin image tag. |
plugins.aws.securityContext |
object | restricted non-root defaults | Security context for the AWS plugin init container. |
plugins.extra |
array | [] |
Extra plugin init containers. |
Credentials
| Parameter | Type | Default | Description |
|---|---|---|---|
credentials.useSecret |
boolean | true |
Mount credentials when existingSecret, name, or secretContents is set. |
credentials.existingSecret |
string | "" |
Existing secret containing the credentials file (key: cloud). |
credentials.name |
string | "" |
Name for the Secret created by the chart when existingSecret is empty. |
credentials.key |
string | cloud |
Key inside the credentials secret. |
credentials.secretContents |
string | "" |
Full AWS credentials file content for inline secret creation. |
RBAC
| Parameter | Type | Default | Description |
|---|---|---|---|
rbac.create |
boolean | true |
Create a ClusterRoleBinding for the Velero service account. |
rbac.clusterAdministrator |
boolean | true |
Bind to cluster-admin. Required for full cluster backup. |
rbac.clusterAdministratorName |
string | cluster-admin |
ClusterRole name to bind. |
Configuration
| Parameter | Type | Default | Description |
|---|---|---|---|
configuration.uploaderType |
string | kopia |
Filesystem backup engine. kopia is the current default (replaces Restic). |
configuration.defaultBackupTTL |
string | 168h |
Default backup expiration TTL (7 days). Expired backups are deleted from S3. |
configuration.defaultItemOperationTimeout |
string | 4h |
Default timeout for item-level operations. |
configuration.logLevel |
string | info |
Server log verbosity. |
configuration.logFormat |
string | text |
Log format: text or json. |
configuration.restoreOnlyMode |
boolean | false |
Lock the server to restore operations only (useful for DR clusters). |
configuration.defaultVolumesToFsBackup |
boolean | false |
Include PVC data in backups by default. Requires nodeAgent.enabled: true. |
configuration.features |
string | "" |
Comma-separated Velero feature flags. |
configuration.extraArgs |
array | [] |
Extra server arguments. |
configuration.extraEnvVars |
array | [] |
Extra environment variables for the Velero server and node-agent. |
Backup Storage Locations
The default entry uses the AWS plugin in S3-compatible mode. For real AWS S3, omit s3Url.
| Parameter | Type | Default | Description |
|---|---|---|---|
configuration.backupStorageLocations[].name |
string | default |
BSL name. |
configuration.backupStorageLocations[].provider |
string | aws |
Provider plugin name. |
configuration.backupStorageLocations[].bucket |
string | "" |
S3 bucket name. |
configuration.backupStorageLocations[].prefix |
string | "" |
Optional key prefix within the bucket. |
configuration.backupStorageLocations[].default |
boolean | true |
Mark as the default BSL. |
configuration.backupStorageLocations[].accessMode |
string | ReadWrite |
ReadWrite for primary, ReadOnly for DR. |
configuration.backupStorageLocations[].config.region |
string | us-east-1 |
S3 region (use a custom string for MinIO). |
configuration.backupStorageLocations[].config.s3Url |
string | "" |
S3-compatible endpoint. Empty = AWS S3. |
configuration.backupStorageLocations[].config.s3ForcePathStyle |
boolean | true |
Required for MinIO and most S3-compatible stores. |
configuration.backupStorageLocations[].config.insecureSkipTLSVerify |
boolean | false |
Skip TLS verification (dev/MinIO HTTP only). |
Schedules
Schedules are rendered as Velero Schedule CRDs. The template.ttl in each schedule overrides the
server-level defaultBackupTTL.
| Parameter | Type | Description |
|---|---|---|
schedules[].name |
string | Schedule name. |
schedules[].schedule |
string | Cron expression for the backup schedule. |
schedules[].template.ttl |
string | Backup TTL for this schedule (overrides server default). |
schedules[].template.includedNamespaces |
array | Namespaces to include. Empty = all namespaces. |
schedules[].template.defaultVolumesToFsBackup |
boolean | Include PVC data in this schedule’s backups. |
schedules[].template.snapshotVolumes |
boolean | Use volume snapshots (requires cloud provider support). |
Node Agent (Filesystem Backup)
The node-agent requires host path access to pod volume directories. It runs as root (runAsUser: 0) by design — this
is necessary to read PVC mount paths on the node filesystem. Enabling node-agent is the only way to include PVC data
in backups via filesystem copy.
| Parameter | Type | Default | Description |
|---|---|---|---|
nodeAgent.enabled |
boolean | false |
Deploy the node-agent DaemonSet for filesystem backup. |
nodeAgent.podVolumePath |
string | /var/lib/kubelet/pods |
Host path to pod volume directories. |
nodeAgent.pluginVolumePath |
string | /var/lib/kubelet/plugins |
Host path to kubelet plugin directories. |
nodeAgent.useScratchEmptyDir |
boolean | true |
Mount an emptyDir scratch volume into the node-agent. |
nodeAgent.resources |
object | {} |
Resources for node-agent containers. |
Metrics
| Parameter | Type | Default | Description |
|---|---|---|---|
metrics.enabled |
boolean | true |
Expose Velero metrics on a Service. |
metrics.containerPort |
integer | 8085 |
Port listened on by the Velero process. |
metrics.service.type |
string | ClusterIP |
Metrics service type. |
metrics.service.port |
integer | 8085 |
Metrics service port. |
metrics.serviceMonitor.enabled |
boolean | false |
Create a Prometheus Operator ServiceMonitor. |
metrics.serviceMonitor.interval |
string | 30s |
Metrics scrape interval. |
metrics.serviceMonitor.scrapeTimeout |
string | 10s |
Metrics scrape timeout. |
metrics.serviceMonitor.additionalLabels |
object | {} |
Extra labels for the ServiceMonitor. |
Service Networking
| Parameter | Type | Default | Description |
|---|---|---|---|
service.ipFamilyPolicy |
string | "" |
Optional metrics Service IP family policy. |
service.ipFamilies |
array | [] |
Optional ordered metrics Service IP family list. |
Resources and Security
| Parameter | Type | Default | Description |
|---|---|---|---|
resources |
object | {} |
CPU and memory requests and limits for the Velero server. |
terminationGracePeriodSeconds |
integer | 3600 |
Grace period (1 hour). Allows in-progress backups or restores to complete. |
priorityClassName |
string | "" |
PriorityClass for the Velero server pod. |
podSecurityContext |
object | restricted non-root defaults | Pod-level security context. |
containerSecurityContext |
object | restricted non-root defaults | Security context for the Velero server. |
Probes and Network Policy
| Parameter | Type | Default | Description |
|---|---|---|---|
startupProbe.enabled |
boolean | true |
Probe the metrics listener while the server starts. |
readinessProbe.enabled |
boolean | true |
Remove an unhealthy metrics endpoint from Service endpoints. |
livenessProbe.enabled |
boolean | true |
Restart a server whose metrics listener stops responding. |
networkPolicy.enabled |
boolean | true |
Create the server NetworkPolicy. |
networkPolicy.allowExternalEgress |
boolean | true |
Permit Kubernetes API and object-storage egress. |
Service Account
| Parameter | Type | Default | Description |
|---|---|---|---|
serviceAccount.server.create |
boolean | true |
Create the Velero service account. |
serviceAccount.server.name |
string | "" |
Override the service account name. |
serviceAccount.server.annotations |
object | {} |
Annotations for the service account (e.g. IRSA for AWS EKS). |
serviceAccount.server.automountServiceAccountToken |
boolean | true |
Mount the API token required by the controller. |
Scheduling
| Parameter | Type | Default | Description |
|---|---|---|---|
nodeSelector |
object | {} |
Node selector for the server pod. |
tolerations |
array | [] |
Tolerations for the server pod. |
affinity |
object | {} |
Affinity rules for the server pod. |
priorityClassName |
string | "" |
PriorityClass for the server pod. |
Extra
| Parameter | Type | Default | Description |
|---|---|---|---|
extraVolumes |
array | [] |
Extra volumes for the server pod. |
extraVolumeMounts |
array | [] |
Extra volume mounts for the server container. |
extraManifests |
array | [] |
Extra Kubernetes manifests rendered with tpl. |
extraObjects |
array | [] |
Deprecated pre-1.6 alias retained for upgrades. |
More Information
Velero v1.18.4 fixes a backup queue that could remain stuck when a dequeued backup completed during its status patch. Review the upstream release before upgrading production recovery infrastructure.