Velero backupPVC 配置设计:基于 node-agent ConfigMap 的 CSI 快照数据迁移中间卷调优
2026/9/16 1:31:50 网站建设 项目流程

Velero backupPVC 配置设计:基于 node-agent ConfigMap 的 CSI 快照数据迁移中间卷调优

【免费下载链接】veleroBackup and migrate Kubernetes applications and their persistent volumes项目地址: https://gitcode.com/GitHub_Trending/ve/velero

导读

本文围绕 Velero(Kubernetes 应用与持久卷备份迁移工具)中Volume Snapshot Data Movement(卷快照数据迁移)场景下的中间 PVC(backupPVC)配置机制展开,完整解析其设计文档《Backup PVC Configuration Design》中的背景、目标、数据结构、配置示例与实现细节。你将掌握:如何通过node-agent的 ConfigMap 按源 PVC 的 StorageClass 为 backupPVC 指定专用存储类与ReadOnlyMany只读访问模式,理解配置项在node-agent启动时如何被加载、如何传递到 CSI Snapshot Exposer 并最终作用到 backupPVC/backupPod 的创建上,以及配置错误时 DataUpload CR 卡在Accepted阶段与 prepare 超时(默认 30 分钟)的排障思路。

背景:为什么要为 backupPVC 提供高级配置

在 Volume Snapshot Data Movement Design 定义的数据迁移架构中,Exposer 模块负责把卷快照"暴露"给 Velero node-agent,VGDP(Velero Generic Data Path)通过一个中间卷完成数据读取。这个中间卷在设计中被称为backupPVC,消费它的 Pod 称为backupPod,而真正要被备份的 PVC 称为sourcePVC。三者关系如下:

  • sourcePVC:要被备份的 PVC(其快照由数据迁移插件创建);
  • backupPVC:由 Exposer 创建的中间 PVC,VGDP 从它上面读取数据;
  • backupPod:挂载 backupPVC 的 Pod,供 VGDP 访问其中数据。

在默认流程里,Exposer 从快照创建一个可写的 backupPVC,其存储类与访问模式继承自 sourcePVC。但在一些真实环境中,这种默认行为并非最优:

  1. 只读卷创建更快:部分存储提供商从快照创建只读卷时速度极快,而创建可写卷则需要克隆整块磁盘数据,耗时明显。如果 backupPVC 的accessModes被设为ReadOnlyMany,卷驱动便有机会通知存储层直接创建只读卷,从而大幅缩短快照暴露时间。但ReadOnlyMany并非所有存储都支持,因此需要允许用户自行配置。
  2. 中间卷不需要副本:部分存储提供商在创建卷时会按存储类定义生成一个或多个副本,但对备份用的中间卷来说保留副本毫无意义。因此需要允许用户为 backupPVC 指定另一个专用存储类。

这正是本设计文档要解决的问题——为用户提供一种机制,按需为 backupPVC 指定多种高级配置

设计目标

  • 为用户提供指定 backupPVC 各种配置的机制;
  • 配置需要按卷(即按 sourcePVC 的存储类)区分,允许不同来源卷使用不同的 backupPVC 配置。

解决方案总览:复用 node-agent ConfigMap

设计采用 Velero node-agent CLI 的--node-agent-configmap参数所指定的 ConfigMap 来承载 backupPVC 配置。核心约定如下:

  • 该 ConfigMap不是由 Velero 创建的,用户按需手动创建;
  • ConfigMap 必须位于Velero 安装所在的命名空间;如果多个 Velero 实例安装在不同命名空间,则每个命名空间各有一个 ConfigMap,且只对该命名空间内的 node-agent 生效;
  • node-agent 服务在启动时读取这些配置并用于初始化相关 Exposer 模块。因此用户可以随时编辑该 ConfigMap,但要使修改生效必须重启 node-agent 服务
  • 配置以 ConfigMap 的 data 形式存在,本设计新增一种配置类型,名称为backupPVC
  • 由于用户可能为不同卷设置不同的 backupPVC 配置,因此配置被定义为一个以 sourcePVC 存储类名为键的 map:键是 sourcePVC 使用的存储类名,值是针对该 sourcePVC 创建的 backupPVC 的配置集合。

从源码看,node-agent 的配置加载逻辑位于 pkg/nodeagent/node_agent.go 的GetConfigs函数:它读取指定 ConfigMap,要求 data 中只能有一个 key,并将该 JSON 字符串反序列化为NodeAgentConfigs结构。配置读取发生在 node-agent server 构造阶段(见 pkg/cmd/cli/nodeagent/server.go 的getDataPathConfigs调用),随后在run()中被取出并传给 DataUpload 控制器(见 pkg/cmd/cli/nodeagent/server.go 与 pkg/cmd/cli/nodeagent/server.go),印证了"启动时读取、编辑后需重启"的设计约束。

数据结构详解

设计中给出了承载配置的核心数据结构。它隶属于 node-agent 整体配置Configs,当前实现中该类型位于 pkg/types/node_agent.go,名为NodeAgentConfigs

