Appearance
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/etcd | etcd 数据目录(Raft 日志、snapshot、DB 文件) |
/etc/kubernetes/pki/etcd | etcd 专用证书:CA、server、peer、healthcheck-client |
/etc/kubernetes/manifests/etcd.yaml | 静态 Pod manifest |
/etc/kubernetes/manifests/kube-apiserver.yaml | apiserver 静态 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 | 允许同时故障 |
|---|---|---|
| 1 | 1 | 0 |
| 3 | 2 | 1 |
| 5 | 3 | 2 |
三成员坏一个:是常规运维,移除坏成员,加新成员补位。三成员坏两个(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 exceeded | etcd 不可达、证书错误、端口被防火墙挡 | 查 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 size | DB 过大影响读写性能、备份和恢复耗时 |
| member health | 成员是否处于健康状态 |
| NOSPACE alarm | DB 触及空间上限,集群变为只读 |
查 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 tableetcd 备份覆盖的是 K8s 资源对象这一层。StatefulSet 绑定的 PV 里如果存了数据库文件、文件存储、对象存储等业务数据,那些数据的备份是另外一条线——不属于 etcd 的范围。