Velero 备份仓库配置机制详解:repositoryConfig 与 backup-repository-configmap 的设计与实战
【免费下载链接】veleroBackup and migrate Kubernetes applications and their persistent volumes项目地址: https://gitcode.com/GitHub_Trending/ve/velero
导读
本文围绕 Velero 仓库中的设计文档 backup-repo-config.md 展开,深入讲解 Velero 如何让用户为不同类型的备份仓库(Backup Repository)提供个性化配置:一方面在 BackupRepository CR 中新增repositoryConfig配置映射,另一方面引入由--backup-repository-configmap参数指定的 ConfigMap 作为配置模板。读完本文,你将掌握cacheLimitMB、enableCompression等核心配置项的语义与生效边界,能够独立创建并应用备份仓库配置,同时理解这些配置从 ConfigMap 到 Unified Repository 底层模块的完整源码调用链。
背景:为什么需要为备份仓库提供配置能力
在 Velero 的 Unified Repository 设计中,备份仓库(Backup Repository)被抽象为位于数据移动器(Data Mover,如 fs-backup、volume snapshot data movement)与备份存储(Backup Storage)之间的独立层,用于提供去重、压缩、加密、数据检索等备份恢复(BR)相关能力。Velero 默认基于 Kopia 仓库实现 Unified Repository,并保留 Restic 作为遗留路径。
由于不同备份仓库的运行环境差异很大,仓库的默认参数往往无法在所有场景下取得最佳效果。设计文档给出了两个典型例子:
- 性能导向:如果运行环境 CPU 与内存资源充裕,用户可能希望开启备份仓库提供的压缩功能,从而获得更高的备份吞吐量;
- 磁盘受限:如果本地磁盘空间不足,用户可能希望限制备份仓库的本地缓存大小,防止仓库把磁盘写满。
因此,设计目标非常明确:创建一种机制,让用户能够为备份仓库指定关键配置参数,且配置允许因备份仓库类型而异。下文介绍的两大核心机制正是为达成这一目标而设计。
核心机制一:BackupRepository CRD 与 repositoryConfig 配置映射
BackupRepository 的角色
当某个备份仓库被初始化之后,Velero 会创建一个 BackupRepository 自定义资源(CR)来代表该仓库的实例。其spec是 Unified Repo 各模块与备份仓库交互时的核心参数载体,包含备份存储位置(backupStorageLocation)、维护频率(maintenanceFrequency)、仓库类型(repositoryType,取值为kopia/restic/ 空)、restic 标识(resticIdentifier)以及卷命名空间(volumeNamespace)等。
新增 repositoryConfig 配置映射
由于不同备份仓库的配置各不相同,设计上不会为每个配置项逐一显式建模,而是在 BackupRepository 的 spec 中新增一个名为repositoryConfig的map[string]string类型字段,用于承载任意需要下发给备份仓库的配置。设计文档给出的完整 CRD spec 结构如下:
spec: description: BackupRepositorySpec is the specification for a BackupRepository. properties: backupStorageLocation: description: |- BackupStorageLocation is the name of the BackupStorageLocation that should contain this repository. type: string maintenanceFrequency: description: MaintenanceFrequency is how often maintenance should be run. type: string repositoryConfig: additionalProperties: type: string description: RepositoryConfig contains configurations for the specific repository. type: object repositoryType: description: RepositoryType indicates the type of the backend repository enum: - kopia - restic - "" type: string resticIdentifier: description: |- ResticIdentifier is the full restic-compatible string for identifying this repository. type: string volumeNamespace: description: |- VolumeNamespace is the namespace this backup repository contains pod volume backups for. type: string required: - backupStorageLocation - maintenanceFrequency - resticIdentifier - volumeNamespace type: object该结构在仓库源码中有完全对应的 Go 类型定义,见 backup_repository_types.go:
// RepositoryConfig is for repository-specific configuration fields. // +optional // +nullable RepositoryConfig map[string]string `json:"repositoryConfig,omitempty"`配置的按需取用原则
设计文档特别强调一个关键语义:配置项采用“按需取用”而非“无条件生效”。Unified Repo 各模块在操作备份仓库时,只会从repositoryConfig映射中检索当前操作实际需要的配置项。因此,即使某个配置被写入了 CR,如果当前操作对该仓库不需要该配置,它也不会被访问或生效——这不会带来任何问题。至于某个配置“何时生效、如何生效”,由配置自身定义,并应在配置的规范说明中予以明确。这一点对于理解后续cacheLimitMB与enableCompression的行为边界至关重要。
核心机制二:BackupRepository configMap 模板
为什么需要 configMap
BackupRepository CR 并不是由 Velero CLI 显式创建的,而是在备份、恢复或维护操作进行过程中,由 BackupRepository 控制器在 CR 不存在时自动创建。这意味着:在 CR 被创建之前,用户没有任何途径预先指定配置。
为此,设计引入了一个BackupRepository configMap,作为“将要应用到备份仓库 CR 的配置模板”:
- 当 BackupRepository 控制器创建备份仓库 CR 时,会读取 configMap 中的配置,并将其复制到 CR 的
repositoryConfig字段; - 对于已经存在的 BackupRepository CR,configMap永远不会再被读取——如果用户想修改配置值,必须直接编辑 BackupRepository CR。
生效规则
configMap 的生效遵循以下规则(均来自设计文档,且有源码佐证):
- configMap 由用户在 Velero 安装命名空间中自行创建;
- configMap 的名称必须通过 Velero server 参数
--backup-repository-configmap指定,否则配置不会生效; - 如果指定了 configMap 名称,但备份仓库被创建时该 configMap 尚不存在,则该名称会被忽略(不会阻塞仓库创建);
- 只要 configMap 未生效,备份仓库 CR 就不会被写入任何配置,Unified Repo 模块将使用代码内置的硬编码默认值。
从源码看,该参数同时在 Velero server 与 node-agent(VeleroNodeAgent daemonSet)中注册。在 config.go 中:
flags.StringVar( &c.BackupRepoConfig, "backup-repository-configmap", c.BackupRepoConfig, "The name of ConfigMap containing backup repository configurations.", )node-agent 的注册位于 nodeagent/server.go。同时,velero install 命令也提供了同名 flag,用于在安装时将 configMap 名称写入 deployment / daemonset 的参数,见 deployment.go 与 daemonset.go 中--backup-repository-configmap=<name>参数的拼接逻辑。
按备份仓库类型索引
虽然用户只能指定一个 configMap,但它支持按备份仓库类型分别配置。configMap 的data中支持多个条目,以仓库类型为键进行索引。在备份仓库创建过程中,控制器会按照仓库类型(如kopia、restic)去 configMap 中查找对应的配置 JSON。
配置项详解
基于上述机制,理论上任何配置项都可以被扩展加入。设计文档给出了当前(文档写作时点)已定义的配置项,本仓库源码中还展示了额外的维护间隔配置。
cacheLimitMB:本地数据缓存上限
- 语义:指定本地数据缓存的大小上限,单位为 MB。
- 性能权衡:本地缓存的数据越多,需要从备份存储下载的数据就越少,从而可能获得更好的性能;但缓存会占用本地磁盘空间,实践中应指定小于磁盘剩余空间的数值,避免磁盘被写满。
- 生效粒度:该参数按“仓库连接”生效,即用户可以在连接仓库之前修改它。
- 兼容性:如果备份仓库不使用本地缓存,该参数会被忽略;对于 Kopia 仓库,该参数受支持。
在源码中,缓存上限的默认值定义于 backend/common.go:DefaultCacheLimitMB = 5000(即默认 5000MB)。SetupConnectOptions在建立与 Kopia 仓库的连接时会读取该配置并将缓存细分为数据缓存与元数据缓存(数据缓存约占 80%、元数据缓存约占 20%),见 backend/common.go。此外,lib_repo.go 中的ClientSideCacheLimit也实现了对cacheLimitMB的解析。
enableCompression:压缩开关
- 语义:为备份仓库开启或关闭数据压缩。
- 兼容性:绝大多数备份仓库支持数据压缩;若某仓库不支持,该参数会被忽略。
- 动态调整:多数仓库支持在运行时动态开启/关闭压缩,因此该参数被设计为“每次创建到仓库的写连接时”使用;若仓库不支持动态调整,则该参数仅在初始化仓库时生效。
- Kopia:设计文档明确 Kopia 支持该参数,且可动态修改。
需要指出的是,从当前仓库的实现看,lib_repo.go 中getCompressorForObject目前返回空压缩器,注释写明“at present, we don't support compression”,仅元数据使用 Kopia 默认的zstd-fastest压缩。也就是说,设计文档描述的enableCompression能力是否在当前代码路径下最终透传并生效,取决于对应底层模块(如 Kopia 仓库库版本)的实现状态,配置本身被设计为“可安全忽略”式兼容。
配置白名单:从源码看配置的过滤边界
设计文档强调“任何配置项都可以被扩展加入”,但仓库代码对用户输入做了严格的白名单过滤。在 unified_repo.go 的getStorageVariables中,从backupRepoConfig(即 CR 的repositoryConfig)提取参数时,只有白名单内的参数才会被保留:
// We remove the unnecessary parameters and keep the modules/logics below safe if backupRepoConfig != nil { // range of valid params to keep, everything else will be discarded. validParams := []string{ udmrepo.StoreOptionCacheLimit, // "cacheLimitMB" udmrepo.StoreOptionKeyFullMaintenanceInterval, // "fullMaintenanceInterval" } ... }对应常量定义在 repo_options.go:StoreOptionCacheLimit = "cacheLimitMB",StoreOptionKeyFullMaintenanceInterval = "fullMaintenanceInterval"。后者支持三种取值:fastGC(12 小时)、eagerGC(6 小时)、normalGC(24 小时),用于覆盖 Kopia 的维护(GC)间隔。由此可见,当前仓库实际放行的配置项包括cacheLimitMB与fullMaintenanceInterval,而enableCompression尚未出现在该白名单中——这再次印证了“配置生效与否由配置自身与对应实现决定”的设计原则。
实战:创建并应用 BackupRepository configMap
配置示例
设计文档给出的完整 configMap 示例(支持多个仓库类型条目)如下:
apiVersion: v1 kind: ConfigMap metadata: name: <config-name> namespace: velero data: <repository-type-1>: | { "cacheLimitMB": 2048, "enableCompression": true } <repository-type-2>: | { "cacheLimitMB": 1, "enableCompression": false }其中<repository-type-1>、<repository-type-2>需替换为实际的仓库类型键,例如kopia、restic。注意:
- configMap 必须创建在Velero 安装命名空间(示例中为
velero)下; data中每个键对应一种仓库类型,值为一段JSON 字符串(而非 YAML 对象);- 配置值均为字符串形式,控制器在读取时会将其反序列化并写入 CR 的
repositoryConfig。
仓库的单元测试也使用了同样结构的样例数据,见 backup_repository_controller_test.go:例如"fake-repo-type": "{\"cacheLimitMB\": 1000, \"enableCompression\": true, \"fullMaintenanceInterval\": \"fastGC\"}",并断言读取结果被转换为map[string]string。
创建命令
将上述内容保存为 YAML 文件后,执行:
kubectl apply -f <yaml file name>在安装 / 升级时指定 configMap 名称
仅创建 configMap 还不够,必须让 Velero server(以及 node-agent)知道它的名称:
- 安装时使用
velero install --backup-repository-configmap=<config-name>,安装命令会校验该 configMap 是否存在且内容为合法 JSON,见 install.go(调用kubeutil.VerifyJSONConfigs); - 已安装环境下,可通过修改 Velero server deployment / node-agent daemonset 的参数
--backup-repository-configmap=<config-name>使其生效。
配置的后续修改方式
再次强调:configMap 仅在备份仓库 CR首次创建时被复制到repositoryConfig。仓库 CR 创建之后,configMap 不再被访问;若要调整已存在仓库的配置,请直接编辑 BackupRepository CR 的spec.repositoryConfig。
源码实现链路剖析
从配置的读取到最终落地下发,整条链路在仓库中清晰可循,这里结合代码逐段说明。
第一步:控制器读取 configMap
backup_repository_controller.go 中的getBackupRepositoryConfig实现了配置读取的核心逻辑:
- 若
--backup-repository-configmap为空,直接返回nil(不配置任何内容); - 从指定命名空间获取该 ConfigMap;
- 按仓库类型键
loc.Data[repoType]查找对应 JSON; - 若键不存在,记录日志并返回
nil(配置被忽略); - 对 JSON 反序列化并转换为
map[string]string返回。
第二步:配置写入 CR
在initializeRepo中(backup_repository_controller.go),控制器调用上述函数获取配置,并通过 patch 将结果写入rr.Spec.RepositoryConfig:
config, err := getBackupRepositoryConfig(ctx, r, r.backupRepoConfig, r.namespace, req.Name, req.Spec.RepositoryType, log) if err != nil { log.WithError(err).Warn("Failed to get repo config, repo config is ignored") } else if config != nil { log.Infof("Init repo with config %v", config) } ... rr.Spec.RepositoryConfig = config注意:即使读取失败,日志也只会告警并忽略配置,仓库初始化不会被阻塞——这与“configMap 未生效时使用硬编码默认值”的设计一致。
第三步:通过 Repository Provider 透传
Repository Provider 的GetStoreOptions(unified_repo.go)将BackupRepo.Spec.RepositoryConfig传入getStorageVariables,经白名单过滤后并入存储选项。这一数据流在 repo_init.go 的注释中有完整标注:
pkg/controller/getBackupRepositoryConfig(...) -> BackupRepo.Spec.RepositoryConfig map[string]string -> provider.getStorageVariables(..., backupRepoConfig) -> repoOption.StorageOptions[udmrepo.StoreOptionCacheLimit] / [StoreOptionKeyFullMaintenanceInterval]例如configMapName.data.kopia: {"fullMaintenanceInterval": "eagerGC"}最终会映射到 Kopia 的全量维护周期选项上。
第四步:缓存与维护参数落地
- 缓存:
SetupConnectOptions(backend/common.go)把cacheLimitMB(MB)换算为字节(<< 20),并按 80%/20% 拆分为数据缓存与元数据缓存;ClientSideCacheLimit(lib_repo.go)在参数缺失或解析失败时回退到默认值 5000MB。 - 维护间隔:
fullMaintenanceInterval在 repo_init.go 中被解析为fastGC/eagerGC/normalGC对应的 12h / 6h / 24h 间隔,覆盖 Kopia 的 Full Cycle 维护周期。
上述链路均有对应单元测试覆盖,例如ClientSideCacheLimit在 lib_repo_test.go 中验证了“无配置时使用默认 5000MB”“仅含 enableCompression 时仍回退默认值”“无 cacheLimitMB 时回退默认值”等场景。
注意事项与边界
综合设计文档与源码,使用备份仓库配置时需特别留意以下边界:
- configMap 是“一次性模板”:只在仓库 CR 首次创建时被复制,之后修改 configMap 不影响已有仓库;已存在仓库的配置必须直接编辑 CR。
- 名称未指定则完全无效:即便创建了 configMap,只要 Velero server 未通过
--backup-repository-configmap引用它,配置就不会生效。 - configMap 缺失不阻塞:指定名称但 configMap 不存在时,名称被忽略,仓库按硬编码默认值初始化。
- 配置“按需取用、白名单过滤”:配置项只有在对应操作需要它、且仓库实现支持它时才生效;用户输入还会被
getStorageVariables的白名单过滤,未放行的参数会被静默丢弃。 - 默认值兜底:
cacheLimitMB未配置时 Kopia 侧默认 5000MB(backend/common.go),配置解析失败时同样回退默认值。 - 配置不与备份/恢复数据路径冲突:仓库配置只影响备份仓库本身的运行参数(缓存、压缩、维护周期等),不影响备份数据在对象存储中的组织方式。
总结
备份仓库配置机制是 Velero Unified Repository 体系下“面向不同运行环境优化备份/恢复性能”的关键能力。它通过repositoryConfig映射与 BackupRepository configMap 模板两个机制,将“配置的承载”与“配置的注入”解耦:CR 承载最终生效值,configMap 提供创建时的模板来源,而--backup-repository-configmap参数完成二者的绑定。cacheLimitMB用于约束本地缓存、enableCompression用于控制压缩,另有fullMaintenanceInterval可调整仓库维护节奏,所有参数均遵循“按需取用、白名单过滤、默认值兜底”的稳健设计原则。对于想要在资源充足环境提升吞吐、或在磁盘受限环境防止缓存撑爆磁盘的用户,这一机制提供了标准、可复制的配置路径。
【免费下载链接】veleroBackup and migrate Kubernetes applications and their persistent volumes项目地址: https://gitcode.com/GitHub_Trending/ve/velero
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考