Skip to content

etcd 备份恢复

etcd 是所有 K8s 资源对象的数据库。Node、Pod、Service、Secret、ConfigMap、RBAC、Deployment、StatefulSet——这些对象全部存在 etcd 里。业务数据库(MySQL、Redis)、对象存储、PV 后端的真实数据不在 etcd 里。etcd 快照恢复的是 K8s 资源对象,不恢复业务数据。

恢复 etcd 是把集群所有资源对象回退到快照时间点。这不是普通的回滚命令,是控制平面的灾难恢复动作——快照之后创建、修改、删除的 K8s 对象都会消失。

etcd 在哪里

kubeadm stacked 集群里,etcd 是以静态 Pod 形式跑在控制平面节点上的。kubelet 监测 /etc/kubernetes/manifests/etcd.yaml 这个文件,自动管理 etcd 容器:

bash
kubectl -n kube-system get pods -l component=etcd -o wide
ls /etc/kubernetes/manifests/etcd.yaml
ls /etc/kubernetes/pki/etcd

关键路径:

路径内容
/var/lib/etcdetcd 数据目录(Raft 日志、snapshot、DB 文件)
/etc/kubernetes/pki/etcdetcd 专用证书:CA、server、peer、healthcheck-client
/etc/kubernetes/manifests/etcd.yaml静态 Pod manifest
/etc/kubernetes/manifests/kube-apiserver.yamlapiserver 静态 Pod manifest

静态 Pod 的特性:manifest 文件被挪出目录,kubelet 停止对应容器;放回去,kubelet 重新启动。恢复过程中需要短暂停止控制平面组件,用的就是这个机制——不是 kill 进程,而是 mv manifest 文件。

etcdctl 和 etcdutl 的分工

etcd 3.5 之后工具分工更明确了:

工具用途使用场景
etcdctl通过网络访问 etcd 集群健康检查、成员管理、在线快照
etcdutl直接操作 etcd 数据文件快照恢复、数据校验、DB 分析

etcdctl snapshot restore 在 3.5 后已不推荐,恢复用 etcdutl snapshot restore。旧文档里很多还在用 etcdctl restore,看到时要留意版本。

快照备份

在线创建快照用 etcdctl snapshot save。在任一台健康的控制平面节点上执行,证书直接引用 kubeadm 生成的 etcd 证书:

bash
mkdir -p /backup/etcd

ETCDCTL_API=3 etcdctl snapshot save /backup/etcd/etcd-$(date +%F-%H%M%S).db \
  --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

验证快照文件可读:

bash
# status 输出 revision、key 数量、DB 大小——确认快照不是损坏文件
ETCDCTL_API=3 etcdctl snapshot status /backup/etcd/etcd-2026-05-22-120000.db -w table

快照文件里有全量 Secret 和 ConfigMap 等敏感数据,权限和传输要做保护:

bash
chmod 600 /backup/etcd/*.db
sha256sum /backup/etcd/*.db > /backup/etcd/SHA256SUMS

只存在控制平面本机风险很高。系统盘坏掉时,本机快照也一起没了。快照文件至少要同步到备份机或对象存储,保留校验值用于验证传输完整性。

quorum 和成员管理

etcd 用 Raft 协议,超过半数成员存活集群才能正常读写:

成员数quorum允许同时故障
110
321
532

三成员坏一个:是常规运维,移除坏成员,加新成员补位。三成员坏两个(quorum 丢失):进入灾难恢复,从快照重建 etcd 集群。处理方式完全不同。

查看成员列表和状态:

bash
ETCDCTL_API=3 etcdctl member list \
  --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

# endpoint status 能看到 leader、DB 大小、raft index
ETCDCTL_API=3 etcdctl endpoint status -w table \
  --cluster \
  --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

恢复前先确认

etcd 恢复之前,有几项信息必须先搞清楚——不是背下来,是动手前必须对照确认的:

项目为什么要确认
快照时间点恢复后,快照之后创建或改动的 K8s 对象全部不存在了
集群拓扑单控制平面、stacked 多控制平面、外置 etcd 的操作不一样
apiserver 状态恢复期间 apiserver 必须停掉,否则继续基于旧状态读写
PV 和业务数据etcd 快照不恢复业务数据,对象和数据的时间点可能不一致
证书和节点标识etcd peer 通信靠证书 SAN、节点名和 IP
当前故障类型成员故障 vs 数据损坏 vs 误删对象 vs 控制平面全毁,处理各自不同

误删了一个 Deployment 时,去 GitOps、Helm history、审计日志或 YAML 备份里找回来,影响面远小于恢复整个 etcd。恢复整个 etcd 之后,所有 namespace、所有对象回到快照时间点——这不只是把删掉的 Deployment 找回来。

单控制平面恢复

单控制平面假设快照文件在 /backup/etcd/etcd.db,etcd 数据目录在 /var/lib/etcd

第一步:停止控制平面。挪走静态 Pod manifest,kubelet 自动停掉对应的容器:

bash
mkdir -p /root/k8s-manifests.bak

# apiserver 必须先停,避免恢复期间继续往旧 etcd 写数据
mv /etc/kubernetes/manifests/kube-apiserver.yaml /root/k8s-manifests.bak/
mv /etc/kubernetes/manifests/kube-controller-manager.yaml /root/k8s-manifests.bak/
mv /etc/kubernetes/manifests/kube-scheduler.yaml /root/k8s-manifests.bak/
mv /etc/kubernetes/manifests/etcd.yaml /root/k8s-manifests.bak/

确认容器已停止(kubectl 不可用,从节点本地查):

bash
crictl ps -a | grep -E 'kube-apiserver|kube-controller-manager|kube-scheduler|etcd'

第二步:恢复数据目录

bash
# 先备份旧数据目录,万一恢复出问题还能回退
mv /var/lib/etcd /var/lib/etcd.bak.$(date +%F-%H%M%S)

# etcdutl 从快照生成新数据目录
etcdutl snapshot restore /backup/etcd/etcd.db \
  --data-dir=/var/lib/etcd

chown -R root:root /var/lib/etcd

第三步:放回静态 Pod manifest。先起 etcd,再起其他组件:

bash
mv /root/k8s-manifests.bak/etcd.yaml /etc/kubernetes/manifests/
sleep 20  # 等 etcd 完全启动并选举 leader

mv /root/k8s-manifests.bak/kube-apiserver.yaml /etc/kubernetes/manifests/
mv /root/k8s-manifests.bak/kube-controller-manager.yaml /etc/kubernetes/manifests/
mv /root/k8s-manifests.bak/kube-scheduler.yaml /etc/kubernetes/manifests/

第四步:验证

bash
kubectl get nodes
kubectl get pods -A
kubectl get --raw='/readyz?verbose'

恢复完后重点核对:快照时间点之后新建的 namespace、Secret、Deployment、CRD 对象、证书等可能全部消失了。依赖这些对象的工作负载、入口规则、CI/CD 流程也要一起检查。

多控制平面恢复

多控制平面场景首先要区分故障类型:

场景处理方向
3 成员坏 1 个,quorum 还在从健康成员移除坏成员,补新成员
3 成员坏 2 个,quorum 丢失停掉所有 apiserver,从同一快照在三台节点上重建 etcd 集群
某成员数据目录损坏但 quorum 在优先替换该成员
所有控制平面都丢了从快照和证书重建控制平面,再恢复工作节点连接
外置 etcd先恢复外置 etcd 集群,再确认 apiserver 指向新 endpoints

从快照重建三成员 etcd 时,每台控制平面节点都用同一份快照文件,但 --name--initial-advertise-peer-urls--data-dir 按每台节点的实际值填写:

bash
# cp01 上执行;cp02/cp03 也执行同样的命令,但 name、peer URL 换成本机
etcdutl snapshot restore /backup/etcd/etcd.db \
  --name cp01 \
  --initial-cluster cp01=https://192.168.10.11:2380,cp02=https://192.168.10.12:2380,cp03=https://192.168.10.13:2380 \
  --initial-advertise-peer-urls https://192.168.10.11:2380 \
  --data-dir=/var/lib/etcd

恢复后 etcd 静态 Pod manifest 的 --initial-cluster--name--data-dir 要和上面完全对应,peer 证书的 SAN 也要包含正确的节点名和 IP。不同安装方式(kubeadm、Kubespray、二进制)生成的 manifest 参数不一样,适合提前给本集群写好三台控制平面的恢复 runbook,故障时只按验证过的命令执行。

常见故障分支

现象判断方向处理
context deadline exceededetcd 不可达、证书错误、端口被防火墙挡查 endpoint、证书路径、apiserver/etcd 的启动参数
x509: certificate 类错误证书 SAN 不包含当前 IP 或 hostname、CA 不匹配核对 /etc/kubernetes/pki/etcd 里的证书
无 leader(endpoint status 无 leader)quorum 丢失、网络分区、磁盘延迟过高member list 看成员数、endpoint status 对每个节点单独查
apiserver 起不来etcd endpoints 配置错、证书、数据目录直接从 crictl logs 看 apiserver 日志
恢复后 K8s 对象少了快照时间点产在对象创建之前从 GitOps/Helm/审计日志补差异
PV 对象在但数据不完整etcd 恢复了 PV 对象,真实数据可能被修改或删除按业务数据的时间点单独处理

控制平面日志在 kubectl 不可用时用 crictl 看:

bash
crictl ps -a | grep -E 'etcd|kube-apiserver'
crictl logs <etcd-container-id> | tail -100
crictl logs <apiserver-container-id> | tail -100

监控和告警

etcd 对磁盘延迟高度敏感。控制平面节点装慢的系统盘时,API 写入、调度和控制器同步全部变慢:

指标看什么
leader changes频繁切 leader 通常指向网络或磁盘延迟
fsync duration磁盘慢会导致 etcd 写盘慢,整个 apiserver 的写操作都受影响
backend commit duration写事务落盘延迟
DB sizeDB 过大影响读写性能、备份和恢复耗时
member health成员是否处于健康状态
NOSPACE alarmDB 触及空间上限,集群变为只读

查 alarm:

bash
ETCDCTL_API=3 etcdctl alarm list \
  --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

备份策略

项目建议
频率至少每天一次,变更频繁的集群可以半天
位置控制平面本机一份 + 远端备份机或对象存储一份
保留按天保留 7 天、按周保留 4 周、按月保留
权限快照文件 600,远程存储加密
校验保存 snapshot status 结果和 sha256sum
演练在隔离的测试集群上定期做恢复演练

一个基础备份脚本:

bash
#!/usr/bin/env bash
set -euo pipefail

backup_dir="/backup/etcd"
file="${backup_dir}/etcd-$(date +%F-%H%M%S).db"
mkdir -p "${backup_dir}"

ETCDCTL_API=3 etcdctl snapshot save "${file}" \
  --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

chmod 600 "${file}"
sha256sum "${file}" >> "${backup_dir}/SHA256SUMS"
ETCDCTL_API=3 etcdctl snapshot status "${file}" -w table

etcd 备份覆盖的是 K8s 资源对象这一层。StatefulSet 绑定的 PV 里如果存了数据库文件、文件存储、对象存储等业务数据,那些数据的备份是另外一条线——不属于 etcd 的范围。