Kubernetes集群备份与恢复实战:etcd快照与Velero配置指南
2026/9/11 5:49:44 网站建设 项目流程

很多人觉得 Kubernetes 这层壳子自带“描述即恢复”的能力,YAML 还在,资源就能重建,所以备份需求被一拖再拖。直到某天误删了 namespace、etcd 数据目录损坏、或者同事把生产环境的 PV 捅了个洞,才发现集群崩起来毫无预警,而“重建一个一样的集群”这句话远比听起来复杂。我在维护生产集群时吃过这种亏,后来把备份恢复从“有空再弄”变成了基础设施的一部分。这篇内容围绕 Kubernetes 集群备份与恢复的整套配置思路和实操过程来写,会讲清楚到底要备份哪些东西、工具怎么选、命令怎么敲、以及恢复时最常踩的坑。适合刚接触 Kubernetes 资源管理、也在规划容灾方案的运维和平台工程师参考,看完可以直接照着配。

1. 先定备份边界:集群里哪些数据丢了会出大事

配置备份之前,最容易犯的错误是“不知道该备份什么”。Kubernetes 集群的状态构成大概可以拆成三层:控制面状态、应用编排状态、业务数据。这三层分别在 etcd、API Server 里的资源对象、以及持久卷里,性质完全不同,恢复手段也完全不同。

1.1 控制面状态在 etcd 里,这是一切的地基

etcd 是 Kubernetes 控制面的唯一存储。集群里所有资源对象——namespace、Node、Pod、Service、ConfigMap、RBAC 规则、CRD 实例——最终都以键值对的形式存在 etcd 里。etcd 一旦损坏,整个集群就处于“看得见摸不着”的状态:kube-apiserver 可能起不来,节点调度信息全部丢失,内部 DNS 和网络策略也会跟着错乱。我见过一次 etcd 数据目录所在磁盘被写满的场景,集群进入只读状态,所有变更请求超时,最后只能靠快照恢复。

etcd 备份的本质就是把 key-value 数据完整导出一份。它不像 MySQL 那样有 binlog 可以精准回放到某个事务,etcd 的快照是某个时间点的全量状态。实际操作中一般用etcdctl snapshot save生成一个.db文件,恢复时再用snapshot restore把它还原到一个指定数据目录。所以在备份设计方案里,etcd 快照必须是频率最高、优先级最高的一层。

1.2 声明式资源不等于备份,应用配置是最容易被低估的资产

Kubernetes 的声明式设计给很多人造成一种错觉:所有配置都写成了 YAML,Git 里存一份,丢了也能重新 apply 回去。这个想法在理想状态下没错——但现实里,生产集群中的资源来源非常混乱:有人用kubectl create直接创建、有人在 Helm Chart 里改了 values 但没提交、有人用kubectl edit临时改过 Deployment 的参数。这些没有落入版本库的“漂移配置”,在集群事故后根本无处找回。

所以,资源对象的备份本质上是对“代码仓库之外”的兜底。Velero 这类工具会把 namespace 下的 Deployment、Service、ConfigMap、Secret、PVC 声明等全部导出为 JSON/YAML,并连同 PV 快照一起归档。这层备份的价值在于,不需要去翻 Git 历史核对每一处改动,恢复时直接把集群状态拉回到某个时间点。

1.3 业务数据在 PV 里,这层丢失才是真正的灾难

etcd 和资源清单搞定了,也只恢复了“空壳”。应用的实际业务数据——数据库文件、上传图片、日志归档——都存在 PV 背后的存储里。云环境里通常是云盘(EBS、云硬盘一类),自建机房可能是 Ceph RBD、NFS 或本地盘。Kubernetes 本身不负责数据备份,它只负责把 PV 挂载到 Pod 里。

