K8s 存储踩坑记:强拆 Longhorn '僵尸 Pod' 钉子户
This content is not available in your language yet.
在折腾 K3s + Longhorn 搭建我的赛博影音堡垒时,我遇到了一个极其让人血压升高的玄学 Bug。
整个流水线突然停工,应用 Pod 疯狂报错无法启动,而罪魁祸首,居然是一个在系统里“死活退不出来”的僵尸进程。
🚨 案发现场:拔不掉的管子
Section titled “🚨 案发现场:拔不掉的管子”一切起因于我修改了媒体应用(Radarr/Sonarr)的配置文件并重新部署。新 Pod 迟迟无法启动,查看事件日志,赫然飘着那句经典的存储死锁报错:
Multi-Attach error for volume ... Volume is already exclusively attached to one node and can't be attached to another
意思是:存储卷正被旧节点死死锁着,新 Pod 拿不到权限。
顺藤摸瓜,我发现底层负责管理挂载的 longhorn-csi-plugin Pod 一直卡在 Terminating(正在终止)状态,时长超过了 20 分钟!查看它的详细日志,看到了这句致命的超时宣告:
error killing pod: failed to "KillContainer" for "longhorn-liveness-probe" ... rpc error: code = DeadlineExceeded desc = context deadline exceeded🧠 赛博验尸报告:为什么它“杀不死”?
Section titled “🧠 赛博验尸报告:为什么它“杀不死”?”表面上看是 Kubernetes 出了 Bug,但深入探究,这其实是 Linux 内核底层的自我保护机制导致的。
- I/O 阻塞:由于之前尝试跨网段挂载 NFS 导致了网络超时,底层的存储进程卡在了“等待磁盘响应”的状态。
- 内核级锁死 (D-state):在 Linux 中,当进程卡在底层 I/O 等待时,内核会将其标记为 不可中断睡眠 (Uninterruptible Sleep, D状态)。在这个状态下,进程会无视任何外部信号(包括
kill -9)。 - Kubelet 懵逼:Kubernetes 的包工头 Kubelet 给容器引擎下达了“拔管”指令,但底层容器因为 D 状态根本不鸟它。Kubelet 苦等 2 分钟后无奈宣布超时(DeadlineExceeded),于是这个 Pod 就成了一个永远卡在
Terminating的“钉子户”,并且牢牢霸占着 Longhorn 的存储锁。
🛠️ 三板斧解决僵尸 Pod
Section titled “🛠️ 三板斧解决僵尸 Pod”对付这种级别的钉子户,常规的清理已经没用了。必须采取暴力强拆手段。
第一板斧:K8s 逻辑强抹除(本次生效的绝招)
Section titled “第一板斧:K8s 逻辑强抹除(本次生效的绝招)”既然正常的优雅退出走不通,那就直接在 K8s 的记录本上把它强行划掉,不给任何宽限时间。
执行以下命令强杀卡死的 Pod:
kubectl delete pod <卡住的Pod名称> -n longhorn-system --force --grace-period=0效果:命令敲下的瞬间,Pod 从列表中消失,Longhorn 控制平面终于意识到锁可以释放,随后新 Pod 瞬间挂载存储卷成功,业务恢复!
第二板斧:重启底层容器引擎(备用方案)
Section titled “第二板斧:重启底层容器引擎(备用方案)”如果在执行完第一步后,kubectl get pods 里确实没它了,但应用依然报 Multi-Attach error,说明底层 Linux 进程依然在霸占资源。此时需要重启 K3s 的 agent 服务来重置容器状态:
# 登录出问题的 K3s 工作节点执行sudo systemctl restart k3s-agent# 如果是主节点则执行 restart k3s第三板斧:物理重启(终极毁灭)
Section titled “第三板斧:物理重启(终极毁灭)”如果前两招都打完,存储依然处于死锁状态,说明 Linux 内核的 I/O 队列已经彻底崩溃。别犹豫,直接 sudo reboot 重启该节点所在的物理机或虚拟机,这是清理 D 状态进程最彻底的方案。
💡 赛博包工头的总结
Section titled “💡 赛博包工头的总结”这次踩坑不仅让我深入理解了 Kubernetes 和底层操作系统的联动关系,也总结出了一条铁律:
在 HomeLab 环境中,对于独占存储(ReadWriteOnce)的单副本有状态应用(如 qBittorrent、数据库等),在 deployment.yaml 中务必将更新策略设置为重建!
spec: replicas: 1 strategy: type: Recreate # 强制先杀旧,再启新,绝不抢锁遇到 Terminating 不要慌,找准病根,果断拔管!