- 云原生
- 存储
- 高可用
- 容器编排
【免费下载链接】longhorn
Cloud-Native distributed storage built on and for Kubernetes
导读
Longhorn 的 RecurringJob(定时任务)机制在 v1.5.0 引入了两种专用于快照清理的新任务类型:snapshot-delete与snapshot-cleanup,用于解决"非定时任务创建的快照无法自动回收"的痛点。本文以 enhancements/20230103-recurring-snapshot-cleanup.md 为骨架,结合当前仓库中的 CRD 定义、Helm 参数与演进文档,完整讲解这两种任务的语义差异、YAML 配置方法、底层执行流程与验证方式,帮助你为卷建立自动化的快照空间回收策略。
背景与动机:为什么需要"快照清理型"定时任务
既有清理能力的局限
Longhorn 的 RecurringJob 长期支持对快照的自动回收:定时执行snapshot任务创建快照后,会自动删除超过spec.retain定义数量的较旧快照。但这套清理逻辑存在一个明确边界——它只清理由该 RecurringJob 自己创建的快照。
对于以下来源的快照,用户此前只能手动删除:
- 手动(非定时)创建的卷快照;
- 备份流程中由 Longhorn 生成的快照;
- 卷操作过程中产生的系统快照(如删除副本、在线扩容时生成的中间快照)。
上述快照如果长期堆积,会持续占用备份存储或磁盘空间,而用户缺少一个"按保留数量统一回收所有来源快照"的自动机制。这正是 issue #3836 提出的核心诉求,也是 enhancements/20230103-recurring-snapshot-cleanup.md 的设计目标。
设计目标
该增强提案引入两个新的RecurringJobType:
| 任务类型 | 行为 | 保留语义 |
|---|---|---|
snapshot-delete | 定期删除并 purge(彻底清除)超出保留数量的所有类型快照 | 遵循spec.retain保留数量 |
snapshot-cleanup | 定期 purge 可移除的系统快照 | 不依赖spec.retain,一律清除过期系统快照 |
功能已在 Longhorn v1.5.0 正式发布,见 CHANGELOG-1.5.0.md 中的 "Snapshot Cleanup & Delete Recurring Job" 条目。
两种任务类型的语义辨析
snapshot-delete:按保留数回收全部快照
- 枚举卷上所有已过期快照,无论其创建方式(手动、定时、备份产生)如何;
- 删除超出
spec.retain数量的快照,并对已标记删除的快照执行 purge(彻底清除数据块); - 与既有
snapshot任务共用同一套"过期判定 + purge"清理管线(下文详述)。
snapshot-cleanup:仅回收系统快照
- 只针对可移除的或系统生成的快照(如删除副本、在线扩容等操作留下的临时快照);
- 不删除用户手动创建的快照,因此保留数量
retain对该任务无实际作用——这正是设计文档中"RecurringJob Mutate"一节将spec.retain强制改写为 0 的原因。
一句话区分:snapshot-delete是"全量按数保留",snapshot-cleanup是"定向清理系统残留"。
配置实战:完整 YAML 示例
两种任务均通过longhorn.io/v1beta2的RecurringJobCRD 声明,唯一差异在spec.task字段。
示例一:snapshot-delete(每分钟执行,保留 2 个快照)
apiVersion: longhorn.io/v1beta2 kind: RecurringJob metadata: name: recurring-snap-delete-per-min namespace: longhorn-system spec: concurrency: 1 cron: '* * * * *' groups: [] labels: {} name: recurring-snap-delete-per-min retain: 2 task: snapshot-delete任务完成后,卷上(无论快照来源)将只剩 2 个最新快照。
示例二:snapshot-cleanup(每分钟执行)
apiVersion: longhorn.io/v1beta2 kind: RecurringJob metadata: name: recurring-snap-cleanup-per-min namespace: longhorn-system spec: concurrency: 1 cron: '* * * * *' groups: [] labels: {} name: recurring-snap-cleanup-per-min task: snapshot-cleanup任务完成后,卷上的系统快照数量应为 0。注意此例中无需(也不应依赖)retain字段——CRD 校验与控制器会在该任务类型下将其按 0 处理。
字段说明(依据当前仓库 CRD 定义)
以上字段的语义可在 chart/templates/crds.yaml 的RecurringJobSpec中逐项核对:
| 字段 | 类型 | 说明 |
|---|---|---|
concurrency | integer | 每次触发的快照/备份操作的并发度 |
cron | string | Cron 调度表达式(如* * * * *表示每分钟) |
groups | array | 定时任务所属分组,供卷通过分组标签批量引用 |
labels | object | 应用到生成快照/备份的标签 |
retain | integer | 保留的快照/备份数量,仅count-based保留策略下生效 |
task | string | 任务类型,合法枚举见 CRD:snapshot、snapshot-force-create、snapshot-cleanup、snapshot-delete、backup、backup-force-create、filesystem-trim、system-backup |
另外,当前 CRD 还提供了retentionPolicy(默认count-based,可选age-based)与retainAge(Go duration 字符串,如10m、24h、8760h)字段,实现基于快照/备份年龄的过期清理。需要留意的是:age-based保留策略与snapshot-delete/snapshot-cleanup任务互斥,校验会直接拒绝task: snapshot-delete配合retentionPolicy: age-based的组合,详见 enhancements/20260819-age-based-retention-for-recurring-jobs.md 的约束表。
将任务绑定到卷
RecurringJob本身是集群级定义,需要通过标签机制挂到具体卷或 StorageClass 上(源自 label-driven recurring job 设计):
- 卷标签引用单个任务:
recurring-job.longhorn.io/<JobName>: enabled; - 卷标签引用任务分组:
recurring-job-group.longhorn.io/<GroupName>: enabled; - 任务处于
default分组时,会对没有配置任何任务标签的卷自动生效; - StorageClass 侧通过
persistence.recurringJobSelector配置(enable: true时以jobList指定任务名或分组名,例如[{"name":"backup", "isGroup":true}]),见 chart/README.md。
绑定完成后,调度器会为每个 RecurringJob 生成对应的 Kubernetes CronJob,按cron表达式周期触发。
底层执行流程:从源码设计看实现
设计文档明确了两个任务的执行路径都收敛到同一套清理函数,差异只在"输入的快照清单"。
snapshot-delete 执行链
- 枚举过期快照:列出卷上所有已过期快照,逻辑与既有
listSnapshotNamesForCleanup实现一致; - 构造清理清单:将上述快照名作为
cleanupSnapshotNames传入清理入口doSnapshotCleanup; - 执行 purge:沿用既有的 purge 实现,将标记删除的快照数据彻底清除,释放存储空间。
snapshot-cleanup 执行链
仅调用doSnapshotCleanup执行 purge 步骤,且清理对象限定为系统/可移除快照——因此无需快照枚举与保留数比较,retain无任何作用。
RecurringJob Mutate 规则
控制器的 mutate(变更)逻辑会在任务类型为snapshot-cleanup时,将spec.retain强制改写为 0,以避免用户误以为设置了保留数会影响清理结果。
从源码结构看,
listSnapshotNamesForCleanup与doSnapshotCleanup是清理管线的核心构件,两类任务通过复用同一 purge 流程保证了清理行为的一致性与可测试性。
相关全局设置与空间管理
快照清理并非孤立功能,实际部署时可配合以下 Longhorn 全局设置(均可在 chart/README.md 及 chart/questions.yaml 中配置):
recurringJobMaxRetention:单个 RecurringJob 允许保留的快照/备份最大数量上限;snapshotMaxCount:卷允许的最大快照数量(2~250,默认 100),超出会触发TooManySnapshots卷条件告警,与snapshotCountWarningThreshold配合使用;autoCleanupRecurringJobBackupSnapshot:是否自动清理由定时备份任务生成的快照;allowRecurringJobWhileVolumeDetached:卷处于分离状态时是否自动挂载以执行定时任务;snapshotHeavyTaskConcurrentLimit:每节点并发执行的快照重任务(如 purge、clone)数量上限,清理任务同样受此限流保护。
一个典型的空间治理组合是:snapshot-delete(retain=2)负责兜底回收所有来源快照 +snapshot-cleanup(按天调度)负责清扫系统残留 + 全局snapshotMaxCount作为最后防线。
测试计划:如何验证清理行为
设计文档给出了两条可复现的验证路径(适用于本地测试集群):
验证 snapshot-delete
- 创建卷;
- 创建 2 个卷备份;
- 创建 2 个手动快照;
- 创建
task: snapshot-delete的 RecurringJob(保留数自定); - 将任务绑定到卷;
- 等待定时任务完成;
- 检查卷上快照数量,应恰好等于 RecurringJob 的
spec.retain。
验证 snapshot-cleanup
- 创建卷;
- 制造 2 个系统快照(例如删除一个副本、执行一次在线扩容);
- 创建
task: snapshot-cleanup的 RecurringJob; - 将任务绑定到卷;
- 等待定时任务完成;
- 检查卷上系统快照数量应为 0,同时手动快照不受影响。
演进与注意事项
- 发布节点:该能力随 v1.5.0 一并发布,升级前请确认目标版本 ≥ v1.5.0;
- 与卷组快照的交互:后续的卷组快照设计(enhancements/20260811-volume-group-snapshot.md)明确说明,
snapshot-delete的 retain 计数作用于卷上的每一个快照,因此它可能将组内成员快照老化清除并导致快照组进入 Degraded 状态——这是刻意保留的硬性保留上限行为,防止被遗忘的组拖住快照导致snapshot-max-count触顶后新快照创建失败; - 与 age-based 策略的互斥:
snapshot-delete/snapshot-cleanup不接受age-based保留策略,配置前请检查 RecurringJob 的retentionPolicy字段。
总结
snapshot-delete与snapshot-cleanup补齐了 Longhorn 定时任务在"快照回收"维度上的能力拼图:前者以保留数为准绳统一回收所有来源快照,后者定向清扫系统快照残留。结合卷标签绑定、StorageClass 选择器与全局空间阈值设置,你可以将快照生命周期管理完全自动化,避免手动清理的运维负担与空间浪费。
- 云原生
- 存储
- 高可用
- 容器编排
【免费下载链接】longhorn
Cloud-Native distributed storage built on and for Kubernetes
相关推荐
Device Mapper 快照支持(snapshot / snapshot-origin / snapshot-merge)内核机制与 LVM2 实战指南
Device Mapper 快照支持(snapshot / snapshot origin / snapshot merge)内核机制与 LVM2 实战指南 D
操作系统内核驱动驱动开发虚拟化嵌入式网络存储Longhorn 扩展 CSI Snapshot 支持集群内 Longhorn 快照:设计原理、配置实战与验证指南
Longhorn 扩展 CSI Snapshot 支持集群内 Longhorn 快照:设计原理、配置实战与验证指南 本指南以 Longhorn 增强设计文档 e
云原生存储高可用容器编排AVA Snapshot Workflow 实战:移除快照断言时数据的清理与保留机制
AVA Snapshot Workflow 实战:移除快照断言时数据的清理与保留机制 导读 在 AVA 测试框架中,快照(snapshot)文件与测试代码的生命
测试
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考