StatefulSet 卡住是什么情况
StatefulSet 采用有序推进,序号 0 的副本没就绪,序号 1 就不会创建,因此问题总是集中在最先卡住的那个序号上。常见卡点有两类:PVC 长期 Pending 拿不到存储,以及卷挂载失败(跨可用区、盘未释放、路径不存在)。定位方法是沿着「PVC 状态、StorageClass、Pod 事件」这条链走。
基本信息
| 有序性 | kubectl get pods -l app=db 看卡在第几个序号 |
|---|---|
| PVC 状态 | get pvc 看 Pending 还是 Bound,describe 看 Events |
| 存储类 | kubectl get sc 看 provisioner 与 volumeBindingMode |
| 挂载失败 | Pod 事件里的 FailedMount 或 FailedAttach 给出原因 |
| 数据保留 | 删除 StatefulSet 默认不删 PVC,重建不清数据也不恢复数据 |
| 命名规律 | PVC 名通常为模板名加 StatefulSet 名与序号 |
卡点与处置
| 现象 | 根因 | 处置 |
|---|---|---|
| PVC Pending(等待调度) | 绑定模式为 WaitForFirstConsumer | 属正常等待,先看 Pod 是否已调度 |
| PVC Pending(provisioner 失败) | 配额、权限或可用区不符 | 看 StorageClass 事件与云平台配额 |
| Pod 报 FailedAttach | 盘仍挂在上一个节点未释放 | 等卸载完成,确认旧节点已下线 |
| Pod 报 FailedMount | 路径不存在、权限或文件系统不兼容 | 核对卷模式与宿主挂载点 |
| 报 volume node affinity conflict | 卷与节点不在同一可用区 | 让卷与节点池对齐 |
排查命令
排查命令
kubectl get pods -l app=mysql -o wide # 看序号与所在节点
kubectl get pvc -l app=mysql # Pending 还是 Bound
kubectl describe pvc data-mysql-0 # Events 写明 provisioner 报错
kubectl describe pod mysql-0 | grep -A5 -i mount # 挂载相关事件
kubectl get sc # provisioner 与绑定模式
kubectl get statefulset mysql -o yaml | grep -A10 volumeClaimTemplates典型使用场景
- 数据库集群扩容副本时新 PVC 拿不到盘,整个扩容流程卡死
- 节点故障后 Pod 漂移,旧盘未释放导致新节点挂载失败
- 跨可用区部署时卷与节点不同区,Pod 长时间无法调度
- 误以为删掉 StatefulSet 便会清数据,结果数据仍留在卷上
- 滚动更新时后一个副本迟迟不创建,需要先解决前一个未就绪的副本
PVC Pending 要先分清两种情况:WaitForFirstConsumer 下等调度触发属于正常等待,provisioner 侧失败(云盘配额、权限、可用区不符)才是真故障,两者的处置方式完全不同。
删除 StatefulSet 不会删除 PVC,重建后仍能拿回原数据;反过来,想彻底清理数据必须显式删除 PVC,并确认底层盘按回收策略的去向。
手工抢建 PV 会干扰 WaitForFirstConsumer 的绑定时机,可能把卷绑到不合适的节点形成调度死锁,动态供给场景下不要手写 PV。