Skip to content

K8s 存储踩坑记:强拆 Longhorn '僵尸 Pod' 钉子户

🌱 创建: 2026/05/04 ⏱️ 更新: 2026/05/22

This content is not available in your language yet.

在折腾 K3s + Longhorn 搭建我的赛博影音堡垒时,我遇到了一个极其让人血压升高的玄学 Bug。

整个流水线突然停工,应用 Pod 疯狂报错无法启动,而罪魁祸首,居然是一个在系统里“死活退不出来”的僵尸进程。

一切起因于我修改了媒体应用(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 内核底层的自我保护机制导致的。

  1. I/O 阻塞:由于之前尝试跨网段挂载 NFS 导致了网络超时,底层的存储进程卡在了“等待磁盘响应”的状态。
  2. 内核级锁死 (D-state):在 Linux 中,当进程卡在底层 I/O 等待时,内核会将其标记为 不可中断睡眠 (Uninterruptible Sleep, D状态)。在这个状态下,进程会无视任何外部信号(包括 kill -9)。
  3. Kubelet 懵逼:Kubernetes 的包工头 Kubelet 给容器引擎下达了“拔管”指令,但底层容器因为 D 状态根本不鸟它。Kubelet 苦等 2 分钟后无奈宣布超时(DeadlineExceeded),于是这个 Pod 就成了一个永远卡在 Terminating 的“钉子户”,并且牢牢霸占着 Longhorn 的存储锁。

对付这种级别的钉子户,常规的清理已经没用了。必须采取暴力强拆手段。

第一板斧:K8s 逻辑强抹除(本次生效的绝招)

Section titled “第一板斧:K8s 逻辑强抹除(本次生效的绝招)”

既然正常的优雅退出走不通,那就直接在 K8s 的记录本上把它强行划掉,不给任何宽限时间。

执行以下命令强杀卡死的 Pod:

Terminal window
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 服务来重置容器状态:

Terminal window
# 登录出问题的 K3s 工作节点执行
sudo systemctl restart k3s-agent
# 如果是主节点则执行 restart k3s

第三板斧:物理重启(终极毁灭)

Section titled “第三板斧:物理重启(终极毁灭)”

如果前两招都打完,存储依然处于死锁状态,说明 Linux 内核的 I/O 队列已经彻底崩溃。别犹豫,直接 sudo reboot 重启该节点所在的物理机或虚拟机,这是清理 D 状态进程最彻底的方案。

这次踩坑不仅让我深入理解了 Kubernetes 和底层操作系统的联动关系,也总结出了一条铁律:

在 HomeLab 环境中,对于独占存储(ReadWriteOnce)的单副本有状态应用(如 qBittorrent、数据库等),在 deployment.yaml 中务必将更新策略设置为重建!

spec:
replicas: 1
strategy:
type: Recreate # 强制先杀旧,再启新,绝不抢锁

遇到 Terminating 不要慌,找准病根,果断拔管!

Last updated: