kubectl执行命令卡住,访问apiserver:6443 报504连接超时报错,k8s集群无法操作,根据经验感觉 etcd 集群是出问题了,查看 etcd 集群发现只剩一个节点的etcd还在运行,登陆异常 etcd 节点发现etcd容器一直在不断重启,拿到报错日志,备份3个master节点上etcd数据,将etcd报错信息截图和故障现象描述发给 qwen3.8-max,根据AI的分析参考恢复。
这是一个非常典型的 etcd 故障场景。根据你提供的日志截图,我们可以清晰地定位到问题的根源,并制定恢复方案。
1. 故障原因分析
核心报错信息:
在第一张图的最后一行,可以看到致命的错误日志:{"level":"fatal", ... "msg":"failed to read WAL, cannot be repaired", "error":"wal: slice bounds out of range" ...}
详细解读:
WAL 损坏 (Write-Ahead Log Corruption): etcd 使用 WAL 来保证数据的一致性和持久化。报错
failed to read WAL, cannot be repaired和wal: slice bounds out of range明确指出,当前节点(chegva-s3)的 WAL 日志文件已经损坏,且 etcd 尝试自动修复失败。这通常是由于磁盘 I/O 错误、非正常关机(断电)、或者文件系统问题导致的。快照文件异常: 日志中还有一行警告:
found unexpected non-snap file; skipping ... .snap.broken。这说明 etcd 在启动时检测到了损坏的快照文件,并将其标记为 broken。虽然它尝试从另一个快照恢复 (recovered v3 backend from snapshot),但在重放 WAL 日志以追赶最新状态时失败了。集群状态:
当前节点 chegva-s3 (IP: 172.xx.xx.45) 无法启动。
从启动参数
--initial-cluster可以看到这是一个 3 节点集群:chegva-s3(45), chegva-s2(44), chegva-s1(43)。关键点: etcd 是强一致性集群,只要多数派(2/3)节点存活,集群理论上仍可工作。但如果
kubectl卡住,说明 API Server 无法连接到健康的 etcd 节点,或者另外两个节点也出现了问题(例如网络隔离、或者也因为类似原因挂了)。备份脚本卡死: 第二张图显示有一个
etcdctl snapshot save的进程正在运行。因为本地 etcd 挂了,这个命令会一直等待连接,导致卡住。这证实了 etcd 服务不可用。
2. 恢复方案
由于这是一个 3 节点集群,恢复策略取决于另外两个节点 (chegva-s1, chegva-s2) 的状态。
第一步:检查其他节点状态 (至关重要)
请登录到另外两台机器 (43 和 44),执行以下命令检查 etcd 是否健康:
# 在另外两台机器上执行 crictl ps | grep etcd # 或者查看日志 crictl logs <etcd_container_id> --tail 50
同时,尝试在任意一台健康的节点上使用 etcdctl 检查集群状态(需要配置证书环境变量,或者直接在容器内执行):
# 示例:在容器内执行 (假设容器ID已知) crictl exec -it <healthy_etcd_container_id> /bin/sh 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 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 # 示例:在物理机上执行 ETCDCTL_API=3 etcdctl \ --endpoints=172.xx.xx.43:2379,172.xx.xx.44:2379,172.xx.xx.45: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
场景 A:另外两个节点健康 (集群多数派存活)
如果 chegva-s1 和 chegva-s2 是健康的,那么恢复 chegva-s3 最简单的方法是移除坏节点的数据,让它作为新成员重新加入集群同步数据。
操作步骤 (在 chegva-s3 上执行):
1.停止 etcd 容器:
由于是 kubelet 管理的静态 Pod,直接删除容器可能会重启。最好的方式是临时移走 manifest 文件。
mv /etc/kubernetes/manifests/etcd.yaml /tmp/etcd.yaml.bak # 等待几秒,确认容器已停止 crictl ps | grep etcd
2.备份并清理数据目录:
警告: 务必先备份,以防万一。
mv /etc/kubernetes/manifests/etcd.yaml /tmp/etcd.yaml.bak # 等待几秒,确认容器已停止 crictl ps | grep etcd
3.从集群中移除该成员 (在健康的节点上执行):
你需要获取 chegva-s3 的 Member ID。
在健康节点执行 etcdctl member list,找到对应 172.xx.xx.45 的 ID (例如 8e9e05c52164694d)。
# 在健康节点执行 ETCDCTL_API=3 etcdctl \ --endpoints=172.xx.xx.43:2379,172.xx.xx.44:2379,172.xx.xx.45:2379 \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key \ member remove <chegva-s3_Member_ID>
4.将该节点重新加入集群 (在健康的节点上执行):
# 在健康节点执行 etcdctl member add chegva-s3 --peer-urls=https://172.xx.xx.45:2380
执行后,终端会输出一段环境变量配置,请记录下来(虽然静态 Pod 通常不需要手动配这些,但确认一下 peer urls 是对的)。
5.恢复 etcd 静态 Pod:
回到 chegva-s3 节点。
mv /tmp/etcd.yaml.bak /etc/kubernetes/manifests/etcd.yaml
6.观察恢复情况:
kubelet 会自动拉起 etcd 容器。查看日志:
crictl logs -f <new_etcd_container_id>
你应该能看到它开始从 Leader 节点同步数据 (streaming snapshot, applying entries)。同步完成后,集群恢复正常。
场景 B:所有节点都挂了,或者无法形成多数派 (灾难恢复)
如果另外两个节点也挂了,或者数据也损坏了,你需要使用快照恢复。
前提: 你必须有之前备份的 etcd snapshot 文件 (.db 文件)。
看第二张图,你的系统里似乎有个定时任务在跑 etcdctl snapshot save /data/snapshot-latest.db。如果这个文件存在且是最新的,可以用它恢复。
操作步骤 (全集群重建):
1.停止所有节点的 etcd:
在所有 3 台机器上执行:
mv /etc/kubernetes/manifests/etcd.yaml /tmp/etcd.yaml.bak
2.清理所有节点的数据目录:
在所有 3 台机器上执行:
rm -rf /var/lib/etcd/*
3.在一个节点上恢复快照 (例如 chegva-s1):
假设快照文件在 /data/snapshot-latest.db。
# 注意:这里的 --name, --initial-cluster 等参数必须与原集群配置完全一致 etcdctl snapshot restore /data/snapshot-latest.db \ --name chegva-s1 \ --initial-cluster chegva-s1=https://172.xx.xx.43:2380,chegva-s2=https://172.xx.xx.44:2380,chegva-s3=https://172.xx.xx.45:2380 \ --initial-cluster-token etcd-cluster-1 \ --initial-advertise-peer-urls https://172.xx.xx.43:2380 \ --data-dir /var/lib/etcd
注意:--initial-cluster-token 最好查看原 etcd.yaml 里的配置,如果没有显式配置,etcd 有默认值,但为了保险起见,尽量保持一致。如果原配置没写,可以去掉这个参数或保持默认。
4.将恢复后的数据分发到其他节点 (或者分别恢复):
方法一(推荐): 分别在每个节点上用同一个快照文件执行 snapshot restore,但修改 --name 和 --initial-advertise-peer-urls 为对应节点的 IP。
确保所有节点的 /var/lib/etcd 目录权限正确 (通常是 root:root)。
chegva-s2:
--name chegva-s2 ... --initial-advertise-peer-urls https://172.xx.xx.44:2380chegva-s3:
--name chegva-s3 ... --initial-advertise-peer-urls https://172.xx.xx.45:2380
5.启动所有节点的 etcd:
在所有 3 台机器上执行:
mv /tmp/etcd.yaml.bak /etc/kubernetes/manifests/etcd.yaml
6.验证:
等待几分钟,检查日志,确认集群建立成功。
3. 针对你当前情况的建议操作顺序
不要急着删数据。 先保留现场
/var/lib/etcd的备份。立刻去检查 43 和 44 节点。
如果 43/44 活着 -> 采用 场景 A (移除 s3 成员,清空 s3 数据,重新加入)。这是最快且风险最小的方法。
如果 43/44 也死了 -> 寻找
/data/snapshot-latest.db(看图二似乎有这个文件),采用 场景 B 进行全量恢复。关于卡住的 kubectl: 一旦 etcd 恢复,API Server 会自动重连 etcd,
kubectl命令会自动恢复响应,无需重启 API Server (除非 API Server 也挂了)。
补充提示:
图二中显示的 etcdctl snapshot save 进程卡住是因为它连不上本地 etcd。在修复过程中,你可以直接 kill 掉这个进程 (PID 3560716),以免影响后续操作或占用资源。
参考:


