
Velero VolumePolicies 动作扩展以fs-backup与snapshot实现按策略驱动的卷备份【免费下载链接】veleroBackup and migrate Kubernetes applications and their persistent volumes项目地址: https://gitcode.com/GitHub_Trending/ve/velero导读本篇技术文章围绕 Velero 仓库中的设计文档 Extend-VolumePolicies-to-support-more-actions.md 展开讲解 Velero 如何把 1.11 引入的 VolumePolicies 从仅支持skip动作扩展为同时支持fs-backup文件系统备份与snapshot卷快照三种动作。文章会完整还原设计目标、两种动作在备份工作流中的改动方案、VolumeHelper接口的实现细节、与旧有注解/参数体系的优先级关系并结合当前仓库源码internal/volumehelper/volume_policy_helper.go、internal/resourcepolicies/、pkg/backup/item_backupper.go给出源码级印证。读完本文你将掌握如何编写「CSI 卷走快照、其余卷走文件系统备份」这类策略配置理解底层决策函数ShouldPerformSnapshot/ShouldPerformFSBackup的执行逻辑并能为实际备份场景选型合适的数据通路。一、背景从skip单动作到多动作的演进VolumePolicies 功能在 Velero 1.11 中引入其初衷来自设计文档 handle-backup-of-volumes-by-resources-filters.md在 Velero 中批量处理卷备份或跳过备份长期依赖逐 Pod 打注解opt-in/opt-out或 label-selector当集群中卷数量大、标签差异明显时非常繁琐因此需要一个「按卷属性条件conditions分组、并指定 Velero 对分组卷采取何种动作action」的通用机制。VolumePolicies 的 YAML 采用「条件 动作」结构策略之间按列表顺序匹配命中第一条后忽略后续条目每个条件键内部为「AND」语义即一个策略内所有条件需同时满足。该机制在 1.11 版本中只落地了skip一个动作file-system-backup即后来的fs-backup与volume-snapshot即snapshot被预留到后续版本。本篇关联文档正是对该预留能力的落地设计。从当前仓库 internal/resourcepolicies/resource_policies.go 可以看到最终支持的动作类型常量const ( // skip action implies the volume would be skipped from the backup operation Skip VolumeActionType skip // fs-backup action implies that the volume would be backed up via file system copy method using the uploader(kopia) configured by the user FSBackup VolumeActionType fs-backup // snapshot action can have 3 different meaning based on velero configuration and backup spec - cloud provider based snapshots, local csi snapshots and datamover snapshots Snapshot VolumeActionType snapshot // custom action is used to identify a volume that will be handled by an external plugin. Velero will not snapshot or use fs-backup if actioncustom Custom VolumeActionType custom )动作校验逻辑位于 internal/resourcepolicies/volume_resources_validator.goskip、snapshot、fs-backup、custom均为合法类型同时会对dataMover、snapshotClass等动作参数做类型与适用动作的校验。设计目标与非目标设计文档明确列出目标把 VolumePolicies 扩展为支持fs-backup文件系统备份与snapshot卷快照改善用户通过 Velero 备份卷的体验。非目标不改变现有的卷 opt-in/opt-out 注解方式不改变既有 VolumePolicies 功能不实现更细粒度的snapshot-csi、snapshot-datamover等动作留待后续增强。二、核心使用场景两条策略覆盖全部卷设计文档给出了两个典型场景说明多动作支持带来的收益。场景一CSI 卷快照 其余卷文件系统备份用户希望对所有 CSI 支持的卷使用snapshot其余卷使用fs-backup。在没有多动作支持前用户必须为每个挂载卷的 Pod 手工打上backup.velero.io/backup-volumes注解来逐个指定fs-backup在规模变大后极其繁琐。使用扩展后的 VolumePolicies只需两条策略version: v1 volumePolicies: - conditions: storageClass: - gp2 action: type: snapshot - conditions: {} action: type: fs-backup注意最后一条conditions: {}为空条件表示「匹配任意卷」作为兜底策略所有不满足第一条 CSI 卷条件的卷都会落入fs-backup分支。这正是设计文档强调的「criteria 和 action 必须具体且显式没有默认行为」的反例——把兜底行为显式写成空条件策略。场景二按 NFS 服务器定向做文件系统备份用户希望对某个特定 NFS 服务器导出的卷统一使用fs-backupversion: v1 volumePolicies: - conditions: nfs: server: 192.168.200.90 action: type: fs-backup条件中的nfs.server来自 PV 的persistentVolumeSource。在 internal/resourcepolicies/volume_resources.go 中nfsCondition.match实现了该匹配逻辑当条件中path为空、server非空时要求实际卷的 NFS server 与之完全相等若nfs: {}server 与 path 均为空则只要卷使用 NFS 源即匹配。三、高层设计两条改动路径设计文档将改动划分为两条路径均以 pkg/backup/item_backupper.go 中的backupItem() - backupItemInternal()为切入点fs-backup路径在备份工作流遇到 Pod 作为待备份 item 时针对 Pod 的每个卷调用卷策略判定决定该卷是否进入 PodVolumeBackup文件系统备份流程。snapshot路径在备份工作流遇到 PV 时调用takePVSnapshot遇到 PVC 时CSI 快照场景在executeActions()中拦截 CSI 插件动作。snapshot动作既可以是云厂商原生快照也可以是 CSI 快照具体走哪条由 Velero 根据 Backup CR 的既有配置自行决策。与旧机制的优先级关系关键语义设计文档明确规定了新动作与旧参数体系共存时的优先级这些规则在官方文档 site/content/docs/main/resource-filtering.md 中亦有完整描述snapshot动作 vsbackup.Spec.SnapshotVolumesVolumePolicy 中匹配到snapshot动作的卷无论如何都走快照备份不受SnapshotVolumes设置影响若未匹配到snapshot动作则当SnapshotVolumes未被显式设为false时仍走快照。fs-backup动作 vs 传统 opt-in/opt-outVolumePolicy 中匹配到fs-backup动作的卷优先级高于DefaultVolumesToFsBackup设置与 Pod 上的 opt-in/opt-out 注解若未匹配到fs-backup动作则回退到传统注解方式。整体回退语义VolumePolicy 只对「命中的卷」生效对某卷没有动作命中时使用传统 opt-in/opt-out 注解方式作为兜底。官方文档建议用户只用其中一种方式策略或注解管理卷备份避免混用造成理解混乱。综合而言过滤器优先级从高到低为include/exclude 资源过滤器最高→ VolumePolicy → fs-backup 的 opt-in/opt-out 注解 →backup.Spec.SnapshotVolumes最低这一点可在 site/content/docs/main/resource-filtering.md 中核对。四、详细设计与源码实现VolumeHelper接口设计文档提出引入VolumeHelper接口统一封装上述两种判定接口包含两个方法internal/volumehelper/volume_policy_helper.go 中实际实现为volumeHelperImpltype VolumeHelper interface { ShouldPerformSnapshot(obj runtime.Unstructured, groupResource schema.GroupResource) (bool, error) ShouldPerformFSBackup(volume corev1api.Volume, pod corev1api.Pod) (bool, error) }实现结构体volumeHelperImpl携带卷策略、快照开关、日志、K8s 客户端、默认 FS 备份开关与 PVC 排除标记等字段type volumeHelperImpl struct { volumePolicy *resourcepolicies.Policies snapshotVolumes *bool logger logrus.FieldLogger client crclient.Client defaultVolumesToFSBackup bool backupExcludePVC bool }该结构体在备份启动时于 pkg/backup/backup.go 中构造并注入itemBackupper与设计文档给出的初始化片段一致volumeHelperImpl, err : volumehelper.NewVolumeHelperImplWithNamespaces( backupRequest.ResPolicies, backupRequest.Spec.SnapshotVolumes, log, kb.kbClient, boolptr.IsSetToTrue(backupRequest.Spec.DefaultVolumesToFsBackup), !backupRequest.ResourceIncludesExcludes.ShouldInclude(kuberesource.PersistentVolumeClaims.String()), namespaces, ) ... itemBackupper : itemBackupper{ ... volumeHelperImpl: volumeHelperImpl, ... }需要说明的是当前仓库在NewVolumeHelperImpl基础上还演进出了NewVolumeHelperImplWithNamespaces与NewVolumeHelperImplWithCache两个变体后者通过pvcPodCache缓存 PVC 到 Pod 的映射避免大量 PVC/Pod 场景下的 O(N×M) 查询开销源码注释引用 issue #9179同时插件侧CSI 备份插件可通过NewVolumeHelperWithCache惰性构建缓存。这属于实现层面的后续优化不影响本文设计语义。4.1ShouldPerformFSBackupPod 卷的文件系统备份判定核心函数逻辑internal/volumehelper/volume_policy_helper.gofunc (v volumeHelperImpl) ShouldPerformFSBackup(volume corev1api.Volume, pod corev1api.Pod) (bool, error) { if !v.shouldIncludeVolumeInBackup(volume) { v.logger.Debugf(skip fs-backup action for pod %ss volume %s, due to not pass volume check., pod.Namespace/pod.Name, volume.Name) return false, nil } if v.volumePolicy ! nil { ... if volume.VolumeSource.PersistentVolumeClaim ! nil { pvc, err kubeutil.GetPVCForPodVolume(volume, pod, v.client) ... pvResource, err : kubeutil.GetPVForPVC(pvc, v.client) ... } ... vfd : resourcepolicies.NewVolumeFilterData(pv, podVolume, pvc) action, err : v.volumePolicy.GetMatchAction(vfd) ... if action ! nil { if action.Type resourcepolicies.FSBackup { // 命中 fs-backup 动作执行文件系统备份 return true, nil } else { // 命中其他动作如 snapshot / skip跳过文件系统备份 return false, nil } } } // 未命中任何策略回退到 legacy opt-in/opt-out 注解方式 if v.shouldPerformFSBackupLegacy(volume, pod) { return true, nil } return false, nil }要点解读前置过滤shouldIncludeVolumeInBackup会排除 hostPathnode-agent 无法访问、secret、configMap、projected、downwardAPI、默认 token 卷以及当backupExcludePVC为真时的 PVC 卷。这正是结构体注释中「用 backupExcludePVC 对齐 fs-backup 与 snapshot 动作」的原因——快照流程中 PVC 已被资源过滤器过滤而 fs-backup 基于 Pod 资源PVC 过滤器并不天然生效。策略匹配链对 PVC 卷会依次取 PVC → PV构造VolumeFilterData后调用GetMatchAction对非 PVC 的内联卷如 emptyDir、nfs 直挂则直接用 Pod 卷本身构造过滤数据。显式动作语义命中动作但类型非fs-backup时明确返回false印证了「没有默认行为」的设计原则。legacy 回退shouldPerformFSBackupLegacy同文件 L332-L357在defaultVolumesToFSBackupfalse时读取backup.velero.io/backup-volumesopt-in为true时读取backup.velero.io/backup-volumes-excludesopt-out与 Pod 注解工具pkg/util/podvolume配合。该函数在 pkg/backup/item_backupper.go 中于 Pod 被备份时逐卷调用返回true的卷会进入pvbVolumes列表交给backupPodVolumes处理并通过podVolumeSnapshotTracker登记避免同一 PVC 既走 PodVolumeBackup 又走快照造成重复备份。4.2ShouldPerformSnapshotPV/PVC 的快照判定对应设计文档中的快照判定函数internal/volumehelper/volume_policy_helper.gofunc (v *volumeHelperImpl) ShouldPerformSnapshot(obj runtime.Unstructured, groupResource schema.GroupResource) (bool, error) { // 将 unstructured 对象转换为 pvc / pv // PVC 场景额外通过 GetPVForPVC 拿到关联 PVPV 不存在时记录 pvNotFoundErr // PV 场景直接转换 if v.volumePolicy ! nil { vfd : resourcepolicies.NewVolumeFilterData(pv, nil, pvc) action, err : v.volumePolicy.GetMatchAction(vfd) ... if action ! nil { if action.Type resourcepolicies.Snapshot { return true, nil // 命中 snapshot 动作执行快照 } else { return false, nil // 命中其他动作跳过快照 } } } // 若 PV 已被 PVC 声明检查是否有 Pod 已通过 PodVolumeBackup 备份该卷内容是则不再快照 if pv.Spec.ClaimRef ! nil { pods, err : podvolumeutil.GetPodsUsingPVCWithCache(...) ... for _, pod : range pods { for _, vol : range pod.Spec.Volumes { if vol.PersistentVolumeClaim ! nil vol.PersistentVolumeClaim.ClaimName pv.Spec.ClaimRef.Name v.shouldPerformFSBackupLegacy(vol, pod) { return false, nil // 已被 PodVolumeBackup 备份跳过快照 } } } } if !boolptr.IsSetToFalse(v.snapshotVolumes) { return true, nil // SnapshotVolumes 未显式置 false按旧行为走快照 } return false, nil }这段代码精确实现了设计文档中的三条语义策略命中且动作类型为snapshot→ 返回true无论SnapshotVolumes如何设置策略命中但动作类型非snapshot→ 返回false跳过快照策略未命中 → 回退检查PV 若已被 PodVolumeBackup 覆盖则跳过否则取决于SnapshotVolumes是否为 false。4.3 快照路径的两个调用点PV 原生快照takePVSnapshotpkg/backup/item_backupper.go在快照前调用ShouldPerformSnapshot(obj, kuberesource.PersistentVolumes)返回false时记录 skipped PV 并直接返回不再触发 VolumeSnapshotter 插件snapshotVolume, err : ib.volumeHelperImpl.ShouldPerformSnapshot(obj, kuberesource.PersistentVolumes) if err ! nil { return err } if !snapshotVolume { ib.trackSkippedPV( obj, kuberesource.PersistentVolumes, volumeSnapshotApproach, not satisfy the criteria for VolumePolicy or the legacy snapshot way, log, ) return nil }此外takePVSnapshot中还有两处与策略相关的守卫CSI 特性开启时对pv.Spec.CSI ! nil的 PV 跳过原生快照避免与 CSI 插件重复快照若策略匹配到的动作是skip则直接跳过快照并跟踪记录同文件 L633-L654。PVC 的 CSI 快照在executeActionspkg/backup/item_backupper.go中当资源为 PVC 且执行动作为 CSI 备份插件velero.io/csi-pvc-backupper时if groupResource kuberesource.PersistentVolumeClaims actionName csiBIAPluginName { snapshotVolume, err : ib.volumeHelperImpl.ShouldPerformSnapshot(obj, kuberesource.PersistentVolumeClaims) if err ! nil { return nil, itemFiles, errors.WithStack(err) } if !snapshotVolume { ib.trackSkippedPV( obj, kuberesource.PersistentVolumeClaims, volumeSnapshotApproach, not satisfy the criteria for VolumePolicy or the legacy snapshot way, log, ) continue } }命中skip策略的 PVC 也会在executeActions中提前跳过同文件 L417-L423。设计文档同时指出vSphere 插件尚未支持 VolumePolicy因此在 vSphere 场景暂不应用策略判定——这一限制在代码中体现为对 CSI 插件名称的显式判断。4.4 卷策略的加载与匹配底层策略从 ConfigMap 加载后解析为Policies结构校验版本必须为当前支持的v1internal/resourcepolicies/volume_resources_validator.go。GetMatchActioninternal/resourcepolicies/resource_policies.go将 PV/Pod 卷/PVC 转换为structuredVolume提取容量、存储类、NFS/CSI 源、卷类型、PVC 标签/阶段/卷模式/访问模式再逐策略逐条件做 AND 匹配返回第一个全命中策略的动作。条件实现分布在 volume_resources.go 中当前仓库在 1.11 的capacity、storageClass、nfs、csi基础上还扩展了volumeTypes、pvcLabels、pvcPhase、pvcVolumeMode、pvcAccessModes等条件见 volume_resources_validator.go 与官方文档 resource-filtering.md。五、配置与操作指南5.1 创建策略 ConfigMap 并引用策略以 ConfigMap 形式存放于 Velero 安装命名空间通过 CLI 参数--resource-policies-configmap关联到具体备份该参数定义见 pkg/cmd/cli/backup/create.go# 1. 将策略写入 configmap示例CSI 卷快照其余卷 fs-backup kubectl create configmap backup-volume-policy -n velero \ --from-filepolicies.yaml./policies.yaml # 2. 创建备份并引用策略 velero backup create my-backup \ --resource-policies-configmap backup-volume-policy \ --include-namespaces my-workload-nsConfigMap 的 data 中只允许包含一个键其值为完整 YAML 文档getResourcePoliciesFromConfig在 internal/resourcepolicies/resource_policies.go 中对此有严格校验。策略 YAML 顶层结构为version: v1与volumePolicies列表。5.2 动作参数snapshotClass与dataMover当前实现为snapshot动作引入了两个可选参数internal/resourcepolicies/resource_policies.gosnapshotClass指定 CSI 快照使用的VolumeSnapshotClass适合「同一 CSI 驱动挂接多个存储阵列、各自需要不同快照类」的场景当参数存在时优先级高于备份注解与 VolumeSnapshotClass 标签选择但低于 PVC 上的注解见 csi.md 的完整优先级说明。dataMover选择快照数据移动器合法值包括velero默认内置、velero-fs、velero-block由Action.GetDataMover同文件 L87-L114解析并归一化。示例version: v1 volumePolicies: - conditions: storageClass: - array-1-sc action: type: snapshot parameters: snapshotClass: vsc-array-1 - conditions: storageClass: - array-2-sc action: type: snapshot parameters: snapshotClass: vsc-array-25.3 组合示例与预期结果以下示例取自官方文档 resource-filtering.md可直接作为验收用例。假设应用 Pod 含两个卷卷 1 使用存储类gp2-csi卷 2 使用存储类gp3-csi。场景策略预期结果只对gp2-csi做 fs-backupstorageClass: [gp2-csi]type: fs-backup仅卷 1 走文件系统备份只对gp2-csi做 snapshotstorageClass: [gp2-csi]type: snapshot仅卷 1 走快照按存储类分流gp2-csi→snapshot、gp3-csi→fs-backup两条策略卷 1 快照、卷 2 文件系统备份策略 注解混用gp3-csi→snapshot同时 Pod 注解backup.velero.io/backup-volumesVolume-1卷 2 快照策略命中卷 1 走注解兜底做 fs-backup策略 defaultVolumesToFSBackup: truegp2-csi→fs-backup且开启默认 FS 备份卷 1 策略命中做 fs-backup卷 2 无匹配动作经兜底逻辑也做 fs-backup5.4 全局卷策略可选扩展除按备份引用策略外Velero 服务器还支持--global-backup-volume-policies-configmap全局兜底策略详见 resource-filtering.md全局 ConfigMap 仅volumePolicies生效备份级策略在前、全局策略在后合并首个命中者生效全局策略在服务器启动与每次备份时都会校验缺失或非法会导致备份进入FailedValidation阶段。对应的合并实现为GetResourcePoliciesFromBackupWithGlobalinternal/resourcepolicies/resource_policies.go。六、未来扩展方向设计文档在「Future Implementation」中勾勒了更细粒度动作的构想但明确标注这些仅属建议、可能不会按原样落地snapshot-native仅使用云厂商原生快照volume snapshotter不兼容/不存在时直接跳过snapshot-csi仅走 CSI 插件不调用原生快照即使snapshotMoveDatatrue也不使用 datamoversnapshot-datamover仅使用 CSI 配合 datamover不调用原生快照即使snapshotMoveDatafalse也强制使用 datamover。文档同时指出待旧版 opt-in/opt-out 注解机制废弃、CSI 插件并入主仓库流程后这些动作更易于落地也可能不新增动作名而是通过snapshot动作的参数与条件来区分上述细分语义。从当前仓库看snapshot动作已通过dataMover参数实现了一部分细分能力验证了该方向的可行性。七、关联设计文档本设计是 VolumePolicies 的扩展其前身设计为 handle-backup-of-volumes-by-resources-filters.md其中包含 VolumePolicies 的 API 定义、条件格式capacity/storageClass/volume sources、ConfigMap 引用方式、版本管理与迁移、以及与既有资源过滤器的兼容性规则。读者可将两篇文档配合阅读形成从「单动作 skip」到「多动作策略驱动备份」的完整认知。结语VolumePolicies 的多动作扩展fs-backup与snapshot把「按卷属性分组 指定备份方式」从繁琐的逐 Pod 注解中解放出来两条策略即可覆盖整集群的卷备份决策。其核心价值在于三点显式且无默认的命中语义、对旧参数体系SnapshotVolumes、opt-in/opt-out 注解的清晰优先级、以及快照与文件系统备份两条数据通路在VolumeHelper接口下的统一封装。通过本文的源码对照读者可以在 internal/volumehelper/volume_policy_helper.go 中追踪判定逻辑、在 pkg/backup/item_backupper.go 中观察调用点、并以官方文档 resource-filtering.md 中的示例直接上机验证。【免费下载链接】veleroBackup and migrate Kubernetes applications and their persistent volumes项目地址: https://gitcode.com/GitHub_Trending/ve/velero创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考