也就是说,如果 PV 底层存储出了问题,Kubernetes 的 etcd 快照和资源备份都帮不上忙。这一层要么依赖云厂商的快照能力,要么在对象存储层面做周期归档,要么用 Velero 集成的 Restic/Kopia 把 PV 数据直接备份到对象存储。分层设计时,必须把“业务数据备份”单独拎出来作为一等公民,而不是混在资源备份里顺带处理。

2. 工具选型逻辑:Velero 兜底、etcdctl 保命、对象存储做底座

市面上做 Kubernetes 备份的工具不少,但我实际用下来,真正经得起生产环境考验的组合很固定:Velero 管资源对象和 PV 数据,etcdctl 管控制面状态,对象存储作为统一备份底座。三者职责不同,互相不能替代。

2.1 Velero 解决的是资源对象和 PV 数据的“捞回”问题

Velero 是目前社区里最主流的 Kubernetes 备份/恢复工具,它直接调用 Kubernetes API 读取资源对象,并通过插件对接各家云存储或自建 S3 兼容存储。Velero 的优势在于,它不是简单执行kubectl get -o yaml,而是会把资源之间的依赖关系一起处理。比如恢复一个 Deployment 时,它会先把关联的 ConfigMap、Secret、PVC 声明先恢复,再创建工作负载,避免因为依赖缺失导致 Pod 调度失败。

另外 Velero 的 Restic 集成能直接把 PV 里的文件备份到对象存储,不依赖底层存储快照接口。这对于自建集群或者使用本地存储的场景非常关键。我的实际经验是:如果业务数据本身量不大(几百 GB 以内),Restic 的方式最简单,一个 Velero 就能同时搞定资源和数据两层备份;如果 PV 数据是 TB 级的数据库,那优先用云盘快照或数据库自身的备份机制,Velero 只负责备份资源对象。

2.2 etcdctl 解决的是控制面整体崩溃的“保命”问题

Velero 备份的是 API Server 视角下的资源状态,它无法备份 etcd 里更底层的内部数据——比如某个资源对象的历史版本、集群内部的 Lease 信息、etcd 自身的元数据。如果整个集群的 etcd 数据目录被误删或者数据损坏,Velero 的备份也救不了,因为 API Server 可能根本起不来,Velero 连不上集群。

这时候就必须依赖 etcd 快照。etcdctl 是 etcd 自带的命令行工具,用法简单直接,但对集群稳定性影响很大,一定要在非高峰时段执行。生产环境中我通常把 etcd 快照的频率设在每天一次,并在集群发生重大变更(比如升级 Kubernetes 版本、修改集群级 RBAC、调整网络插件配置)前手动触发一次。整个集群恢复路径中,etcd 快照是最底层的保命手段。

2.3 备份介质选型直接决定恢复速度

备份放在哪,很多人最后才会想。实际上,这会直接影响 RTO(恢复时间目标)。如果备份直接存在集群本地磁盘,那么集群挂了备份也随之中断,等于没有备份。生产环境的最低要求是:备份数据必须存放在独立于集群故障域的位置。

我自己的方案是建一个独立的 S3 兼容对象存储,Velero 的备份文件和 Restic 的数据归档都写到那里。etcd 快照则用脚本生成后,通过s3cmdaws cli同步到对象存储。这样做有两个好处:一是集群全挂时备份仍然完好;二是恢复新集群时可以直接从对象存储拉取备份,不需要额外搭中转机器。如果公司已有 MinIO、Ceph RGW 或者云厂商的对象存储服务,直接复用即可,成本几乎为零。

3. 从配置到落盘:Velero 安装、定时备份、etcd 快照实操

工具选型只是第一步,真正的价值在于把备份流程固化下来。这一部分给出一套经过生产验证的配置路径,包括 Velero 安装、备份计划创建、etcd 快照脚本化和数值参数说明,照着操作就能搭出基础备份体系。

3.1 Velero 安装与配置:几个容易出错的细节点

Velero 的安装本身不复杂,核心是安装 CLI 工具和初始化服务端。以对接 S3 兼容对象存储为例,先准备好访问凭证文件,格式如下:

