Velero CSI、Node Agent 与 Data Mover
对象存储故障演练开始后,团队发现最新 Backup 一直是 Completed,但三块 PVC 的命运完全不同。第一块卷只有 CSI snapshot handle,源存储账号被隔离后目标集群看不见它;第二块卷走 File System Backup,恢复出了文件,却因为备份时应用仍在写,索引与数据块不在同一时点;第三块卷启用了 snapshot data movement,DataUpload 卡在 Accepted,临时 PVC 选错 StorageClass,直到超时才被取消。
这不是“Velero 备份偶尔不稳定”,而是三条数据路径被混成了一个开关。CSI snapshot 解决存储侧时间点副本,FSB 从已挂载的 live filesystem 读取文件,CSI Snapshot Data Movement 则先快照,再把快照内容经 node-agent 和 Kopia 搬进所选 BSL。只有 BSL 的账号、region、KMS、网络入口和保留控制确实独立于源存储,数据移动才真正跨出源故障域。三者的一致性、故障域、权限、临时容量和恢复速度都不同。
用恢复位置区分三条路径
| 路径 | 备份读取点 | 主要运行对象 | 数据最终位置 | 一致性与故障域 |
|---|---|---|---|---|
| 仅 CSI snapshot | CSI driver 创建的卷快照 | VolumeSnapshot、VolumeSnapshotContent | provider/存储后端快照 | 单卷时间点通常强于 live scan;仍可能绑定原 region、账号、driver 与 KMS |
| File System Backup | Pod 已挂载的 live volume | PodVolumeBackup、PodVolumeRestore | BSL 中的 Kopia repository | 可跨存储恢复;扫描跨越时间,不能自动保证数据库或多文件一致 |
| CSI Snapshot Data Movement | 从快照供应的临时 volume | DataUpload、DataDownload、BackupRepository | 所选 BSL 中的 Kopia repository | 先固定快照再上传,兼顾时间点与可移植性;是否跨故障域取决于 BSL 的独立性,且链路、临时资源和成本最长 |
从 Velero 1.14 起 CSI plugin 已合并进 Velero 主仓库,不应再安装旧 velero-plugin-for-csi。但“内置 CSI 逻辑”不等于集群已有快照能力:目标 Kubernetes 仍需 snapshot.storage.k8s.io/v1 CRD、snapshot-controller、CSI driver 旁的 external-snapshotter,以及 driver 真正实现快照。稳定行为以 Velero v1.18 CSI 文档和存储厂商支持矩阵为准。
FSB 与内建 CSI data mover 都使用 node-agent,但用途不同。FSB 需要从 kubelet 管理的 Pod volume 路径读取 live files;CSI data mover 的 node-agent 承载 DataUpload/DataDownload controller,并启动独立 data mover Pod 挂载临时 PVC。只使用 CSI data movement 时可以去掉不必要的 kubelet hostPath;使用 FSB 时则不能这样做。
先核验稳定版本与存储前提
以下实验固定 Velero v1.18.2 与 v1.18 文档。执行前核对 Velero Release、Kubernetes/Velero 兼容矩阵、CSI driver 版本、snapshot-controller/external-snapshotter、VolumeSnapshotClass、StorageClass 和 provider plugin。官网 main 是开发线,新字段必须回到目标稳定 release 才能进入生产配置。
实验账号需要创建 namespace、PVC、Pod、VolumeSnapshot 和 Velero CR;安装者还需 DaemonSet、ClusterRole、Secret、hostPath/privileged 等平台权限。对象存储身份要能访问专用 BSL prefix,repository password 必须在首次 FSB/data movement 前确定并在集群外保管。
velero version
kubectl version
kubectl api-resources | grep -E 'volumesnapshot|dataupload|datadownload|podvolumebackup|backuprepository'
kubectl get volumesnapshotclasses.snapshot.storage.k8s.io
kubectl get storageclass
kubectl -n velero get deploy,daemonset,pod
velero backup-location get
velero repo get最低可用证据是:Velero server 与 CLI 版本匹配;BSL Available;snapshot API 三类对象可发现;目标 CSI driver 有可用 VolumeSnapshotClass;node-agent 在将承载 FSB/data mover 的节点 Ready。只看到 CRD 不足以证明后端快照可创建。
安装 node-agent 时先决定是否需要 hostPath
现有 Velero 安装可以重新执行相同安装方式增加 node-agent。CLI 骨架如下,provider、plugin、bucket 与凭证参数沿用已经审核的安装清单:
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 支持下增加:
velero install \
--namespace velero \
--use-node-agent \
--node-agent-disable-host-path \
<the-same-reviewed-provider-arguments>这会减少默认 kubelet hostPath 暴露面。若后来启用 FSB,必须恢复正确 hostPath 与 MountPropagation。块卷 data movement 可能要求 --privileged-node-agent 访问 block device;OpenShift 等环境还需核对 SCC/SELinux。不能为了绕过一次权限错误就给所有 data mover Pod 永久 privileged。
Helm 安装使用 Chart 对应字段启用 deployNodeAgent,并把服务端镜像固定到 v1.18.2。Chart 字段会变化,先执行 helm show values vmware-tanzu/velero --version <reviewed-chart-version>;node-agent 的 hostPath、securityContext、资源和 toleration 由受版本控制的 values 管理,不再用 kubectl edit 形成漂移。
为三条实验路径准备同一份数据
准备一个支持目标 CSI driver 的测试 StorageClass 与 VolumeSnapshotClass。下面的 <csi-storage-class>、<snapshot-class> 必须替换为隔离集群真实对象;VolumeSnapshotClass 的 driver 要与 StorageClass provisioner 对应,且删除策略由实验清理计划决定。
export LAB_NS=velero-volume-lab
export STORAGE_CLASS='<csi-storage-class>'
export SNAPSHOT_CLASS='<snapshot-class>'
kubectl create namespace "${LAB_NS}"
kubectl get storageclass "${STORAGE_CLASS}" -o yaml
kubectl get volumesnapshotclass "${SNAPSHOT_CLASS}" -o yaml为 Velero 标记当前 driver 应使用的快照类;若同一 driver 有多个类,只标记经过恢复测试的一个:
kubectl label volumesnapshotclass "${SNAPSHOT_CLASS}" \
velero.io/csi-volumesnapshot-class=true --overwrite创建 PVC 和 writer Pod。marker、校验值和文件大小是三条路径共同的恢复断言:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: source-data
namespace: velero-volume-lab
spec:
accessModes: [ReadWriteOnce]
storageClassName: <csi-storage-class>
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: Pod
metadata:
name: volume-writer
namespace: velero-volume-lab
labels:
app: volume-writer
spec:
containers:
- name: app
image: busybox:1.36
command:
- sh
- -c
- |
printf 'checkpoint=ledger-000042\n' > /data/marker.txt
dd if=/dev/zero of=/data/payload.bin bs=1M count=64
sha256sum /data/marker.txt /data/payload.bin > /data/SHA256SUMS
sync
sleep 3600
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: source-datakubectl apply -f velero-volume-lab.yaml
kubectl -n "${LAB_NS}" wait --for=condition=Ready pod/volume-writer --timeout=180s
kubectl -n "${LAB_NS}" exec volume-writer -- cat /data/marker.txt
kubectl -n "${LAB_NS}" exec volume-writer -- sha256sum -c /data/SHA256SUMS预期输出 marker 为 ledger-000042,两个文件校验均为 OK。这只是单卷 crash-consistent 样本;数据库或多卷应用仍需 quiesce、Hook、VolumeGroupSnapshot 或数据库原生备份,并在恢复后执行事务级断言。
路径一:仅 CSI snapshot
先确保 Pod 没有 FSB annotation,然后创建默认卷快照 Backup:
kubectl -n "${LAB_NS}" annotate pod volume-writer \
backup.velero.io/backup-volumes- \
backup.velero.io/backup-volumes-excludes- || true
velero backup create csi-snapshot-only \
--include-namespaces "${LAB_NS}" \
--snapshot-volumes=true \
--wait
velero backup describe csi-snapshot-only --details
velero backup logs csi-snapshot-only
kubectl -n "${LAB_NS}" get volumesnapshot -o yaml
kubectl get volumesnapshotcontent -o yaml
kubectl -n velero get datauploads,podvolumebackups预期 Backup 的 CSI 卷信息包含 snapshot handle;不应出现属于该 Backup 的 DataUpload 或 PodVolumeBackup。VolumeSnapshot/Content 是否保留、如何标注和由谁删除,取决于 Velero 的备份流程与 class/content 删除策略;真正证据还包括 provider 侧快照 inventory,而不是只看 Kubernetes 对象。
恢复时 Velero 重新创建快照相关对象,再由 CSI provision 新 PVC。目标集群必须能使用同一 snapshot handle、driver、region/zone、KMS 与账号权限。仅 CSI snapshot 通常恢复快、没有仓库全量上传费用,但它不是天然异地副本;源存储服务或 KMS 故障会同时影响生产卷和恢复点。
可执行反例是把 Backup 同步到另一个无法访问源 snapshot handle 的隔离集群,再创建 Restore。预期 PVC Pending,event 或 CSI controller log 指向 handle、region、driver、KMS 或权限不可用;此时对象归档成功不能弥补卷数据不可达。不要在生产账号里故意撤销 KMS,而应使用专门实验快照和受控拒绝策略。
路径二:File System Backup
FSB 默认 opt-in,通过 Pod annotation 指定 volume 名。它读取 Pod 已挂载的 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
velero backup logs fsb-live-volume
kubectl -n velero get podvolumebackups \
-l velero.io/backup-name=fsb-live-volume -o wide
velero repo get预期产生 PodVolumeBackup,终态为 Completed,repository 为 Ready。node-agent 通过源 Pod 所在节点读取 volume path,Kopia 将文件分块、去重、压缩、加密并写入 BSL。FSB 能保护没有快照能力的 NFS、文件服务和 local persistent volume,也能跨不同 StorageClass 写回;但 hostPath volume 不受支持,未被 Pod 挂载的 PVC 也没有同样的读取入口。
FSB 的反向实验是移除 annotation 后再备份:
kubectl -n "${LAB_NS}" annotate pod volume-writer \
backup.velero.io/backup-volumes-
velero backup create fsb-missing-opt-in \
--include-namespaces "${LAB_NS}" \
--snapshot-volumes=false \
--wait
kubectl -n velero get podvolumebackups \
-l velero.io/backup-name=fsb-missing-opt-in
velero backup describe fsb-missing-opt-in --details预期可能仍得到 API 对象层面的 Completed,但找不到对应 PodVolumeBackup,因此这不是可用的 PVC 数据恢复点。若平台启用 --default-volumes-to-fs-backup 改成 opt-out,反向风险会变成“误把大卷、缓存卷或敏感卷全部上传”;此时用 excludes annotation 和资源筛选验证实际选择集合。完整注解和限制查 File System Backup。
live scan 期间修改大文件可以稳定暴露一致性风险:先在隔离卷持续覆盖 payload,再触发 FSB,恢复后比较应用生成的 manifest 与文件 checksum。出现不一致时应增加应用停写/flush Hook 或改走 snapshot-based path,而不是把 uploader 重试次数调大。
路径三:CSI Snapshot Data Movement
这条路径先创建 CSI snapshot,再从快照供应中间 backupPVC,最后由 data mover Pod 上传 BSL。创建 Backup 时显式增加 --snapshot-move-data:
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 pv
velero repo get稳定链路按以下状态推进:
Velero 遇到 PVC,内置 CSI Backup Item Action 创建 VolumeSnapshot/VolumeSnapshotContent。CSI plugin 创建每快照一个 DataUpload,Backup controller 周期查询异步 item operation。node-agent 中的 controller 接管请求,Kubernetes 从快照供应临时 backupPVC,并把它调度到可挂载节点。
node-agent 启动 data mover Pod;内建 data mover 使用 Kopia uploader 写入 BSL 对应的 Unified Repository。DataUpload 到达 Completed、Failed 或 Cancelled,临时 Pod/PVC/PV/快照对象按流程清理,Backup 才完成 finalization。
BYTES DONE 与 TOTAL BYTES 表示处理进度,INCREMENTAL BYTES 需 -o wide 才显示;实际对象存储增量可能因 Kopia 去重和压缩更小。状态机、默认 item timeout 与中间资源以 v1.18 CSI Snapshot Data Movement为准。
成功后保存:
velero backup describe csi-snapshot-moved --details
velero backup logs csi-snapshot-moved
kubectl -n velero get datauploads \
-l velero.io/backup-name=csi-snapshot-moved -o yaml
velero repo get -o yaml通过条件包括所有预期 DataUpload 为 Completed、bytes 进度闭合、Backup 无未知 partially failed item、BSL 中有对应仓库数据,且临时 PVC/Pod 没有长期残留。仅看到源快照 Ready 仍不能证明数据已经移动。
DataDownload 如何把仓库数据写回新卷
恢复 CSI data movement Backup 时,CSI plugin 为每个卷创建 DataDownload。目标侧先按恢复信息准备动态卷,node-agent 再启动 data mover Pod,从 Kopia repository 下载并写入目标 PVC:
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 -w
kubectl -n velero get pod,pvc
kubectl -n velero-volume-restore get pvc,pod
velero restore describe csi-moved-restore --details
velero restore logs csi-moved-restore恢复完成后,先在恢复出的 volume-writer Pod 内读取目标卷,避免给 ReadWriteOnce PVC 再挂一个 verifier Pod 而触发跨节点 Multi-Attach:
kubectl -n velero-volume-restore wait \
--for=condition=Ready pod/volume-writer --timeout=300s
kubectl -n velero-volume-restore exec volume-writer -- cat /data/marker.txt
kubectl -n velero-volume-restore exec volume-writer -- \
sh -c 'cd /data && sha256sum -c SHA256SUMS'预期 marker 精确为 ledger-000042,两个校验项均为 OK。若必须使用独立 verifier 镜像,应先停止或删除原挂载 Pod,确认 PVC 已卸载,再在满足 access mode 与拓扑约束的节点挂载;不能把 verifier Pending 误判为恢复数据损坏。DataDownload Completed 只证明 uploader 已写完,不证明文件 owner、SELinux label、应用事务、数据库启动和业务读写均正确。
目标 StorageClass 可以与源不同,但必须提前验证 access mode、filesystem、volume mode、拓扑、容量、KMS、动态供应和调度。StorageClass 名称映射只改字段,不会把不兼容 driver 变成兼容实现。
反向实验:错误 backupPVC StorageClass
CSI data movement 的中间 backupPVC 默认沿用源 StorageClass。某些存储创建可写 clone 很慢,可按 StorageClass 配置专用临时类或 ReadOnlyMany;但目标类不存在或不支持从快照供应时,DataUpload 会停在准备阶段。
在 node-agent ConfigMap 中为实验源类故意配置不存在的类:
{
"backupPVC": {
"<csi-storage-class>": {
"storageClass": "missing-backup-pvc-class",
"readOnly": false
}
}
}kubectl -n velero create configmap node-agent-negative \
--from-file=node-agent-config.json=./node-agent-negative.json将安装配置的 --node-agent-configmap 指向该 ConfigMap,滚动重启 node-agent 后创建专用 Backup:
kubectl -n velero rollout restart daemonset/node-agent
kubectl -n velero rollout status daemonset/node-agent --timeout=300s
velero backup create csi-move-bad-class \
--include-namespaces "${LAB_NS}" \
--snapshot-move-data
kubectl -n velero get datauploads \
-l velero.io/backup-name=csi-move-bad-class -o wide -w
kubectl -n velero get pvc,pod
kubectl -n velero get events --sort-by=.lastTimestamp预期 DataUpload 停在 Accepted/准备阶段,中间 PVC 因 StorageClass 不存在无法 Bound;达到 data-mover-prepare-timeout 后请求被取消、临时对象清理,Backup 标记为不可完整使用。默认准备超时和终态以目标 release 输出为准,官方 BackupPVC 配置给出了这一故障路径。
实验结束立即恢复受审 ConfigMap 引用,重启 node-agent,并用新 Backup 证明 DataUpload Completed。不要修改同名 ConfigMap 后假设热加载生效;node-agent 在启动时读取并发与 PVC 配置。
node-agent 权限边界要按路径收敛
FSB 的 node-agent 需要读取 kubelet Pod volume 路径、以 root 运行并依赖 MountPropagation,某些平台要求 privileged/SCC。这个 DaemonSet 一旦被攻破,风险接近读取节点上其他工作负载数据,因此应限制镜像 digest、节点选择、ServiceAccount、hostPath、网络出口和可写目录,并审计谁能修改 DaemonSet/ConfigMap。
纯 CSI data movement 可以用 --node-agent-disable-host-path 移除 FSB 路径;但 data mover Pod 仍能挂载包含业务数据的临时卷,并持有访问 BSL/Kopia 的能力。块卷可能需要 privileged node-agent,文件卷通常不应因此一并放宽。
Velero server 与 node-agent 还需要管理 VolumeSnapshot、临时 PVC/PV/Pod、DataUpload/DataDownload、BackupRepository 和相关 Secret。收紧 RBAC 时用三条真实路径分别演练;只让 Backup CR 可创建而阻止中间对象,会得到长期 Pending/Accepted,而不是安全降级。
仓库凭证分两层:对象存储身份控制 bucket/prefix,velero-repo-credentials 中的 repository password 控制 Kopia 仓库。密码应在第一次仓库操作前固定,变更后旧 repository 可能不可连接。Velero 当前 FSB/Kopia 文档还明确提示仓库使用静态公共 key 的限制:能访问备份存储的人可能解密数据,因此对象存储访问控制、KMS、独立账号和审计才是主安全边界,不能只依赖 repository password。
Kopia repository 不是一个普通目录
Velero 为需要文件数据的 namespace 管理 BackupRepository。Kopia 将内容分块、压缩、去重、加密,并维护索引与 snapshot 引用;多个 Backup 可能共享底层 blob。删除一个 Backup 不意味着其逻辑大小等量转化为物理空间下降。
velero repo get
velero repo get <repository-name> -o yaml
kubectl -n velero get backuprepositories.velero.io -o yamlrepository Ready 只说明当前可连接。完整恢复仍需验证目标文件、应用启动和业务水位。删除 Backup 时先移除 repository snapshot 引用,orphan blob 要等 full maintenance 回收;即使 full maintenance 完成,repository metadata 也不会被 Velero 自动删除。手工按猜测删除某个对象 key 会破坏共享索引。
中断的 data movement 可能留下 Kopia internal snapshot。正常后续 Backup 会清理一部分内部状态;若仓库永久停用且再也不运行 Backup,应在确认所有恢复点、保留和审计责任结束后,按整个专用 repository prefix 做退出,而不是局部删 blob。
缓存与并发决定恢复长尾
内建 data mover 默认每个节点一次处理一个 load。提高并发会同时增加快照 clone、临时 PVC、data mover Pod、CPU、内存、对象请求、网络、KMS、节点写吞吐与 cache 压力。先测单任务,再增加并发,并观察 P95/P99 耗时和失败率。
node-agent 并发 ConfigMap 示例:
{
"loadConcurrency": {
"globalConfig": 2,
"perNodeConfig": [
{
"nodeSelector": {
"matchLabels": {
"backup.example.io/capacity": "small"
}
},
"number": 1
}
]
}
}kubectl -n velero create configmap node-agent-config \
--from-file=node-agent-config.json=./node-agent-config.json
kubectl -n velero rollout restart daemonset/node-agent
kubectl -n velero rollout status daemonset/node-agent --timeout=300s全局并发从 1 起;per-node 规则覆盖全局规则,多个规则命中时采用较小值。配置不会热加载,细节查 Node-agent Concurrency。生产值由节点容量和恢复压测决定,不能把 2 当推荐值。
Kopia restore cache 默认位于 data mover Pod 根文件系统。cache 太小会重复读取远端并降低吞吐,太大则可能耗尽 ephemeral storage,导致 Pod eviction。可以在 node-agent ConfigMap 为较大恢复动态供应专用 cache PVC:
{
"cachePVC": {
"residentThresholdInMB": 1024,
"storageClass": "<cache-storage-class>"
}
}cache PVC 只支持动态供应。其大小由 repository cache limit 决定;Kopia 未配置 cacheLimitMB 时,v1.18 文档基线使用 5 GB 并额外计算开销。这个默认值必须随 release 重新核对,配置方法见 Data Movement Cache PVC和 Backup Repository Configuration。
监控至少覆盖:
DataUpload/DataDownload 排队年龄、phase、bytes done/total、incremental bytes 与 terminal reason。data mover Pod CPU、memory、ephemeral storage、restart、eviction、实际网络与卷吞吐。中间 PVC Pending 时间、StorageClass、拓扑、快照暴露时间和清理延迟。
BSL 请求错误、限流、KMS latency、repository maintenance 和物理容量趋势。每节点 active load、队列长度、Backup/Restore item operation timeout 与业务 RTO。
按第一停滞对象排障
| 停滞位置 | 常见原因 | 证据入口 |
|---|---|---|
VolumeSnapshot 不 Ready | snapshot-controller/sidecar 缺失、class/driver 不匹配、provider 配额/KMS | Snapshot condition、event、CSI controller log |
DataUpload Accepted | backupPVC 未 Bound、StorageClass/ROX/拓扑/SELinux 不兼容 | DataUpload YAML、PVC event、node-agent log |
| data mover Pod Pending | node selector、taint、资源、PVC 拓扑冲突 | Pod condition、scheduler event |
| data mover Pod OOM/Evicted | 并发过高、cache/ephemeral、资源 limit 过小 | termination reason、node pressure、usage trend |
DataUpload Failed | BSL/KMS/TLS、repository password、网络中断、Kopia error | DataUpload message、pod/server/node-agent log |
DataDownload 长时间运行 | cache 太小、对象读取限流、目标卷写慢、小文件过多 | bytes 进度、cache、对象请求、卷 latency |
Backup Finalizing | 异步 DataUpload/PodVolumeBackup 未终止 | Backup details、item operation、timeout |
一组最小取证命令:
velero backup describe <backup-name> --details
velero backup logs <backup-name>
velero restore describe <restore-name> --details
velero restore logs <restore-name>
velero repo get -o yaml
kubectl -n velero get datauploads,datadownloads,podvolumebackups,podvolumerestores -o wide
kubectl -n velero get pod,pvc,event --sort-by=.metadata.creationTimestamp
kubectl -n velero logs daemonset/node-agent --all-containers --since=30m
kubectl -n velero logs deployment/velero --since=30mDaemonSet 跨节点日志应先从 DataUpload/DataDownload 的处理节点缩小范围。调高 debug 前评估日志中的对象名、路径和错误内容,故障结束后恢复级别并清理敏感诊断包。
选择路径时同时算一致性、RTO 与账单
仅 CSI snapshot 适合 source/target 都在同一受支持存储故障域、追求快速恢复且已有独立存储级复制的场景。它避免全量对象上传,但 snapshot 数量、容量增量、跨区复制和 KMS 仍有费用;恢复受 driver 和 provider API 约束。
FSB 适合没有 snapshot 能力、需要跨 StorageClass 或保护文件存储的场景。它占用源节点读取、网络、对象请求和 repository 容量,对大量小文件尤其敏感;一致性依赖应用停写/flush。数据恢复时间近似为可恢复字节除以对象读取、网络、node-agent 和目标卷写入四者中的最小吞吐。
CSI data movement 适合既要 snapshot 时间点,又愿意把仓库部署到独立故障域的场景。它额外消耗 provider snapshot、临时 clone/PVC、data mover 计算、Kopia repository、对象请求和下载 cache;大规模并发还会冲击 scheduler、API Server、CSI controller 与 KMS。成本较高,但跨集群/跨 StorageClass 的可移植性通常强于只保留 snapshot。若 BSL 仍与源卷共用账号、region、KMS key 或网络控制面,数据路径虽然改变,灾备独立性仍没有成立。
多卷数据库不要只因每块卷都产生 DataUpload Completed 就声称一致。若目标稳定 release 和 CSI driver 支持 VolumeGroupSnapshot,可在明确支持矩阵内评估;否则使用数据库原生 backup/checkpoint、停写 Hook 或复制协议,并把外部日志/对象存储/消息水位纳入恢复点。
清理、升级与退出不能跳过 repository
先删除恢复实验 namespace,再删除 Restore 记录和专用 Backup:
kubectl delete namespace velero-volume-restore --ignore-not-found --wait=true
velero restore delete csi-moved-restore --confirm
velero backup delete \
csi-snapshot-only \
fsb-live-volume \
fsb-missing-opt-in \
csi-snapshot-moved \
csi-move-bad-class \
--confirm
kubectl delete namespace velero-volume-lab --wait=true
kubectl -n velero delete configmap node-agent-negative --ignore-not-found删除前确认 Backup 名称和 BSL,不要把通配符用于共享环境。velero backup delete 会触发关联清理;kubectl delete backup 只删 CR。随后核对 provider snapshot inventory、VolumeSnapshotContent、临时 PVC/PV/Pod、DataUpload/DataDownload、Kopia snapshot 引用和 BSL 物理容量。容量不会在删除 CR 后立即下降,需等待 repository full maintenance;不可变保留和对象版本还会延迟释放。
升级时把 CSI CRD/controller/driver、Velero CRD/server、node-agent、Kopia repository、StorageClass 和 VolumeSnapshotClass 当成一个兼容事务。候选版至少恢复一份仅 CSI snapshot、一份 FSB 和一份 CSI data movement Backup,并分别验证 marker、checksum、权限、缓存和清理。
restic 旧路径不能拖到最后:1.17/1.18 已禁止新建 restic FSB,只允许恢复旧数据;1.19+ 连旧 restic 恢复也移除。升级前盘点旧 PodVolumeBackup/repository,使用仍支持读取的版本完成恢复演练、迁移重备与保留决策。不要把旧 restic 的取消/恢复行为描述成当前 Kopia data mover 的能力。
退出 node-agent 前先停止会产生 FSB/data movement 的 Schedule,等待所有 PodVolumeBackup、PodVolumeRestore、DataUpload、DataDownload 进入终态,归档 repository password 与至少一个已验证恢复点。仅移除 DaemonSet 会让仓库数据仍在、恢复执行器却消失;仅删除 repository metadata 又会让历史 Backup 失去读取路径。最终退出证明要列出 BSL prefix、Kopia repository、provider snapshot、临时卷、hostPath/privileged 权限、云身份、KMS、cache PVC、对象保留和物理空间核销。
真正的选型问题从来不是“要不要打开 node-agent”,而是恢复时数据从哪里读取、经过哪些可失败对象、最终落在哪个独立故障域,以及团队能否用 VolumeSnapshot、PodVolumeBackup、DataUpload、DataDownload 和业务 checksum 把整条链证明出来。