type Configs struct { // LoadConcurrency is the config for data path load concurrency per node. LoadConcurrency *LoadConcurrency `json:"loadConcurrency,omitempty"` // LoadAffinity is the config for data path load affinity. LoadAffinity []*LoadAffinity `json:"loadAffinity,omitempty"` // BackupPVC is the config for backupPVC of snapshot data movement. BackupPVC map[string]BackupPVC `json:"backupPVC,omitempty"` } type BackupPVC struct { // StorageClass is the name of storage class to be used by the backupPVC. StorageClass string `json:"storageClass,omitempty"` // ReadOnly sets the backupPVC's access mode as read only. ReadOnly bool `json:"readOnly,omitempty"` }

要点说明:

  • BackupPVCmap[string]BackupPVC,键为sourcePVC 的存储类名,值为该卷对应的 backupPVC 配置;
  • StorageClass:backupPVC 要使用的存储类名;
  • ReadOnly:是否将 backupPVC 的访问模式设为只读。

需要特别指出的是,当前仓库中的实现已经在设计文档的两个字段之外做了扩展。在 pkg/types/node_agent.go 中,BackupPVC结构体实际包含以下字段:

type BackupPVC struct { StorageClass string `json:"storageClass,omitempty"` ReadOnly bool `json:"readOnly,omitempty"` // SPCNoRelabeling sets Spec.SecurityContext.SELinux.Type to "spc_t" for the pod mounting the backupPVC // ignored if ReadOnly is false SPCNoRelabeling bool `json:"spcNoRelabeling,omitempty"` // ReadWriteOncePod sets the backupPVC's access mode to ReadWriteOncePod so the kubelet can use // mount-level SELinux labeling (-o context) instead of per-file relabeling, when the CSI driver // advertises SELinux mount support. // ignored if ReadOnly is true ReadWriteOncePod bool `json:"readWriteOncePod,omitempty"` Annotations map[string]string `json:"annotations,omitempty"` // SecretNames is a list of secret names to copy from the source PVC namespace // to the Velero namespace before creating the backupPVC. ... SecretNames []string `json:"secretNames,omitempty"` // ConfigMapNames is a list of configmap names to copy from the source PVC namespace // to the Velero namespace before creating the backupPVC. ... ConfigMapNames []string `json:"configMapNames,omitempty"` }

这些扩展字段(spcNoRelabelingreadWriteOncePodannotationssecretNamesconfigMapNames)对应了后续演进中引入的能力:SELinux 标签控制、ReadWriteOncePod 访问模式、自定义注解以及为加密卷等场景将 Secret/ConfigMap 从源 PVC 命名空间复制到 Velero 命名空间(相关复制逻辑与清理逻辑见 pkg/exposer/csi_snapshot.go 与 pkg/exposer/csi_snapshot.go)。本文以下内容以设计文档的两个核心字段为主线,扩展字段作为补充说明。

配置示例与 ConfigMap 创建

设计文档给出的 ConfigMap data 示例(JSON 格式)如下:

{ "backupPVC": { "storage-class-1": { "storageClass": "snapshot-storage-class", "readOnly": true }, "storage-class-2": { "storageClass": "snapshot-storage-class" }, "storage-class-3": { "readOnly": true } } }

示例中三种场景的语义:

  • 源卷存储类为storage-class-1:backupPVC 使用snapshot-storage-class存储类,且设为只读;
  • 源卷存储类为storage-class-2:backupPVC 仅更换存储类为snapshot-storage-class,保持默认访问模式;
  • 源卷存储类为storage-class-3:backupPVC 不换存储类,仅设为只读。

创建 ConfigMap 的操作步骤为:将上述 JSON 保存为文件(例如node-agent-config.json),然后执行:

kubectl create cm <ConfigMap 名称> -n velero --from-file=<json 文件名>

例如:

kubectl create cm node-agent-config -n velero --from-file=node-agent-config.json

创建后需要在 node-agent 启动参数中通过--node-agent-configmap指定该 ConfigMap 名称(对应 CLI 参数定义见 pkg/cmd/cli/nodeagent/server.go)。GetConfigs对 ConfigMap 的约束是:data 中只能有一个 key,否则会返回more than one keys are found in ConfigMap的错误(见 pkg/nodeagent/node_agent.go)。也就是说,这个 ConfigMap 的 data 应只包含一份完整 JSON(可以包含loadConcurrencyloadAffinity等其他类型的配置项,但都合并在这同一个 JSON 中,而不是拆成多个 key)。

实现原理:从配置到 backupPVC 的完整链路

设计文档规定了两条核心实现规则,均可在 CSI Snapshot Exposer 源码中得到印证:

  1. 存储类回退:如果backupPVC.storageClass不存在或为空,则使用 sourcePVC 的存储类;
  2. 访问模式规则:如果backupPVC.readOnly为 true,则ReadOnlyMany是 backupPVCaccessModes的唯一值;否则使用ReadWriteOnce

在 pkg/exposer/csi_snapshot.go 中,Exposer 先从csiExposeParam.BackupPVCConfig[csiExposeParam.StorageClass]按 sourcePVC 存储类取出配置:若配置中的StorageClass非空则覆盖默认存储类(否则沿用 sourcePVC 的存储类),并读取ReadOnly标志。随后在createBackupPVC中(pkg/exposer/csi_snapshot.go)落实访问模式:

pvcAccessMode := corev1api.ReadWriteOnce if readOnly { pvcAccessMode = corev1api.ReadOnlyMany } else if readWriteOncePod { pvcAccessMode = corev1api.ReadWriteOncePod }

即默认ReadWriteOncereadOnly=true时切换为ReadOnlyMany,扩展字段readWriteOncePod=true且非只读时切换为ReadWriteOncePod。备份 Pod 创建时若 backupPVC 为只读,则对应卷挂载也会带上ReadOnly: true(见 pkg/exposer/csi_snapshot.go)。

配置从 node-agent 到 Exposer 的传递链路为:

  1. node-agent server 在启动时通过getDataPathConfigs加载 ConfigMap(pkg/cmd/cli/nodeagent/server.go);
  2. run()中取出BackupPVCConfig并传入NewDataUploadReconciler(pkg/cmd/cli/nodeagent/server.go);
  3. DataUpload 控制器在 reconcile 时将BackupPVCConfig放入 Exposer 参数(pkg/controller/data_upload_controller.go);
  4. CSI Snapshot Exposer 按 sourcePVC 存储类查找配置并创建 backupPVC/backupPod。

测试用例对该链路做了充分验证,例如 pkg/exposer/csi_snapshot_test.go 的 "backupPod mounts read only backupPVC" 用例构造了BackupPVCConfigStorageClass: "fake-sc-read-only"ReadOnly: true),并断言生成的 PVC 访问模式为只读、存储类被替换;pkg/exposer/csi_snapshot_test.go 则统一断言了ReadOnlyMany/ReadWriteOncePod与存储类的预期结果。这些用例可作为理解配置生效细节的直接参考。

配置错误的影响与排障建议

设计文档明确指出了配置错误会带来的后果:

  • 一旦设置了backupPVC.storageClass,用户必须确保该存储类在集群中存在且可被 backupPVC 使用,否则对应的 DataUpload CR 将一直停留在Accepted阶段,直到 prepare 超时(默认 30 分钟);
  • 一旦设置了backupPVC.readOnly=true,用户必须确保存储支持从快照创建ReadOnlyMany的 PVC,否则同样会导致 DataUpload CR 停留在Accepted阶段直至 prepare 超时。

prepare 超时机制在源码中有对应实现:node-agent 服务默认的data-mover-prepare-timeout为 30 分钟(见 pkg/cmd/cli/nodeagent/server.go 与 pkg/cmd/cli/nodeagent/server.go),DataUpload 控制器在Accepted阶段会依据AcceptedTimestamp与 prepare 超时做超时判断(见 pkg/controller/data_upload_controller.go)。

另一个需要注意的排障难点是:超时发生后 DataUpload CR 会被取消,且 backupPVC 与 backupPod 会被删除,因此仅凭最终状态无法区分问题原因是上述两类配置错误还是其他原因。设计文档提出的改进方向是为 CSI Exposer 增加诊断机制,在 prepare 超时删除 backupPod 之前探查其状态。从当前仓库看,这一思路已被实现:CSI Snapshot Exposer 提供了DiagnoseExpose方法(pkg/exposer/csi_snapshot.go),会依次检查 backupPod、backupPVC(及关联 PV)、backup VolumeSnapshot/VolumeSnapshotContent 以及相关 Event 的状态并输出诊断信息,供排障定位问题根源。

总结

backupPVC 配置机制为 Velero 的 CSI 卷快照数据迁移提供了按需调优中间卷的能力:通过 node-agent ConfigMap 中的backupPVCmap,用户可针对不同 sourcePVC 存储类分别指定 backupPVC 的存储类与只读访问模式,从而利用"快照创建只读卷更快"的存储特性缩短暴露时间、避免中间卷产生冗余副本。该机制的核心约束是配置在 node-agent 启动时加载、修改后需重启 node-agent 生效;配置错误(存储类不存在/不可用,或不支持 ReadOnlyMany)会导致 DataUpload CR 卡在Accepted阶段直至 30 分钟 prepare 超时,排障时可借助 Exposer 的诊断能力定位根因。

如需深入理解该配置所处的整体架构,可继续阅读:

  • 数据迁移整体工作流:Volume Snapshot Data Movement Design
  • VGDP 与备份仓库设计:Unified Repository and Kopia Integration
  • 配置加载与结构定义:pkg/nodeagent/node_agent.go、pkg/types/node_agent.go
  • Exposer 实现与测试:pkg/exposer/csi_snapshot.go、pkg/exposer/csi_snapshot_test.go

【免费下载链接】veleroBackup and migrate Kubernetes applications and their persistent volumes项目地址: https://gitcode.com/GitHub_Trending/ve/velero

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询