[default] aws_access_key_id = YOUR_ACCESS_KEY aws_secret_access_key = YOUR_SECRET_KEY

然后执行安装命令:

velero install \ --provider aws \ --bucket k8s-backups \ --secret-file ./credentials-velero \ --backup-location-config region=us-east-1,s3ForcePathStyle=true,s3Url=https://minio.example.com \ --snapshot-location-config region=us-east-1 \ --plugins velero/velero-plugin-for-aws:v1.9.0

这里有两个细节容易踩坑。一是如果用的是自建 MinIO 这类 S3 兼容服务,必须加上s3ForcePathStyle=trues3Url,否则 Velero 会把请求发到桶名.域名格式的地址,连不上服务。二是--snapshot-location-config即使不打算做云盘快照也要配置,因为 Velero 初始化时如果缺少快照位置配置,某些版本会报错或者备份任务卡在等待状态。

安装完成后,可以用下面命令验证服务端是否正常:

velero backup create test-backup --include-namespaces default velero backup describe test-backup

看到Phase: Completed说明安装配置已经通了。第一次跑通之后,再调整备份范围。

3.2 创建定时备份计划:参数怎么定才合理

手工执行velero backup create只是验证流程,真正要落地的是定时任务。Velero 提供了velero schedule来创建周期备份:

velero schedule create daily-backup \ --schedule="0 2 * * *" \ --include-namespaces default,production \ --ttl 168h \ --default-volumes-to-restic

解释几个关键参数:

  • --schedule:Cron 表达式,0 2 * * *表示每天凌晨 2 点执行。选择凌晨是为了避开业务高峰,避免备份任务占用过多 API Server 资源和磁盘 IO。
  • --include-namespaces:指定要备份的命名空间,不要图省事直接全集群备份。全集群备份会把 kube-system、监控、日志等非业务资源也打进去,备份文件体积大、恢复时干扰多。我在实际项目中只备份业务命名空间,系统组件交给 etcd 快照兜底。
  • --ttl 168h:备份保留时长,7 天。个人建议至少保留 30 天,设置更长为720h,防止某些数据问题在一周后才被发现。
  • --default-volumes-to-restic:开启 Restic 卷数据备份。如果 PV 数据量大,可以先用云盘快照,这里通过--volume-snapshot-locations或者标签选择器精细控制哪些 PV 要备份。

创建之后,Velero 会自动创建 CronJob 来触发备份。可以通过velero schedule get查看当前所有计划,用velero backup get查看每次执行结果。

3.3 etcd 快照的自动化脚本与存储策略

etcd 快照我建议写成定时脚本,配合 systemd timer 或者 Cron 执行。以 kubeadm 部署的集群为例,脚本核心部分如下:

#!/bin/bash set -euo pipefail BACKUP_DIR="/backup/etcd" DATE=$(date +%Y%m%d-%H%M%S) SNAPSHOT_FILE="${BACKUP_DIR}/etcd-snapshot-${DATE}.db" ETCDCTL_API=3 etcdctl \ --endpoints=https://127.0.0.1:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key \ snapshot save "${SNAPSHOT_FILE}" # 同步到独立对象存储 s3cmd put "${SNAPSHOT_FILE}" s3://k8s-backups/etcd/ # 只保留最近 7 份本地快照 ls -t ${BACKUP_DIR}/etcd-snapshot-*.db | tail -n +8 | xargs -r rm --

三个注意点:

  1. etcdctl 访问 etcd 时,证书路径必须准确。kubeadm 集群的 etcd 证书一般都在/etc/kubernetes/pki/etcd/目录下,如果是二进制安装或者其他方式部署的集群,路径可能不同,需要根据实际情况调整。
  2. snapshot save执行时会对 etcd 产生一定压力,建议设置超时时间,比如--command-timeout=30s,避免命令挂住。
  3. 本地快照只是临时的,必须同步到对象存储。我见过太多人只做了本地快照,结果 etcd 节点磁盘崩溃,备份也跟着报废。

