为什么先看事件
存储类故障的原文几乎都在事件里,而不是在 Pod 状态或容器日志里。Kubernetes 把卷相关的失败拆成若干事件类型:FailedAttachVolume 指向卷附着层,FailedMount 指向节点侧挂载层,FailedScheduling 里带卷拓扑信息说明卷位置与节点约束冲突,VolumeResizeFailed 说明扩容请求被存储侧拒绝。认出事件类型,就等于直接跳到对应的排查层,而不是盲目重启 Pod。
事件类型对照
| 事件 | 指向的层 | 下一步动作 |
|---|---|---|
| FailedAttachVolume | 卷附着(云盘 RWO 冲突最常见) | 确认卷是否已被其他节点占用、是否同一可用区 |
| Multi-Attach error | 附着层的独占冲突 | 核对访问模式与副本分布 |
| FailedMount | 节点侧挂载(CSI 节点组件、NFS 可达性) | 看 kubelet 与驱动节点组件日志、节点到存储的连通性 |
| FailedScheduling(卷拓扑) | 卷位置与节点约束不匹配 | 核对节点标签、可用区与卷绑定模式 |
| VolumeResizeFailed | 扩容被存储侧拒绝 | 核对是否允许扩容、存储配额与卷类型 |
| FailedBinding | PVC 找不到可绑定卷 | 检查存储类、容量与访问模式是否匹配 |
典型使用场景
- Pod 卡在 ContainerCreating:直接看事件,通常一次就能确定是 attach 还是 mount 层
- 批量故障:用事件列表按时间排序,判断是否同一存储后端同时出现问题
- 跨可用区集群:调度与卷拓扑冲突会在事件里给出卷所在区与节点所在区
- 扩容不生效:核对是否留下 VolumeResizeFailed 事件,避免误以为是等待重启
- 交付前检查:把事件纳入常规巡检项,早于业务告警发现存储层异常
收集与过滤
收集与过滤
kubectl describe pod web-x | sed -n '/Events:/,$p' # 单 Pod 的完整事件时间线
kubectl get events -A --field-selector reason=FailedMount --sort-by=.lastTimestamp | tail -20
kubectl get events -A --field-selector reason=FailedAttachVolume --sort-by=.lastTimestamp | tail -20
kubectl get events -A --sort-by=.lastTimestamp | grep -i -E 'volume|mount|attach' | tail -20
kubectl describe pvc data-web-0 | sed -n '/Events:/,$p' # 卷侧视角的事件事件字段读法
| 字段 | 含义 | 用途 |
|---|---|---|
| Reason | 事件类型短标识 | 决定去查哪一层 |
| Message | 可读的失败说明 | 常包含具体超时、权限或网络错误原文 |
| Count | 同一事件出现次数 | 次数很高说明持续失败而非抖动 |
| LastTimestamp | 最后发生时间 | 与变更时间对齐可定位触发动作 |
| Involved Object | 关联对象 | 快速区分是 Pod、PVC 还是 PV 层的问题 |
事件有保留时间限制,默认窗口较短。复现后应立即按涉及对象过滤并留存输出,等业务方反馈完再回头取证时,关键条目可能已经消失,只能重新复现。
事件只描述现象与部分原因,存储侧的最终判定往往在 CSI 控制器或云平台 API 日志中。事件指向该层后,下一步是到对应组件日志里找原文,而不是在 Kubernetes 对象上反复改动。