etcdctl snapshot save 生成、校验过完整性,并且与目标集群数据格式兼容的快照。本流程会停止所有控制平面节点的 kubelet,属于计划性停机操作。开始前要确认业务影响、维护窗口和决策人;工作节点无需停止,但如果业务仍在写外部系统,需另行冻结。
export ETCDCTL_API=3
export ETCDCTL_ENDPOINTS=https://127.0.0.1:2379
export ETCDCTL_CACERT=/etc/kubernetes/pki/etcd/ca.crt
export ETCDCTL_CERT=/etc/kubernetes/pki/etcd/server.crt
export ETCDCTL_KEY=/etc/kubernetes/pki/etcd/server.key
etcdutl snapshot status /backup/etcd.db --write-out=table
sha256sum -c /backup/etcd.db.sha256
快照的 revision、键数量和大小应与备份记录一致。不要用直接拷贝的 /var/lib/etcd 目录代替快照,运行中的 WAL 与 SST 文件可能不一致。
确认恢复工具与数据格式匹配。etcdutl 必须能读取目标快照,恢复时使用的参数要能复现集群拓扑。etcd 官方镜像不一定自带 etcdutl,宿主机上要提前准备好可用二进制。
记录当前拓扑和健康状态。只要 API 还能访问,就先留一份现场:
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 \
endpoint status --cluster -w table
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 \
member list -w table
kubectl get nodes -o wide
kubectl get ns
记录成员名、peer URL、集群 token、数据目录和证书路径。恢复时不能把不同快照、不同集群的成员混在一起。
检查证书、静态 Pod 清单和加密配置。快照只包含 etcd 数据,不包含 /etc/kubernetes/pki/etcd/、apiserver-etcd-client 证书,也不包含静态加密所用的 EncryptionConfiguration 与密钥。缺少这些文件,数据恢复成功也无法让控制面正常工作。提前从离线备份中取回,并核对文件权限。
检查磁盘空间、时间同步和端口。恢复会生成一份完整的新数据目录,至少需要与当前数据目录同量级的空闲空间;所有控制平面节点要保持时间同步,2379/2380 端口不能被旧进程占用。
冻结变更并通知相关方。停止发布、控制器调谐和自动化脚本,确认没有 CronJob 会在恢复窗口内重建被删对象。把维护窗口、恢复目标时点和回滚条件写进事故记录。
在每个控制平面节点上停止 kubelet,让 etcd、kube-apiserver、controller-manager 和 scheduler 全部退出:
sudo systemctl stop kubelet
sudo crictl ps | grep -E 'etcd|kube-apiserver|kube-controller-manager|kube-scheduler'
第二条命令应没有输出。不要只停一个节点就恢复,否则其他 apiserver 可能继续写入,造成恢复后数据再次分叉。
先保留现场,再准备空目录。禁止直接覆盖在线成员的数据目录:
sudo mv /var/lib/etcd /var/lib/etcd.pre-restore-$(date +%Y%m%d%H%M%S)
sudo install -d -m 0700 /var/lib/etcd
如果实际数据目录不是 kubeadm 默认路径,以静态 Pod 的 hostPath 为准。旧目录至少保留到验证完成,不要用 rm -rf 清理故障证据。
所有成员使用同一份快照、同一个集群 token,但各自的 --name、peer URL 必须不同。下面以三成员为例:
sudo etcdutl snapshot restore /backup/etcd.db \
--name cp-1 \
--data-dir /var/lib/etcd \
--initial-cluster cp-1=https://10.0.0.11:2380,cp-2=https://10.0.0.12:2380,cp-3=https://10.0.0.13:2380 \
--initial-cluster-token prod-etcd-restore \
--initial-advertise-peer-urls https://10.0.0.11:2380
在 cp-2、cp-3 上分别替换 --name 和 --initial-advertise-peer-urls。--initial-cluster 三台必须完全一致,token 也必须一致;命令中的 prod-etcd-restore 要换成静态 Pod 清单里原有的 --initial-cluster-token。单节点集群只恢复一个成员。
恢复完成后,按原数据目录的属主和属组修正权限:
sudo chown -R etcd:etcd /var/lib/etcd
sudo chmod 0700 /var/lib/etcd
若原环境以 root 运行 etcd,就不要改成 etcd 用户;以静态 Pod 清单和旧目录的实际属主为准。
确认以下文件存在且与快照来源匹配:
sudo ls -l /etc/kubernetes/pki/etcd/
sudo ls -l /etc/kubernetes/pki/apiserver-etcd-client.crt \
/etc/kubernetes/pki/apiserver-etcd-client.key
grep -n 'etcd-data\|--initial-cluster\|--initial-cluster-token' \
/etc/kubernetes/manifests/etcd.yaml
从离线归档恢复证书时,先查看包内路径,再解压到 /etc/kubernetes,避免覆盖无关的 apiserver 证书。静态 Pod 清单中的 hostPath 必须指向刚恢复的数据目录;如果恢复前改过目录,要同步改回。
启用了静态加密的集群,还要把 EncryptionConfiguration 及其密钥恢复到 apiserver 能读取的位置。只恢复 etcd 数据而没有加密密钥,Secret 会变成无法解密的内容。
在所有控制平面节点上启动 kubelet:
sudo systemctl start kubelet
sudo systemctl status kubelet --no-pager
sudo journalctl -u kubelet -n 80 --no-pager
先确认 etcd 静态 Pod 已启动,再检查成员状态。etcd 需要多数派才能对外服务,三成员集群至少要有两台健康成员:
sudo crictl ps | grep etcd
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 \
endpoint health --cluster
如果某个成员反复退出,先看该成员的容器日志,不要继续停止其他成员。常见原因是 data-dir 权限、peer 证书 SAN 不匹配、--initial-cluster 写错,或端口被旧进程占用。
etcdctl endpoint status --cluster -w table 能列出全部成员,且有且只有一个 leader;DB 大小和 revision 与快照记录接近。etcdctl alarm list 没有 NOSPACE、CORRUPT 等告警。kubectl get --raw='/healthz/etcd' 返回 ok,kubectl get nodes 能列出节点,核心系统 Pod 逐步恢复。kubectl get ns、kubectl get crd、kubectl get pods -A 的结果与快照时点一致,关键业务对象没有缺失。kubectl get secrets -A -o json >/dev/null;如果报解密错误,回头检查加密配置。恢复后不要立即清理旧数据目录和日志。先把快照时间、revision、成员列表、验证结果和恢复耗时写进事故记录。
部分成员启动失败。 保留失败成员的数据目录和日志,检查证书、URL、token、权限与磁盘。不要用另一个快照单独补这个成员;同一集群的所有成员必须来自同一快照。若只是单成员硬件故障,应在集群恢复后按正常的成员替换流程处理。
恢复后 apiserver 无法连接 etcd。 优先检查 /etc/kubernetes/pki/apiserver-etcd-client.* 与 etcd 的 CA 是否匹配,其次看 apiserver 日志中的 TLS 错误和 endpoint 地址。不要通过关闭证书校验来绕过问题。
快照损坏或数据格式不兼容。 停止所有控制面,换一份已校验的旧快照,所有成员重新恢复。不要尝试把不同快照的数据目录拼在一起,也不要在恢复过程中升级 etcd 或 Kubernetes。
恢复目标时点选错。 如果旧数据目录在故障前仍可服务,可以回退到旧目录:
sudo systemctl stop kubelet
sudo mv /var/lib/etcd /var/lib/etcd.restore-failed-$(date +%Y%m%d%H%M%S)
sudo mv /var/lib/etcd.pre-restore-* /var/lib/etcd
sudo systemctl start kubelet
这条回滚只适用于旧数据本身可用的情况。如果故障是逻辑损坏、误删或数据污染,回退到旧目录等于回到损坏状态;此时应改用另一份快照,而不是盲目回滚。
证书或加密密钥丢失。 先用离线备份恢复;无法恢复时,需要按集群 PKI 重建流程重新签发证书并重新加入节点。不要为了省事重建 etcd CA 后继续使用旧快照中的客户端证书,TLS 握手会持续失败。
验证失败但业务已恢复写入。 立即停止业务写入,重新评估快照时点。恢复后的新写入可能与快照后的数据冲突,不能简单再灌一次快照;应把新写入导出、隔离,再决定重新恢复还是人工合并。
合上页面,先回答,再展开对照。
小程序版
微信扫码,随时查命令