除了每日定时快照,重大操作前一定要手动执行一次。所谓重大操作包括:升级 Kubernetes 版本、修改 etcd 参数、变更网络插件、大批量清理资源。这些场景下,如果操作失败需要回滚,刚生成的快照会把回滚窗口缩到最小。

4. 恢复实操:Velero 单命名空间恢复和 etcd 全集群恢复

备份做得再漂亮,恢复不验证等于白做。这一部分是我认为整篇最有价值的地方:分别演示 Velero 级别的恢复、etcd 级别的恢复流程,以及恢复过程中常见的失败原因和处理思路。所有这些步骤我都至少在测试环境完整演练过三遍以上,生产环境也实际执行过两次恢复操作。

4.1 Velero 恢复命名空间:从备份列表中捞回业务

场景:某个业务命名空间里的资源被误删,Deployment、Service、ConfigMap 全部消失,但 PV 数据还在。这种情况下,用 Velero 恢复即可。

先查看现有备份:

velero backup get

找到目标备份名称后,执行恢复:

velero restore create --from-backup daily-backup-20250110 \ --include-namespaces production \ --namespace-mappings production:production-restored

如果没有特别指定--namespace-mappings,Velero 会直接恢复原命名空间。我习惯在恢复到生产环境时先映射到一个临时命名空间,确认资源状态没问题后,再迁移回原命名空间,避免误恢复覆盖当前实际数据。临时恢复的命令:

velero restore create --from-backup daily-backup-20250110 \ --include-namespaces production \ --namespace-mappings production:production-check

恢复完成后,先检查 Pod 是否正常调度、PVC 是否绑定、Service 的 Endpoint 是否有就绪端点。因为 PV 数据在底层存储里,PVC 绑定成功不等于应用可用,必须确认挂载正常。

4.2 etcd 快照恢复整个集群:冷恢复的完整链路

整个集群挂了,或者 etcd 数据损坏,就轮到 etcd 快照出马。恢复的过程会比 Velero 重得多,需要谨慎操作。

在单节点 etcd 场景(比如测试环境)中,恢复流程是:

  1. 停止所有控制面组件,包括 kube-apiserver、kube-controller-manager、kube-scheduler,以及 etcd 服务本身。
  2. 把损坏的 etcd 数据目录备份到一个临时位置,以防万一。
  3. 用快照恢复出一个新数据目录:
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-snapshot-20250110-020000.db \ --data-dir=/var/lib/etcd-restored
  1. 修改 etcd 的配置,让数据目录指向新生成的/var/lib/etcd-restored,然后启动 etcd。
  2. 确认 etcd 健康:etcdctl endpoint health
  3. 依次启动其他控制面组件,确认集群恢复正常。

这里最关键的是:很多人在第 4 步忘了改配置,直接重启 etcd,结果 etcd 还是去读旧数据目录,恢复等于白做。kubeadm 集群的话,还需要检查 etcd 的 static pod manifest 里的hostPath指向,确认是恢复后的数据目录。

4.3 恢复失败排查:几个我实际碰过的问题

恢复环节的问题比备份环节多得多。列几个高频的失败场景:

场景一:恢复后 Pod 一直 Pending

原因大概率是 PVC 没有绑定成功,或者节点资源不足。先看 PVC 状态:kubectl get pvc -n <namespace>,如果 PVC 还是 Pending,说明 PV 的claimRef可能还有残留。解决方式是把旧 PV 的claimRef清空,让 PVC 重新绑定。这个操作需要小心,做之前一定要确认 PV 里的数据完好。

场景二:Velero 恢复时卡在 InProgress 超过 10 分钟

第一种可能是对象存储权限不对,Velero 无法读取备份文件。第二种可能是集群里有大量小文件资源,API Server 处理不过来。第三种比较隐蔽——某个自定义资源的 CRD 被删除过,Velero 在恢复该 CRD 的实例对象时找不到对应 CRD 类型,任务卡住。排查时可以看 Velero 服务端日志:

