K8s 高可用集群 etcd 单节点宕机的应急恢复与重建
2026-08-11 00:53:03 # Kubernetes

问题现象与背景原因

在 Kubernetes 高可用(HA)集群中,etcd 通常以 3 或 5 个节点组成 Raft 集群,是整个集群的”数据库”。当其中某一台 etcd 节点因硬件故障、网络中断或磁盘损坏而宕机时,会表现出以下现象:

  • 监控告警 etcd member <id> has been down for ...
  • kubectl 操作偶发变慢或超时,apiserver 日志中出现 etcd timeout / context deadline exceeded
  • 若宕机的是 Leader 节点,apiserver 会在数秒内无法写入,但 etcd 会自动重新选主,通常很快恢复;
  • 若集群为 3 节点且同时有 2 个节点不可用,则失去 Raft 多数派(quorum),整个控制面写入瘫痪,但已运行的数据面 Pod 不受影响。

影响范围总结

宕机节点 剩余可用 控制面写入 控制面读取 数据面(Pod/Service)
1 个(follower) 2/3 正常 正常 不受影响
1 个(leader) 2/3 短暂中断后恢复 正常 不受影响
2 个(3 节点集群) 1/3 完全瘫痪 几乎不可用 不受影响(但无法新建/变更)

也就是说,etcd 单节点宕机是”设计内可承受”的故障,核心目标是保住 quorum 并尽快把节点恢复或替换回去。

排查过程(思路与定位方法)

第一步,确认 etcd 集群整体健康状态与成员列表:

1
2
3
4
5
6
ETCDCTL_API=3 etcdctl \
--endpoints=https://10.0.0.1:2379,https://10.0.0.2:2379,https://10.0.0.3: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

输出会明确标出哪个端点 unhealthy。接着查看成员列表,定位宕机节点的 member ID:

1
2
3
4
5
6
ETCDCTL_API=3 etcdctl \
--endpoints=https://10.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

第二步,判断宕机节点能否恢复:

  • 登录该节点,确认是进程崩溃、机器重启,还是磁盘损坏(dmesg | grep -i errorsmartctl 等);
  • 若只是 etcd 进程挂掉且数据目录完好,直接拉起即可,不要执行 member remove
  • 若数据目录所在磁盘损坏、无法修复,则需要走”移除 + 重建”流程。

第三步,确认 quorum 是否仍在:

1
2
3
4
5
ETCDCTL_API=3 etcdctl --endpoints=https://10.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 -w table

只要能查到 leader、RAFT TERM 在增长,说明 quorum 仍在,集群可用,你有充足时间做节点重建。

解决方法(节点重建恢复流程)

场景 A:节点可恢复(进程/机器重启,数据完好)

直接重启 etcd 服务,它会以 --initial-cluster-state=existing 重新加入原集群,无需改动成员列表:

1
2
3
4
5
6
# systemd 管理的集群
sudo systemctl restart etcd
# 容器/静态 Pod 托管(kubeadm)
sudo systemctl restart kubelet
# 观察日志
sudo journalctl -u etcd -f # 或 kubectl -n kube-system logs etcd-<node> -f

场景 B:节点不可恢复(磁盘损坏),需替换新节点

  1. 在存活节点上移除故障成员(用 member list 查到的 ID):
1
2
3
4
5
6
ETCDCTL_API=3 etcdctl \
--endpoints=https://10.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 remove <故障节点MemberID>
  1. 新节点准备环境:安装同版本 etcd 二进制、拷贝 CA 与 server 证书、将数据目录清空(新成员必须从其他成员同步,不能带旧数据):
1
2
sudo systemctl stop etcd
sudo rm -rf /var/lib/etcd/member # 清空旧数据,避免 data dir 不一致
  1. 把新节点作为新成员加入集群,拿到新的 member ID:
1
2
3
4
5
6
ETCDCTL_API=3 etcdctl \
--endpoints=https://10.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 add etcd-<新节点名> --peer-urls=https://10.0.0.4:2380
  1. 修改新节点的 etcd 启动配置(kubeadm 环境改 /etc/kubernetes/manifests/etcd.yaml,或 systemd 的 /etc/etcd/etcd.conf),确保:
  • --initial-cluster 包含所有成员(含新节点);
  • --initial-cluster-state=existing
  • --namemember add 时的名字一致;
  • 证书路径正确。
  1. 拉起新节点 etcd,观察其从 leader 同步数据:
1
2
3
4
5
6
sudo systemctl start etcd
ETCDCTL_API=3 etcdctl --endpoints=https://10.0.0.4:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
endpoint health

场景 C:数据损坏需从快照恢复(兜底)

若多个成员数据都损坏,使用此前定期备份的快照恢复:

1
2
3
4
5
6
7
# 在单节点先恢复出 data dir
ETCDCTL_API=3 etcdctl snapshot restore snapshot.db \
--data-dir /var/lib/etcd/member \
--name etcd-1 \
--initial-cluster etcd-1=https://10.0.0.1:2380 \
--initial-cluster-token etcd-cluster
# 再依次拉起其他成员,从已恢复的节点同步

操作命令速查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. 健康检查(集群视角)
ETCDCTL_API=3 etcdctl --endpoints=https://10.0.0.1:2379,https://10.0.0.2:2379,https://10.0.0.3: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

# 2. 查看成员
ETCDCTL_API=3 etcdctl --endpoints=https://10.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

# 3. 移除故障成员
ETCDCTL_API=3 etcdctl --endpoints=https://10.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 remove <ID>

# 4. 添加新成员
ETCDCTL_API=3 etcdctl --endpoints=https://10.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 add etcd-new --peer-urls=https://10.0.0.4:2380

经验总结

  • etcd 节点数取奇数(3/5),永远保证能容忍 (N-1)/2 个节点故障;单节点宕机在 3/5 节点集群里是”设计内可承受”的故障。
  • 定期快照备份是最后兜底:ETCDCTL_API=3 etcdctl snapshot save 配合 cron 定时任务。
  • etcd 必须跑在独立高性能 SSD 上,单独挂载磁盘,避免与系统盘/容器镜像争抢 I/O(磁盘 I/O 延迟过高会触发”死亡螺旋”)。
  • 节点只是进程挂、数据完好时,先拉起,别急着 remove;只有数据不可恢复才走移除 + 重建。
  • 监控 etcd 健康、DB 大小、磁盘延迟与 leader 切换,把告警做在故障之前。
  • 延伸高危场景:etcd 数据碎片整理(etcdctl defrag)与磁盘 I/O 延迟导致的控制面”死亡螺旋”,建议单独纳入日常巡检。