NFS挂载卡死时进程呈D状态,需用umount -l强制卸载并配置hard,intr,timeo=600,retrans=3,noac,actimeo=0等参数防死锁。

当NFS服务器响应延迟飙升或出现间歇性中断时,挂载了NFS卷的Pod会卡在ls /mnt/nfs、cat config.yaml等任意系统调用上,表现为大量进程状态为D(uninterruptible sleep),kubectl exec进容器后连ps aux都卡住,且这种挂起具备传染性——一个Pod卡死会拖慢整个节点上的I/O调度队列。
确认NFS挂载是否处于D状态卡死
在宿主机上执行ps aux | grep nfs,若看到大量形如nfsd 0.0 0.0 0 - D或rpciod 0.0 0.0 0 - D的进程,说明内核NFS客户端已陷入不可中断等待;此时ls /var/lib/kubelet/pods/*/volumes/kubernetes.io~nfs/也会无响应——这一步必须在节点上做,容器内ps早已失效。
运行cat /proc/mounts | grep nfs,检查挂载项中是否含hard,intr,soft,timeo=600,retrans=3等参数;若只有hard而无timeo和retrans,则NFS一旦断连将永久阻塞,【这是只读挂起最直接的配置诱因】。
定位抖动源头:区分是服务端还是网络层
方法一:用tcpdump抓包比对RTT波动
在Pod所在节点执行:tcpdump -i any -w nfs.pcap port 2049 and host ,持续30秒后Ctrl+C停止;用Wireshark打开pcap,过滤nfs.opcode == 17(READ操作),观察Response Time列——若出现>500ms的尖峰且密集成簇,说明服务端处理慢;若RTT正常但大量重传(Retransmission标记),则是中间网络丢包或MTU不匹配。
方法二:绕过K8s直接复现
在该节点新建临时挂载:mkdir /tmp/testnfs && mount -t nfs4 -o hard,intr,timeo=600,retrans=3 ;随后在/tmp/testnfs下执行dd if=/dev/zero of=testfile bs=1M count=100 oflag=sync。若同样卡住,则问题与K8s无关,纯属NFS服务或链路问题。
紧急止血:解挂所有NFS并防止自动重试
第一步:强制解除卡死挂载
执行umount -f -l /var/lib/kubelet/pods/*/volumes/kubernetes.io~nfs/*,【-l(lazy)参数必不可少,-f单独使用在D状态时无效】。
第二步:阻止kubelet自动重挂
编辑/var/lib/kubelet/config.yaml,将volumePluginDir路径临时注释掉,然后重启kubelet:systemctl restart kubelet。这能立即终止所有NFS volume插件的后台轮询,避免新Pod重复踩坑。
第三步:清理残留挂载点
执行find /var/lib/kubelet/pods -name "nfs" -type d -exec umount -l {} \;,再rmdir所有空目录。此时mount | grep nfs应无输出。
修复挂载策略:让NFS在抖动时主动降级而非死锁
修改Pod的Volume定义,在volumeMounts中添加mountOptions:
mountOptions:
- hard
- intr
- timeo=600
- retrans=3
- noac
- actimeo=0
其中noac禁用属性缓存,actimeo=0强制每次访问都校验服务端元数据——看似牺牲性能,实则避免因本地缓存过期导致的误判式挂起;timeo=600单位是0.1秒,即60秒超时,配合retrans=3意味着最多等待3分钟,超时后返回EIO错误而非无限等待。
若NFS服务端支持NFSv4.1+,务必在spec.volumes.nfs中指定server字段为IPv4地址而非主机名,规避DNS解析抖动引发的首次挂载失败连锁反应。