kubectl logs -n velero deployment/velero --tail=100

日志里一般会直接打印出卡住的原因,顺着关键词去查就行。

场景三:etcd 恢复后集群状态跟备份时不一样

快照只恢复备份时刻的状态,备份之后发生的变更全部丢失。这不是故障,而是快照机制本身的特性。所以在恢复前要确定可以接受的数据丢失量,如果要求秒级恢复,必须配合专业的数据层解决方案,而不是指望 etcd 快照。

5. 验证备份的有效性:没有演练过的备份只是心理安慰

备份体系搭起来之后,有一项工作很多人没做,但它比埋头配置更重要——定期做恢复演练。我见过太多团队备份任务天天显示 Completed,真到恢复的时候才发现备份文件权限不对、对象存储的 bucket 被误删、Velero 版本升级后插件不兼容,等等。没有演练过的备份只是心理安慰。

5.1 恢复演练的操作清单与验证标准

我的做法是每季度在测试环境做一次完整的恢复演练。流程包括:

  1. 启动一个全新的 Kubernetes 测试集群,保证它和生产集群处于同一版本,网络插件、存储插件保持一致。
  2. 在测试集群上安装 Velero,使用同一套对象存储配置。
  3. 从生产备份中选择一个最近的全量备份,恢复到测试集群。
  4. 验证核心业务的完整性:Deployment 副本数、Pod 状态、Service 访问、PV 数据文件数量。
  5. 记录恢复耗时,从中评估 RTO。

演练结束后,写一份简短的恢复报告,重点记录“从备份到恢复所需时间”和“恢复后与备份前是否存在差异”。这份报告是后续优化备份频率、调整备份保留周期的重要依据。

5.2 备份保留策略:版本化、异地冗余与成本平衡

备份文件的保留策略需要兼顾成本和安全性。每天一份全量备份,保留 30 天,成本在对象存储里通常可以接受。但要注意,备份文件本身也是数据,也需要防误删。我给对象存储开启版本控制,这样即使不小心覆盖或者删了当前版本的备份文件,也能从历史版本里找回。

另外,如果条件允许,把备份同步到另一个机房/地域的对象存储,形成异地冗余。集群级灾难往往伴随着机房故障,同机房备份可能在灾难中一并消失。异地冗余的配置方式很简单,比如用 Velero 的 BackupStorageLocation 配置两个 bucket,或者通过对象存储的跨区域复制功能自动同步。

5.3 从备份体系到自动化:监控、告警与故障自愈

备份恢复体系最后的形态应该是:备份任务自动跑、失败有告警、恢复有脚本。Velero 的备份任务可以通过velero schedule的 CronJob 触发,但任务失败时默认不会主动通知人。我的做法是写一个定时巡检脚本,检查velero backup get输出中是否有失败记录,如果有就通过 Webhook 发到企业内部通知群。

告警之外,值得做的是把恢复流程脚本化。把第 4 节里 etcd 恢复的操作步骤封装成脚本,参数化快照文件路径、数据目录、etcd 端点,这样即使是新人也能在出事时按照脚本快速执行,而不是临场去查文档。我自己的恢复脚本里,每一步都会打印当前状态,并在关键操作前要求人工确认,避免脚本自动执行覆盖了不该覆盖的数据。

最后几句实在话

备份恢复这件事,功夫全在平时。配置一套备份体系可能只需要半天,但让它持续可靠地运转,靠的是对每一次备份日志的关注、对恢复流程的反复演练、以及对备份文件的妥善保管。我在实际项目中见过太多人把精力花在花哨的监控大屏上,反而忽略了最基础的备份恢复。希望这篇内容能帮你把 Kubernetes 集群备份从“有空再弄”变成“已经配好并且验证过”。祝你的集群永不宕机,备份永不失效。

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

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

立即咨询