Velero 权威手册:对象备份、卷数据移动与恢复
Velero 的 Completed 只说明控制器完成了它实际接收到的工作,不代表应用已经具备可恢复性。一个 namespace 可能被 selector 排除,PVC 可能只保存对象定义或后端 snapshot handle,同名资源可能在 Restore 中被跳过;对象存储里存在归档,也不能证明卷数据已经离开源账号、region、CSI driver 与 KMS 故障域。
判断一份 Velero 恢复点,至少要核对 server 与插件版本、Backup 的对象选择、BackupStorageLocation(BSL)的实际数据、VolumeSnapshotLocation(VSL)或 CSI 路径,以及 Hook、warning、skipped item 和异步卷操作的终态。安装、调度、筛选、仅 CSI 快照、File System Backup、CSI Snapshot Data Movement、恢复验证与仓库退出必须落在同一条产品证据链里。
先把五类对象放回各自位置
Velero CLI 主要是创建和查看 Kubernetes 自定义资源,真正执行的是集群内的 Velero server 与插件 controller。一次命令结束不等于数据已经传完;server 会持续协调对象归档、快照、数据移动和状态更新。
BackupStorageLocation 描述对象存储 bucket 或 prefix、provider、访问模式与凭证引用。Kubernetes 对象归档、日志、结果以及 FSB/CSI data movement 的仓库数据都依赖 BSL。VolumeSnapshotLocation 描述云 provider 原生快照所在 region 等配置。它不保存 Kubernetes 对象,也不自动把快照复制到 BSL。
Backup 是一次保护请求,保存 include/exclude、label selector、TTL、Hook、快照与数据移动选择。它的 status 是 server 对这次请求的汇总,不是业务恢复证明。Schedule 是生成 Backup 的模板与时钟。应检查每个派生 Backup 的实际 spec 和状态,不能只看 Schedule 存在。Restore 从某个 Backup 读取对象和卷恢复信息,按资源顺序、冲突策略、namespace 映射和 Hook 执行。删除 Restore 不会撤销已经创建的业务对象。
Velero 同时处理 Kubernetes API 对象和持久卷数据,但二者是两条路径。对象归档进入 BSL;卷可能进入 provider snapshot、CSI snapshot、CSI snapshot data movement 或 File System Backup。只做本地快照时,数据仍可能留在原账号、region、KMS 和存储故障域。对象关系与位置语义可对照稳定版的 BSL/VSL 文档。
三条卷保护路径不能共用一个“已备份”结论
| 路径 | 读取点与运行对象 | 数据最终位置 | 主要边界 |
|---|---|---|---|
| 仅 CSI snapshot | CSI driver 创建 VolumeSnapshot / VolumeSnapshotContent | provider 或存储后端快照 | 恢复快,但常绑定原 region、账号、driver、拓扑和 KMS |
| File System Backup(FSB) | node-agent 扫描 Pod 已挂载的 live filesystem,生成 PodVolumeBackup | BSL 中的 Kopia repository | 可跨 StorageClass;扫描跨越时间,应用一致性需 Hook 或原生协议 |
| CSI Snapshot Data Movement | 先快照,再由 DataUpload、临时 PVC 和 data mover Pod 上传 | BSL 中的 Kopia repository | 时间点更清晰且便于迁移;链路、临时容量、传输成本和失败对象最多 |
从 Velero 1.14 起,CSI plugin 已并入主仓库,不应继续安装旧 velero-plugin-for-csi。这不等于集群自动具备快照能力:仍要有 snapshot.storage.k8s.io/v1 CRD、snapshot-controller、CSI external-snapshotter、可用 VolumeSnapshotClass,并确认 driver 真正实现快照。FSB 和内建 CSI data mover 都会用到 node-agent,但权限需求不同;FSB 要读取 kubelet 管理的卷路径,纯 CSI data movement 可以在受支持版本中禁用这类 hostPath。
选择路径前先写清恢复目标。若目标只在同一存储故障域内快速回滚,CSI snapshot 可能已经足够;若要跨 StorageClass 或保护无快照能力的文件卷,FSB 更直接;若既需要快照时间点又要把字节搬入独立 BSL,才使用 CSI Snapshot Data Movement。BSL 若仍与源卷共用账号、region、KMS key 或删除身份,开启 data movement 也没有形成独立灾备副本。
node-agent 的安装方式由卷路径决定
启用 FSB 或内建 CSI data mover 时,沿用已经审核的 provider、bucket、prefix 和凭证参数增加 node-agent:
velero install \
--namespace velero \
--use-node-agent \
--plugins='<provider-plugin>@sha256:<digest>' \
--provider='<provider-name>' \
--bucket='<dedicated-bucket>' \
--prefix='<velero-prefix>' \
--backup-location-config='region=<storage-region>' \
--secret-file='./credentials-velero-lab'
kubectl -n velero rollout status deployment/velero --timeout=300s
kubectl -n velero rollout status daemonset/node-agent --timeout=300s确定完全不使用 FSB、只使用内建 CSI Snapshot Data Movement 时,可在目标 release 支持下增加 --node-agent-disable-host-path。这会移除 FSB 所需的 kubelet 路径,不会消除 data mover Pod 对业务临时卷和 BSL 的访问能力。块卷、SELinux、OpenShift SCC、MountPropagation 和 privileged 要按实际 driver 验证,不能因为一类卷需要放宽权限,就把全部 node-agent 节点统一设成宽权限。
velero version
velero backup-location get
velero repo get
kubectl api-resources | grep -E 'volumesnapshot|dataupload|datadownload|podvolumebackup|backuprepository'
kubectl get volumesnapshotclasses.snapshot.storage.k8s.io
kubectl -n velero get deploy,daemonset,pod有效基线包括 CLI/server 与插件版本相容、BSL 为 Available、快照 API 与 class 可用、node-agent 覆盖将承载任务的节点。只有 CRD 而没有 controller 或后端实现,仍会在真正创建快照时失败。
File System Backup 保护的是已挂载文件系统
FSB 默认 opt-in,可在 Pod annotation 指定卷名。它读取 live filesystem,不依赖 CSI snapshot,也不会与同一卷的 snapshot 同时执行:
kubectl -n "${LAB_NS}" annotate pod volume-writer \
backup.velero.io/backup-volumes=data --overwrite
velero backup create fsb-live-volume \
--include-namespaces "${LAB_NS}" \
--snapshot-volumes=false \
--wait
velero backup describe fsb-live-volume --details
kubectl -n velero get podvolumebackups \
-l velero.io/backup-name=fsb-live-volume -o wide
velero repo get预期对应 PodVolumeBackup 到达 Completed,repository 为 Ready。没有被 Pod 挂载的 PVC 缺少同样的读取入口,hostPath 也不在支持范围内。移除 annotation 后再执行同一备份,是最直接的反向实验:API 对象层仍可能完成,但没有 PodVolumeBackup,因此不能声称 PVC 数据可恢复。若平台改用 --default-volumes-to-fs-backup,风险会反过来变成缓存卷、大卷或敏感卷被默认上传,必须用 excludes annotation 和实际对象清单复核。
FSB 的扫描有时间跨度。对隔离卷持续覆盖 payload,同时触发备份,恢复后比较应用生成的 manifest 与文件 checksum,能够暴露索引和数据块来自不同时点的问题。出现不一致时应增加停写、flush Hook 或改用 snapshot-based path,而不是提高 uploader 重试次数。具体注解和限制以目标版本的 File System Backup 文档为准。
CSI Snapshot Data Movement 由异步对象串起
数据移动先由 CSI 创建快照,再从快照供应临时 backupPVC,最后由 data mover Pod 通过 Kopia 上传到所选 BSL:
velero backup create csi-snapshot-moved \
--include-namespaces "${LAB_NS}" \
--snapshot-volumes=true \
--snapshot-move-data \
--wait
kubectl -n velero get datauploads \
-l velero.io/backup-name=csi-snapshot-moved -o wide -w
kubectl -n velero get pod,pvc
kubectl get volumesnapshot,volumesnapshotcontent -A
velero repo get -o yaml内置 CSI Backup Item Action 创建 VolumeSnapshot / VolumeSnapshotContent,随后产生 DataUpload。node-agent controller 接管请求,Kubernetes 从快照供应临时 PVC,data mover Pod 挂载它并把内容写入 Unified Repository。所有预期 DataUpload 到达 Completed、bytes 进度闭合、Backup 没有未知 partially failed item,且临时对象按期清理,才算数据上传完成。源快照 ReadyToUse 不能替代这些证据。
恢复时会为每个卷创建 DataDownload,目标侧准备动态卷后再下载:
velero restore create csi-moved-restore \
--from-backup csi-snapshot-moved \
--namespace-mappings velero-volume-lab:velero-volume-restore \
--wait
kubectl -n velero get datadownloads \
-l velero.io/restore-name=csi-moved-restore -o wide
velero restore describe csi-moved-restore --details
velero restore logs csi-moved-restoreDataDownload Completed 仅证明 uploader 写完。还要从恢复出的 Pod 读取 marker、验证 SHA-256、文件 owner 与安全标签,并执行数据库启动和业务读写断言。目标 StorageClass 可以变化,但 access mode、volume mode、filesystem、容量、拓扑、KMS 和动态供应必须兼容;改一个类名不会让不同 driver 自动互操作。
用错误的临时 StorageClass 固定失败证据
CSI data movement 的中间 backupPVC 默认沿用源 StorageClass。为一次性实验把 node-agent ConfigMap 映射到不存在的类,可以稳定验证准备阶段:
{
"backupPVC": {
"<csi-storage-class>": {
"storageClass": "missing-backup-pvc-class",
"readOnly": false
}
}
}kubectl -n velero get datauploads,pvc,pod -o wide
kubectl -n velero get events --sort-by=.lastTimestamp
kubectl -n velero logs daemonset/node-agent --all-containers --since=30m预期 DataUpload 停在 Accepted 或准备阶段,中间 PVC 因 StorageClass 不存在而无法 Bound,最终按目标 release 的 prepare timeout 取消。保存 DataUpload YAML、PVC event 和 node-agent log 后立即恢复受审 ConfigMap 引用,重启 node-agent,并用新 Backup 证明上传重新完成。配置在启动时读取,修改同名 ConfigMap 后不能假设热加载生效。
Kopia 仓库、并发和缓存共同决定恢复长尾
Kopia 对内容分块、压缩、去重、加密,并维护索引和 snapshot 引用。多个 Backup 可能共享底层 blob,所以删除一个 Backup 不会让物理容量等量下降;BackupRepository Ready 也只说明当前能连接,不等于任意历史点都通过恢复。手工猜测对象 key 并删除,会破坏共享索引。
node-agent 默认每节点处理有限 load。增加并发会同时放大快照 clone、临时 PVC、data mover Pod、CPU、内存、对象请求、网络、KMS 和目标卷写入压力。应从单任务基线开始,逐级观察 P95/P99、失败率和 API 限流。restore cache 太小会重复读取远端,太大则可能耗尽 ephemeral storage 并触发 eviction;较大恢复可按目标版本配置动态 cachePVC,但仍要把缓存容量纳入演练。
排障按第一个未推进对象定位:VolumeSnapshot 不 Ready 看 class、driver、provider 配额与 KMS;DataUpload Accepted 看 backupPVC、拓扑和 node-agent;data mover Pod Pending 看调度、资源和 PVC;DataUpload Failed 看 BSL、TLS、repository password 与 Kopia;DataDownload 长尾看 bytes 进度、缓存、对象限流和目标卷延迟。Backup 长期 Finalizing 时,应回到尚未终止的异步 item operation,而不是反复重启 server。
repository 密码要在首次 FSB/data movement 前固定并在集群外保管。对象存储身份控制 bucket/prefix,repository password 控制 Kopia 连接,两者都不能代替 BSL 的独立账号、KMS、不可变保留与审计。历史 restic 路径也必须进入升级计划:仍能读取它的版本下完成恢复演练、迁移重备和保留决策,再移除旧执行环境。
在第一次安装前固定四套版本
这里以 Velero v1.18.2 和 v1.18 版本化文档为示例基线。执行前先打开 Velero Releases 与兼容矩阵,确认目标 Kubernetes minor、Velero CLI/server、对象存储或云 provider plugin、CSI driver/snapshot controller 是经过团队验证的组合。官网 main 是开发线,不能据此承诺稳定环境中的字段和行为。
安装账号通常需要创建 CRD、Deployment、可选的 DaemonSet、ClusterRole/ClusterRoleBinding、ConfigMap 和 Secret。默认安装授予 Velero cluster-admin,这意味着它可以读取包括 Secret 在内的大量集群资源。对象存储侧另需专用身份,只允许访问 Velero 专用 bucket 或 prefix;不要复用人的云管理员凭证。实验还需要:
至少一个 Linux node 运行 Velero server;Windows workload 的具体镜像与限制另查目标 release。kubectl、Helm、可销毁 namespace,以及不会包含真实客户数据的对象存储位置。若使用快照,准备 provider plugin 或支持 snapshot.storage.k8s.io/v1 的 CSI driver、snapshot controller、CRD 与可用快照类。
若使用 FSB 或内建 CSI data mover,安装 node-agent,并预留节点权限、缓存、CPU、内存和临时空间。
先记录客户端和集群事实:
velero version --client-only
kubectl version
helm version
kubectl get nodes -o custom-columns='NAME:.metadata.name,OS:.status.nodeInfo.operatingSystem,KUBELET:.status.nodeInfo.kubeletVersion'
kubectl api-resources | grep -E 'backupstoragelocation|volumesnapshot'预期 velero version --client-only 输出 v1.18.2;若目标 release 已变化,应整体更新 CLI、server 镜像、插件和文档基线,而不是只替换本机二进制。
用 CLI 安装并保留可审计参数
CLI 可以从 v1.18.2 Release下载对应平台压缩包;macOS 也可用 Homebrew,Windows 可用 Chocolatey。包管理器安装后仍要检查实际版本,避免本机自动升级领先于 server。
下面是对象存储加 provider snapshot 的安装骨架。所有尖括号都必须替换为隔离环境值;插件使用与目标 release 兼容的不可变 digest,凭证文件用短期身份生成并在安装后安全销毁。
export VELERO_VERSION=v1.18.2
export PLUGIN_IMAGE='<provider-plugin>@sha256:<digest>'
export BACKUP_BUCKET='<dedicated-bucket>'
export BACKUP_PREFIX='<velero-prefix>'
export STORAGE_REGION='<storage-region>'
export SNAPSHOT_REGION='<snapshot-region>'
velero install \
--namespace velero \
--image="velero/velero:${VELERO_VERSION}" \
--plugins="${PLUGIN_IMAGE}" \
--provider='<provider-name>' \
--bucket="${BACKUP_BUCKET}" \
--prefix="${BACKUP_PREFIX}" \
--backup-location-config="region=${STORAGE_REGION}" \
--snapshot-location-config="region=${SNAPSHOT_REGION}" \
--secret-file='./credentials-velero-lab'
kubectl -n velero rollout status deployment/velero --timeout=300s
velero version
velero backup-location get
velero snapshot-location get预期客户端和 server 都报告目标版本,Deployment 完成 rollout,默认 BSL 为 Available。VSL 只在安装了相应 provider snapshot 能力时有意义;若只使用 CSI snapshot,可不创建传统 provider VSL。安装参数以 Basic Install和目标 provider 的官方插件文档共同为准。
不要把真实凭证内容贴进终端记录或 Git。安装后检查 Secret 名称、ServiceAccount 和云身份绑定,不读取明文:
kubectl -n velero get serviceaccount,role,rolebinding,clusterrole,clusterrolebinding | grep velero
kubectl -n velero get secret -o custom-columns='NAME:.metadata.name,TYPE:.type'
kubectl -n velero get backupstoragelocation default -o yaml
kubectl -n velero logs deployment/velero --tail=100BSL 的 status.phase 不可用时,优先按日志区分 DNS/TLS、对象存储拒绝、错误 region/endpoint、KMS 拒绝和 bucket/prefix 不存在。不要通过追加全局管理员权限来掩盖具体缺失动作。
用 Helm 安装时显式覆盖应用镜像
Velero 应用版本与 Helm Chart 版本是两套序列。Chart 的 appVersion 可能落后于最新 patch,因此先查询索引和 values,再显式固定 server 镜像与 plugin digest:
helm repo add vmware-tanzu https://vmware-tanzu.github.io/helm-charts
helm repo update
helm search repo vmware-tanzu/velero --versions | head
export VELERO_CHART_VERSION='<reviewed-chart-version>'
helm show chart vmware-tanzu/velero --version "${VELERO_CHART_VERSION}"
helm show values vmware-tanzu/velero --version "${VELERO_CHART_VERSION}" > velero-values.reference.yaml从该 Chart 的 schema 生成受版本控制的 values。下面只展示关键结构;字段必须与查询到的 Chart README/values 对齐,不能把另一版 values 原样复用:
image:
repository: velero/velero
tag: v1.18.2
initContainers:
- name: velero-plugin-for-provider
image: <provider-plugin>@sha256:<digest>
volumeMounts:
- name: plugins
mountPath: /target
configuration:
backupStorageLocation:
- name: default
provider: <provider-name>
bucket: <dedicated-bucket>
prefix: <velero-prefix>
config:
region: <storage-region>
volumeSnapshotLocation:
- name: default
provider: <provider-name>
config:
region: <snapshot-region>
credentials:
useSecret: true
existingSecret: velero-cloud-credentials
deployNodeAgent: false先创建 namespace 与凭证 Secret,再安装。--atomic 只能回滚 Helm release,不会删除已经写入外部 bucket 的数据或云快照:
kubectl create namespace velero
kubectl -n velero create secret generic velero-cloud-credentials \
--from-file=cloud='./credentials-velero-lab'
helm upgrade --install velero vmware-tanzu/velero \
--namespace velero \
--version "${VELERO_CHART_VERSION}" \
--values velero-values.yaml \
--atomic \
--timeout 10m
helm -n velero get values velero -a
kubectl -n velero rollout status deployment/velero --timeout=300s
velero versionCLI 与 Helm 是两种安装入口,不是两个并行 owner。选定 Helm 后,后续配置变更应回到 values 和 release;不要再用 velero install 覆盖同一组资源。
让 BSL 与 VSL 的故障域可见
一个 BSL 至少要明确 owner、bucket/prefix、region、KMS key、访问身份、版本/保留策略和删除权限。Velero 假设自己控制该位置,因此不要与其他应用共享未隔离 prefix。BSL 可以设置 ReadWrite 或 ReadOnly;灾难恢复时常把源集群位置以只读方式挂入目标集群,防止恢复端误删正式恢复点。
velero backup-location get
kubectl -n velero get backupstoragelocations.velero.io -o custom-columns='NAME:.metadata.name,PHASE:.status.phase,MODE:.spec.accessMode,DEFAULT:.spec.default,BUCKET:.spec.objectStorage.bucket,PREFIX:.spec.objectStorage.prefix'
kubectl -n velero describe backupstoragelocation defaultVSL 的 region 必须与可快照卷和 provider 规则兼容。它只描述快照调用入口,不提供跨 provider 可移植性。若 RPO 要求源存储损坏后仍可恢复,应选择 CSI data movement 或 FSB 把卷数据写入独立 BSL,并另外验证对象存储复制与 KMS 可用性。
多 BSL 场景要显式写 --storage-location,多 VSL 场景要显式写对应 location;默认值变化会让同名 Schedule 的后续 Backup 落到不同位置。日常证据中同时保存 Backup spec 与 location 对象 resourceVersion。
正向实验:备份一个可判定 namespace
先创建只含无敏感测试数据的 namespace、ConfigMap 和 Deployment。recovery-marker 是恢复后的业务断言,不使用真实域名、Token 或客户内容:
apiVersion: v1
kind: Namespace
metadata:
name: velero-lab
---
apiVersion: v1
kind: ConfigMap
metadata:
name: recovery-marker
namespace: velero-lab
labels:
protection.example.io/tier: gold
data:
checkpoint: "ledger-000042"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: marker-reader
namespace: velero-lab
labels:
protection.example.io/tier: gold
spec:
replicas: 1
selector:
matchLabels:
app: marker-reader
template:
metadata:
labels:
app: marker-reader
protection.example.io/tier: gold
spec:
containers:
- name: reader
image: busybox:1.36
command: ["sh", "-c", "cat /evidence/checkpoint && sleep 3600"]
volumeMounts:
- name: evidence
mountPath: /evidence
volumes:
- name: evidence
configMap:
name: recovery-markerkubectl apply -f velero-lab.yaml
kubectl -n velero-lab rollout status deployment/marker-reader --timeout=180s
kubectl -n velero-lab logs deployment/marker-reader
velero backup create velero-lab-positive \
--include-namespaces velero-lab \
--selector 'protection.example.io/tier=gold' \
--storage-location default \
--snapshot-volumes=false \
--ttl 168h \
--wait这里关闭卷快照是为了先证明 API 对象筛选链,不把无 PVC 的实验伪装成卷保护。预期日志输出 ledger-000042,Backup 终态为 Completed,且资源清单包含 ConfigMap、Deployment、Pod 及其必要依赖。检查汇总、详情、日志和对象字段:
velero backup get velero-lab-positive
velero backup describe velero-lab-positive --details
velero backup logs velero-lab-positive
kubectl -n velero get backup velero-lab-positive -o yaml如果 Items backed up 为零或目标对象缺失,先核对 selector 是作用于资源自身标签,不是只看 namespace 标签。include/exclude、glob、cluster-scoped 资源和 selector 的组合规则应按 Resource Filtering验证;不要用不断扩大到 * 的方式掩盖筛选错误。
从隔离 namespace 证明 Restore
删除源 namespace 会让实验具有恢复意义,但执行前再次确认名字是 velero-lab,并保留 Backup 详情。恢复到新 namespace,避免与同名对象冲突:
kubectl delete namespace velero-lab --wait=true
velero restore create velero-lab-restore \
--from-backup velero-lab-positive \
--namespace-mappings velero-lab:velero-restore-lab \
--wait
velero restore describe velero-lab-restore --details
velero restore logs velero-lab-restore
kubectl -n velero-restore-lab get configmap recovery-marker \
-o jsonpath='{.data.checkpoint}{"\n"}'
kubectl -n velero-restore-lab rollout status deployment/marker-reader --timeout=180s
kubectl -n velero-restore-lab logs deployment/marker-reader通过条件不是 Restore 为 Completed,而是 marker 精确为 ledger-000042,Deployment Ready,日志没有未知 failed/skipped item。默认 Restore 对同名既有对象通常采取非破坏路径;admission webhook 仍会重新运行,可能拒绝或修改恢复对象。跨集群还需预建 CRD/Operator、StorageClass、CSI、镜像访问、KMS、云身份与外部依赖。
反向实验:让 Hook 稳定失败
Backup Hook 通过 pod exec 在目标容器中运行。命令数组默认不经过 shell;需要管道、变量展开或多条命令时必须显式调用容器已有的 /bin/sh。创建一个缺少放行文件的 Pod,并把 on-error 设为 Fail:
apiVersion: v1
kind: Namespace
metadata:
name: velero-hook-lab
---
apiVersion: v1
kind: Pod
metadata:
name: hook-target
namespace: velero-hook-lab
annotations:
pre.hook.backup.velero.io/container: app
pre.hook.backup.velero.io/command: '["/bin/sh","-c","test -f /tmp/allow-backup"]'
pre.hook.backup.velero.io/on-error: Fail
pre.hook.backup.velero.io/timeout: 30s
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep 3600"]kubectl apply -f velero-hook-negative.yaml
kubectl -n velero-hook-lab wait --for=condition=Ready pod/hook-target --timeout=120s
velero backup create velero-hook-negative \
--include-namespaces velero-hook-lab \
--snapshot-volumes=false \
--wait
velero backup describe velero-hook-negative --details
velero backup logs velero-hook-negative预期证据是日志明确指出 pre hook 命令非零退出,Backup 不应被当作可用恢复点;具体汇总 phase 以目标 release 的实际输出为准。创建放行文件后重跑新 Backup,日志中的 hook error 应消失:
kubectl -n velero-hook-lab exec hook-target -c app -- touch /tmp/allow-backup
velero backup create velero-hook-positive \
--include-namespaces velero-hook-lab \
--snapshot-volumes=false \
--wait
velero backup describe velero-hook-positive --details数据库冻结 Hook 不能只写 pre-freeze;必须设计 post-unfreeze,并验证 pre 成功、快照失败、post 失败和 timeout 四条路径。onError: Continue 只表示继续处理,不会让数据自动一致。字段与默认超时查 Backup Hooks;应用级一致性仍要用数据库启动与业务查询证明。
把一次成功固化为 Schedule
先让一次手工 Backup 与 Restore 通过,再建立 Schedule。前面的步骤已经删除了源 velero-lab,因此这里保护恢复并验证过的 velero-restore-lab;若实际演练选择重建源 namespace,则应把参数改回重建后的真实名称,绝不能让 Schedule 长期指向不存在的 namespace。下面每小时触发,保留七天只是实验值;生产频率和 TTL 要由 RPO、恢复点增长、对象存储版本、快照成本和法规保留共同决定:
velero schedule create velero-lab-hourly \
--schedule='0 * * * *' \
--include-namespaces velero-restore-lab \
--selector 'protection.example.io/tier=gold' \
--storage-location default \
--snapshot-volumes=false \
--ttl 168h
velero schedule get
velero schedule describe velero-lab-hourly
kubectl -n velero get schedule velero-lab-hourly -o yamlSchedule 的时钟被接受不等于派生 Backup 成功。告警至少关联最近成功时间、连续失败数、Backup phase、warnings/errors、BSL 可用性和未完成异步操作。若手工触发模板对应 Backup,可使用目标 CLI 支持的 velero backup create --from-schedule 入口,并检查生成对象的最终 spec。
创建后至少等待一个派生 Backup,确认其 spec.includedNamespaces 为 velero-restore-lab,并检查对象数不是零。这样才能发现 namespace 拼写错误、对象已迁走或 selector 已失配,而不是等到灾难时才发现 Schedule 一直在生产空恢复点。
删除 Schedule 只停止后续创建,不能假设历史 Backup、provider snapshot 和仓库数据会同步消失。Schedule owner reference、Backup TTL、对象存储生命周期与不可变保留要一起演练。
从状态字段定位失败层
排障时按数据路径取证,而不是只收集 server 日志:
velero backup-location get
velero snapshot-location get
velero backup describe <backup-name> --details
velero backup logs <backup-name>
velero restore describe <restore-name> --details
velero restore logs <restore-name>
kubectl -n velero get backup,restore,schedule
kubectl -n velero get podvolumebackups,podvolumerestores
kubectl -n velero get datauploads,datadownloads
kubectl -n velero get events --sort-by=.lastTimestamp
kubectl -n velero logs deployment/velero --since=30m常见分型如下:
| 现象 | 第一证据 | 先查什么 |
|---|---|---|
BSL Unavailable | BSL condition 与 server log | DNS/TLS、region/endpoint、KMS、对象存储权限、专用 prefix |
| Backup 对象数异常少 | Backup spec 与 details | include/exclude、selector、glob、API discovery、RBAC |
Backup 长时间 InProgress/Finalizing | 异步 item operation | DataUpload、PodVolumeBackup、item timeout、node-agent |
Restore Completed 但对象缺失 | restore warnings/skipped | 同名对象、resource policy、webhook、namespace mapping |
| PVC 恢复后 Pending | PVC event、StorageClass、CSI log | driver、拓扑、配额、KMS、snapshot handle 或 data mover |
| Hook 超时 | backup/restore log 与 pod event | 容器名、命令是否存在、pod exec RBAC、冻结解冻路径 |
warnings > 0、未知 skipped item 或 PartiallyFailed 都必须有 owner 和处置结论。一次 Completed 只能说明 Velero 自身已完成它知道的工作;外部数据库、DNS、镜像、证书和下游连接仍需单独验收。
权限、凭证与多租户不能靠 namespace 想象
Velero 的 Backup、Restore 和 Schedule 通常集中在安装 namespace,由一个 server 读取集群资源。默认 cluster-admin 与可读取 Secret 的能力意味着它不是天然的普通租户自助隔离平台。官方提供收紧 RBAC 的方法,但仅把 Role 限制在业务 namespace 会遗漏 PV、CRD、cluster-scoped RBAC、VolumeSnapshotContent 等依赖。
生产收敛时按真实筛选集合生成权限清单,并分别验证备份和恢复。平台 API 只允许受控服务账号创建 Backup/Restore;租户不应直接修改 BSL、VSL、plugin、repository credential 或 namespace mapping。严格租户隔离使用独立 Velero 实例、独立 BSL/prefix、独立云身份和准入策略,再验证 cluster-scoped 对象不会串租户。
至少分开管理四种秘密:对象存储访问身份、provider snapshot 身份、Kopia repository password、目标集群恢复所需的 KMS/registry/外部服务凭证。Velero 备份了 Kubernetes Secret 对象,不表示这些外部身份在灾难后仍有效;仓库访问者也可能读取归档中的敏感配置,因此 bucket policy、传输 TLS、服务端加密、审计和跨账号副本都要独立成立。
用恢复吞吐反推容量与费用
容量预算不能只看当前 PVC 已用空间。对象归档、provider snapshot、对象版本、增量块、Kopia 索引、临时 PVC、节点 cache、日志和跨区复制都会占空间。一次 Backup 的对象数很小,也可能对应数 TB 卷数据;反过来,成千上万个小对象会增加 API listing、压缩和 restore apply 时间。
建立以下可计算项:
daily_logical_change = protected_bytes × daily_change_rate
repository_growth = daily_logical_change × retention_days × compression_dedup_factor
restore_floor = recoverable_bytes / min(object_read_throughput, network, node_write, storage_write)compression_dedup_factor 只能由目标数据压测得出,不能借用其他业务。费用至少包含对象存储容量与请求、provider snapshot、跨区/跨账号复制、下载与出口流量、KMS 请求、数据移动节点、临时卷和日志保留。把最近一次隔离恢复的实际吞吐与尾延迟纳入容量模型;Backup 调度成功并不能证明 RTO 可达。
清理实验对象,而不是误删正式恢复点
先删除恢复出的实验 namespace,再删除 Restore 记录。velero restore delete 会删除 Restore CR 及其日志/结果文件,但不会删除恢复出的对象:
kubectl delete namespace velero-restore-lab velero-hook-lab --ignore-not-found --wait=true
velero restore delete velero-lab-restore --confirm
velero backup delete velero-hook-negative velero-hook-positive --confirm
velero schedule delete velero-lab-hourly --confirmvelero backup delete 才会请求清理 Backup 及其关联 snapshot/repository 引用;直接 kubectl delete backup 只删 CR,可能留下对象存储和快照数据。受 Object Lock、版本保留或跨账号复制保护的对象不会因为 CR 消失而立即释放。FSB/Kopia 的 orphan blob 还要等待 repository maintenance,物理容量下降可能滞后。
实验用 velero-lab-positive 应先完成一次恢复证据归档,再决定删除:
velero backup describe velero-lab-positive --details > velero-lab-positive.describe.txt
velero backup logs velero-lab-positive > velero-lab-positive.log
velero backup delete velero-lab-positive --confirm
velero backup get不要把日志里可能含有的对象名称、错误正文或 Secret 数据直接上传公开工单。证据包保存版本、对象 UID、phase、计数、digest 和脱敏错误即可。
升级、回滚与退出按数据兼容处理
升级到 1.18 的官方路径以 1.17.x 为直接前置版本,要求依次处理 CLI、CRD、server、plugin 与 node-agent。跨多个 minor 时逐版阅读升级文档,不要把“Helm release 能升级”误写成“历史备份一定可恢复”。发布流程至少包含:
导出 Helm values、CRD、BSL/VSL、Schedule、RBAC、plugin digest 和仓库凭证引用。在隔离集群用当前版恢复一个旧恢复点,再用候选版恢复同一恢复点并比较业务断言。更新 CLI 与 CRD,再更新 server/plugin/node-agent;观察 API schema、repository 和异步对象。
创建候选版新 Backup,执行完整 Restore;回滚窗口内保留旧镜像、Chart、CRD 兼容评估和可读仓库。
旧 restic 路径是硬边界:Velero 1.17/1.18 只允许恢复既有 restic 备份,不再新写;1.19+ 将移除旧 restic 恢复。升级前必须盘点旧恢复点,在仍可读取的版本完成恢复演练、重备或到期处置,不能只证明新 Kopia Backup 成功。
退出 Velero 时先停止 Schedule,等待运行中 Backup/Restore/DataUpload/DataDownload 终止并归档证据,再决定外部备份的保留与迁移。按卸载文档删除集群组件,不等于删除 bucket、云快照、Kopia repository、IAM/KMS、恢复出的对象或临时 DNS/LoadBalancer。最终退出证明应同时列出集群内残留、对象存储 inventory、快照、凭证撤销、KMS grant、复制规则和仍受保留期约束的数据 owner。
当团队能从任意一个 Schedule 追到实际 Backup spec,从 Backup 追到 BSL/VSL 与卷数据路径,再从 Restore 追到应用水位和清理证据,Velero 才从“会产生绿色状态的控制器”变成了可治理的恢复平台。
