2. Velero架构与核心组件

理解 Velero 的关键,不是记住一堆 CRD 名字,而是看清两条主线:一条是控制面——由 Server 中的控制器监听各类自定义资源(CR),驱动备份、恢复、定时任务的编排;另一条是数据面——由 Node Agent 在节点上以 DaemonSet 形式运行,通过 Restic 或 Kopia 把卷数据搬进对象存储。控制面决定“做什么、什么时候做、记录什么状态”,数据面决定“卷里的字节怎么走”。两者通过 Backup、Restore、PodVolumeBackup 等对象的状态字段协同。

控制面:Server 与控制器循环

Velero Server 是一个常驻 Deployment,内部注册了多组控制器(controller-runtime 风格)。它启动后主要做三件事:监听 CR 变化、调用云厂商插件、把执行进度写回 CR 的 status。核心对象与职责如下:

  • Backup:一次备份的声明与结果载体。创建后由 BackupController 接管,依次执行资源发现、API 对象序列化、卷快照或文件级备份、上传、状态收敛。
  • Restore:一次恢复的声明。RestoreController 按备份内容重建命名空间、CRD、工作负载,并处理卷数据回填。
  • Schedule:基于 Cron 表达式的定时器。ScheduleController 到点后创建 Backup 对象,本身不直接搬数据。
  • BackupStorageLocation(BSL):描述对象存储位置,如 S3 桶、前缀、region、凭证 Secret。它决定备份元数据和 Restic/Kopia 仓库写到哪里。
  • VolumeSnapshotLocation(VSL):描述云盘快照能力,如 AWS region、Azure 资源组。它只在“快照式卷备份”路径上生效。

这里有一个容易混淆的点:BSL 与 VSL 是能力声明,不是执行者。真正执行的是 Server 内的控制器和插件。BSL 的 status.phase 会显示 Available 或 Unavailable,这是判断备份能否落盘的第一道检查。VSL 则决定 snapshot 类型卷备份是否可用;如果集群没有对应 CSI 快照或云盘插件,VSL 即使创建成功也无法产出快照。

数据面:Node Agent 与 Restic/Kopia

Node Agent 以 DaemonSet 部署,每个节点一个 Pod。它监听两类任务:PodVolumeBackup 和 PodVolumeRestore。当 Backup 中某个 Pod 的卷被标记为文件级备份(例如通过 backup.velero.io/backup-volumes 注解指定),Server 会为每个卷创建 PodVolumeBackup,Node Agent 收到后挂载对应卷路径,调用 Restic 或 Kopia 把数据写入 BSL 指向的仓库。

Restic 与 Kopia 是两种可选的文件级备份引擎。Restic 是 Velero 早期默认方案,仓库格式成熟;Kopia 在较新版本中作为可选上传器,支持更细的并发与内容去重。二者都通过 --uploader-type 在安装时选择,且同一集群内应保持一致,否则恢复时可能找不到对应仓库。它们不负责 API 对象备份,只负责卷内文件。

判断卷走哪条路径:若卷类型是云盘/CSI 且 VSL 可用,优先走快照;若卷是 emptyDir、hostPath、NFS 或未配置快照,则走 Restic/Kopia 文件级备份。两者可以混用,但同一卷不会同时走两条路径。

对象协作与状态流转

下面这张图把控制面对象、数据面组件和存储位置放在同一张关系图里,重点表达“谁创建谁、谁驱动谁、数据往哪走”。

控制面 · Velero Server Schedule Backup Restore BackupController / RestoreController ScheduleController · PodVolumeBackupController BackupStorageLocation 对象存储位置 · 元数据+仓库 VolumeSnapshotLocation 云盘快照能力 · region 数据面 · Node Agent (DaemonSet) PodVolumeBackup 每卷一个任务对象 PodVolumeRestore 恢复时回填卷 Restic / Kopia 上传器 挂载卷路径 → 分块去重 → 写入仓库 节点本地卷路径 /var/lib/kubelet/pods/<uid>/volumes/... 创建任务 对象存储(由 BSL 指向) 备份元数据 backups/<name>/ Restic/Kopia 仓库 restic/ 或 kopia/ 卷快照引用 snapshots/<id> 图例 控制指令 数据流 落盘位置

一次备份的完整链路

以“每天 02:00 备份 prod 命名空间,卷走 Kopia 文件级备份”为例,链路如下:Schedule 到点创建 Backup;BackupController 读取 BSL 确认可用,调用 API 列出 prod 下所有对象并序列化为 JSON 写入对象存储的 backups/<name>/;对带注解的 Pod 卷,Server 创建 PodVolumeBackup;对应节点的 Node Agent 收到后调用 Kopia,把卷内容写入 kopia/ 仓库;全部完成后 Backup 的 status.phase 变为 Completed,并记录 itemsBackedUp、errors、warnings 等计数。

恢复时顺序相反:RestoreController 读取备份元数据,先重建命名空间和 CRD,再创建 PodVolumeRestore,由 Node Agent 从仓库拉取数据回填到目标卷,最后恢复工作负载。若 BSL 不可达,Backup 会停在 InProgress 或 PartiallyFailed;若 VSL 缺失但卷被标记为快照,则对应卷会记录错误并降级或跳过。

关键判断与常见误区

观察点正常表现异常含义
BSL status.phaseAvailableUnavailable:凭证、桶权限或网络问题
Backup status.phaseCompletedPartiallyFailed:部分资源或卷失败,需看 errors
PodVolumeBackup 数量与注解卷数一致缺失:Node Agent 未就绪或注解未生效
上传器类型集群内统一混用 Restic/Kopia 会导致恢复找不到仓库
BSL 和 VSL 只是“位置与能力声明”,不执行备份。真正搬数据的是 Node Agent 中的 Restic/Kopia;真正编排的是 Server 中的控制器。排障时先看 BSL 是否 Available,再看 Backup 的 status 与 PodVolumeBackup 的日志,顺序不要颠倒。

把对象、控制器、数据面三者的关系理清后,后续配置 BSL/VSL、选择上传器、编写 Schedule 时,就能预判每一步会影响哪条链路,而不是盲目试错。