817 字
4 分钟
K8s 集群故障恢复实录
事故现场
起因是我在做 K8s 部署 CI/CD 实验时,只备份了 Master 节点的快照。当时的想法是:etcd 数据主要在 Master 上,只要 Master 能恢复,集群就能恢复到可用状态;工作节点和其他组件即使有问题也可以重新拉起来。之后进行其他实验时,为了快速回到“干净环境”,我在实验结束后直接回滚了 Master 的快照。
问题来了:我只恢复了 Master,Node1 和 Node2 只恢复了刚搭建k8s集群时的快照!
集群起来后直接懵了,所有 Pod 都是 Unknown 状态,完全不工作。
kubectl get pods -ANAMESPACE NAME READY STATUS RESTARTS AGEjenkins jenkins-0 0/1 Unknown 0 3dgitea gitea-0 0/1 Unknown 0 3dargocd argocd-server-xxx 0/1 Unknown 0 3d...这下麻烦了,整个集群挂了。
排查思路
冷静分析了一下:
- Master 恢复到了几天前的状态
- Node1 和 Node2 还是”最初始”的状态
- 时间不同步,节点证书可能过期
- Kubelet 和 containerd 状态不对
- 一堆 Pod 卡在 Unknown,需要强制重建
开始抢救
第一步:时间同步
时间不同步会导致各种奇怪的问题,先把三个节点的时间对齐。
在所有节点上执行:
systemctl start chronydchronyc makestephwclock -wdate # 确认时间已经是当前时间第二步:安装 NFS 客户端
因为 Node 恢复后没有 NFS 工具,但集群里的 PV 都是 NFS 的,会导致挂载失败。
在 Node1 和 Node2 上执行:
yum install -y nfs-utilssystemctl enable --now rpcbind第三步:重启容器运行时
很多 Pod 的状态是旧的,需要重启 containerd 和 kubelet 清理掉僵尸进程。
在 Node1 和 Node2 上执行:
# 停止旧的容器进程(防止僵尸进程占用端口)systemctl restart containerd
# 重启 kubeletsystemctl restart kubelet等了几分钟,看了下节点状态:
kubectl get nodesNAME STATUS ROLES AGE VERSIONk8s-master Ready control-plane 10d v1.28.0k8s-node1 Ready <none> 10d v1.28.0k8s-node2 Ready <none> 10d v1.28.0好,节点恢复 Ready 了。但 Pod 还是 Unknown。
第四步:强制删除 Pod
Unknown 状态的 Pod 已经没救了,只能强制删掉让它们重建。
恢复 Jenkins
kubectl -n jenkins delete pod jenkins-0 --force --grace-period=0等了一会,新的 Pod 起来了:
kubectl -n jenkins get podsNAME READY STATUS RESTARTS AGEjenkins-0 1/1 Running 0 2m恢复 Gitea
kubectl -n gitea get podskubectl -n gitea delete pod --all --force --grace-period=0恢复 ArgoCD
kubectl -n argocd delete pod --all --force --grace-period=0恢复 NFS Provisioner
这个很关键,没有它 PVC 就没法自动创建。
kubectl -n kube-system get pods | grep nfskubectl -n kube-system delete pod -l app=nfs-subdir-external-provisioner --force --grace-period=0第五步:验证
等所有 Pod 都重建完成后,检查一下:
kubectl get pods -ANAMESPACE NAME READY STATUS RESTARTS AGEjenkins jenkins-0 1/1 Running 0 5mgitea gitea-0 1/1 Running 0 4margocd argocd-server-xxx 1/1 Running 0 3margocd argocd-application-controller-xxx 1/1 Running 0 3m...全部 Running!
访问一下服务:
- Jenkins:
http://192.168.100.10:30080✅ - Gitea:
http://192.168.100.10:30030✅ - ArgoCD:
https://192.168.100.10:30090✅
数据也都在,因为用的是 NFS 存储,没丢。
教训
- 备份要全:既然要存快照,Master 和 Node 都得存,不能只存一半
- 时间同步很重要:分布式系统对时间敏感,不同步会出各种奇怪问题
- PV 数据还在就好办:只要持久化存储没丢,Pod 重建就能恢复
折腾了一个多小时,总算把集群救回来了。以后做实验还是得小心点,多备份。
K8s 集群故障恢复实录
https://dev-null-sec.github.io/posts/k8s集群故障恢复实录/