首页
/
行业洞察
/
正文
INDUSTRY INSIGHT · 深度
RDMA资源消失导致CSI挂载失败?污点与容忍的故障隔离实践
📅 2026/10/10 19:58:49
✍️ 爱科研究院
👁 阅读 3,247
我前段时间在维护一套跑高性能计算业务的 Kubernetes 集群时遇到过一串非常奇怪的告警节点上的 RDMA 资源从Allocatable里消失了紧接着各种 Pod 开始报 CSI 挂载失败。如果你同时管理过 RDMA 这类高性能网络设备和 Kubernetes 存储插件应该能想象到这种问题的排查难度——它不是单纯某个组件坏了而是调度、资源上报、设备生命周期和存储挂载链路同时出了问题。今天复盘一下整个过程讲讲 RDMA 资源消失为什么会导致 CSI 挂载失败以及污点Taint和容忍Toleration在这类场景中真正承担的角色。这个问题很适合平台工程师、SRE 和做高性能计算容器化平台的人参考。尤其是那种把 InfiniBand 网卡、GPU 这类物理设备以 Extended Resource 形式暴露给 Pod 的环境早晚会遇到类似的情况。提前理解了这条链路遇到同类故障时可以少走很多弯路。1. 故障现场节点驱逐后 RDMA 资源从 Capacity 中消失CSI 开始批量报错1.1 第一个现象节点 Allocatable 里的 RDMA 资源归零那天上午集群出现告警有三台计算节点的rdma/hca资源从可分配列表里消失了。正常情况下每台节点有 8 张 HCA 卡通过 device plugin 上报到 kubelet节点状态里会显示类似这样的信息$ kubectl describe node cn-021 Capacity: cpu: 64 memory: 524288Mi rdma/hca: 8 Allocatable: cpu: 60 memory: 507904Mi rdma/hca: 7但出问题之后再看rdma/hca这一项直接从Capacity和Allocatable中消失了连 0 都不显示。这意味着设备 plugin 已经没有把网卡资源上报给 kubeletkubelet 也就认为这台节点不再拥有这项资源。当时这几台节点正在做硬件维护拔掉了几张网卡准备更换。原本预期是维护完成后重新插上但可能是固件识别问题设备并没有完全恢复。下面的内容我们会看到设备没有恢复这个问题并不可怕真正引发故障的是 Kubernetes 没有及时“标记”这一状态。1.2 第二个现象CSI 挂载失败批量出现资源消失本身不至于让业务立即中断真正刺眼的是 CSI 挂载错误风暴。集群里使用了一套基于本地设备的 CSI 驱动为容器提供高性能存储卷这些卷的挂载路径和 RDMA 网卡设备在宿主机的/dev/infiniband/下有直接关系。设备消失后大量 Pod 在创建或重启时报错MountVolume.SetUp failed for volume rdma-local-pv-xxx : rpc error: code FailedPrecondition desc device resource not found一开始我以为只是 CSI 驱动对设备消失处理得不够优雅但深入排查后发现这些 Pod 根本不应当被调度回这几台节点。设备已经没了工作负载可能依赖这些设备那它们为什么还会被放过来启动1.3 当资源消失与挂载失败同时出现先别急着怀疑任何一个组件这里有个很重要的排查心态当两个看起来不太相关的组件同时报错时往往说明上游存在一个共同的根因。RDMA 资源消失是“资源供应侧”的状态变化CSI 挂载失败是“资源使用侧”的触发结果中间的桥梁正是 Kubernetes 的调度与节点状态传播机制。我做了个简单的分层梳理排查方向立刻清晰了很多现象所属层面可能根因rdma/hca从节点 Capacity 消失设备生命周期 / 资源上报device plugin 停止上报kubelet 状态更新延迟Pod 仍被调度到无设备节点调度器决策节点标签、污点、资源筛选条件缺失CSI NodePublishVolume 失败存储插件调用链后端设备路径不存在或挂载依赖的物理资源已移除Pod 反复重启、挂载重试Kubelet 同步循环挂载失败未触发 Pod 优雅驱逐或重调度理顺了这条链之后我再去看节点的污点状态发现一个关键事实这三台节点在资源消失之后污点列表是空的。设备出问题节点却没有被打上任何标记调度器自然还会把新 Pod 送过来。接下来我们详细拆开这条因果链。2. 因果链拆解RDMA 设备消失如何传导到 CSI 挂载失败2.1 容器究竟向谁要 RDMA从 device plugin 到 Extended ResourceRDMA 网卡这类硬件设备不是 CPU 和内存Kubernetes 默认无法感知它们的存在。所以平台一般会为每类设备编写一个 device plugin由它去探测宿主机的设备列表再调用 kubelet 的ListAndWatch接口上报。kubelet 收到上报结果后会把设备数量作为Capacity的一部分暴露出来。用户创建 Pod 时就可以用当前标准的资源申请方式去请求这些设备resources: limits: rdma/hca: 1当设备被物理拔出或故障时device plugin 通过 watch 消息感知到变化上报给 kubelet 的新列表中会减少这个数字节点状态随之更新。整个过程大体上是可靠的问题在于 Kubernetes 只承认“资源量少了”它并不会自动产生一个“节点不可调度”的结论。换句话说设备消失后节点的行为很像一个打折促销的商店货架上没货了但系统依然认为商店还在营业顾客照常进来直到付款或收货时才发现东西根本不存在。2.2 CSI 挂载为什么和后端物理设备绑定很多人不理解文件系统挂载不是应该只涉及存储驱动吗为什么 RDMA 网卡没了会影响 CSI 挂载这是因为高性能计算场景中存储卷并不总是远程存储很多平台会为计算任务分配宿主机上的本地目录或本地设备再通过 CSI 驱动把路径映射进容器。如果这个目录或设备的访问依赖 RDMA 网卡生成的字符设备节点那网卡消失就会让挂载动作直接失败。举个例子我们在 CSI 卷配置中使用了类似下面的挂载参数要求容器内的/mnt/rdma_data指向宿主机的本地目录同时应用需要访问/dev/infiniband/uverbs0volumeMounts: - name: rdma-local-pv mountPath: /mnt/rdma_data - name: rdma-device mountPath: /dev/infiniband/uverbs0CSI 驱动在NodePublishVolume阶段执行挂载前检查时需要确认/dev/infiniband/uverbs0是否真实存在。设备被移除后这个检查必然失败于是 kubelet 不断重试挂载Pod 一直停滞在ContainerCreating状态。2.3 状态传播的时差为什么 Pod 可能被放回“已经坏了”的节点这里有一个非常关键的机制细节Extended Resource 的 Capacity 变化不会立即同步触发调度器的“禁止调度”逻辑。调度器在过滤节点时会读取节点最新状态。如果节点状态更新得足够快调度器会发现rdma/hca不可分配从而把 Pod 放到其他节点。但实际场景中状态更新存在延迟设备消失和节点状态刷新之间隔着一个 kubelet 上报周期。如果在那个时间窗口内发生 Pod 驱逐或新建调度器很可能基于旧数据把 Pod 调度到问题节点上。更麻烦的是被驱逐的 Pod 可能带有nodeAffinity或nodeSelector强制要求落在原来那台节点。这个约束在设备正常时是合理的设备消失后却变成了一道枷锁——其他节点全部被过滤掉唯一能去的节点又无法提供挂载。这就是环境里“资源消失但节点依然可调度”的完整代价链。3. 污点与容忍在这里的真正角色一个本应拦住故障扩散的保险机制3.1 污点不是“禁入标志”而是节点意图的表达很多人对污点的理解是“打上之后 Pod 就不能调度过去”这只是表象。更准确地说污点是节点对自己当前状态的声明。它告诉调度器“我这边有问题除非你的工作负载明确表示能容忍这种问题否则别过来。”在 RDMA 设备消失这个场景里维护团队应当第一时间给节点打上类似这样的污点kubectl taint nodes cn-021 rdma.network/device-offlinetrue:NoSchedule打上之后调度器就会拒绝所有没有对应容忍的 Pod 落在这台节点上。这相当于给了平台组件一个缓冲时间让运维人员去修复设备、或把业务慢慢迁移到其他节点。而容忍则是工作负载侧的配合声明。真正依赖 RDMA 的 Pod 需要显式声明自己可以接受这种异常状态否则也会被拒之门外tolerations: - key: rdma.network/device-offline operator: Exists effect: NoSchedule3.2 NoSchedule 与 NoExecute两者分别影响什么如果给节点打的是NoSchedule已经运行在节点上的 Pod 不会立刻被驱逐它只是阻止新的 Pod 调度过来。对于设备故障这种场景这个效果可能还不够——因为故障设备节点上可能还残留着一些依赖该设备的存量 Pod它们已经不再健康了。这时可以选择使用NoExecute。它更激进一旦生效节点上所有没有匹配容忍的 Pod 都会被驱逐。驱逐过程会触发优雅终止从而让本地 CSI 卷卸载给平台组件留出收敛时间kubectl taint nodes cn-021 rdma.network/device-offlinetrue:NoExecute对比来看污点效果阻止新 Pod 调度驱逐存量 Pod适用场景NoSchedule是否设备暂时不可用后续可能恢复NoExecute是是设备彻底损坏需要立即迁移业务PreferNoSchedule软性倾向不强制否设备负载较高但不是不可用在我遇到的这个案例里需要的是NoSchedule。设备只是维护后暂时没有识别成功还没有到彻底报废的程度。如果直接NoExecute会让更多 Pod 无谓迁移反而增加其他节点的压力。3.3 关键疑点为什么设备消失后污点没有自动打上到这里回头看真正需要反思的问题是为什么设备消失后节点没有自动获得“设备异常”的污点Kubernetes 默认对OutOfDisk、NetworkUnavailable等问题会给节点自动添加污点但 RDMA 这类通过自定义 device plugin 管理的资源并不在内置的健康检查列表里。除非平台开发了额外的 controller去监听 device plugin 的上报结果并且自动给节点打污点否则节点就会一直保持“设备异常但可调度”的状态。这个机制缺陷很容易被忽视。很多平台在搭建时只实现了设备资源的上报却没有实现“设备异常与节点状态的联动”。一旦硬件真的出问题运维只能靠人工发现、人工打污点、人工恢复。这不叫自动化这是半自动化。4. 修复路径与长期沉淀从手工打污点到设备生命周期纳入节点管理4.1 短期的恢复操作按顺序处理别先删 Pod确认根因后我们没有直接去重启 CSI 驱动或批量删除 Pod而是按这个顺序恢复先把出问题的三台节点全部打上NoSchedule污点且保证依赖 RDMA 的工作负载不具备对应容忍从源头阻断新的错误调度。针对已经卡在ContainerCreating的 Pod通过kubectl delete pod触发重新创建。此时调度器会因污点过滤掉问题节点把 Pod 重新放到健康节点。检查这些 Pod 是否携带了硬性的nodeAffinity指向原节点。如果有需要评估是否临时放宽调度约束否则删除 Pod 也不会让它们去别的节点。修复节点上的 RDMA 设备驱动状态等待 device plugin 重新上报资源。资源恢复后再移除节点的污点。观察监控曲线确认挂载错误消失、Pod 全部Running后再继续后续的硬件变更。有人可能会问为什么不能直接重启 kubelet 或 CSI 驱动因为问题节点上可能还运行着一些不依赖 RDMA 的正常任务盲目重启会让它们跟着遭殃。先用污点隔离再用定向删除去触发失败 Pod 重调度影响范围最小。4.2 配置层面的补强让工作负载的调度约束带有安全兜底经过这次故障我们对工作负载配置做了几处调整。第一处是给使用 RDMA 资源的 Pod 统一补充了节点选择逻辑让它们只在明确带有 RDMA 设备标签的节点上运行nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: rdma.network/hca operator: Exists这样即使节点出现异常调度器也会优先检查标签配合污点过滤双重保险之下Pod 被放到错误节点的概率大幅降低。第二处是给这类工作负载增加对应的容忍配置。容忍不是为了让自己能调度到故障节点而是为了在后续设备自动检测机制上线后平台可以选择性地对“短期维护”而不是“永久故障”做更平滑的处理。第三处是调整 CSI 挂载重试策略。默认情况下kubelet 会不断重试失败的挂载操作持续产生错误事件。我们给 CSI 驱动补充了更明确的NodePublishVolume错误码让它在检测到设备不存在时快速返回失败而不是等待文件系统挂载超时。4.3 把“节点污点状态”纳入日常巡检和告警故障结束之后我们把巡检逻辑改进了不再只监控节点Capacity中rdma/hca的数量还要监控“资源数量变化”与“节点污点状态”之间的时间差。简单来说如果发现某个节点上rdma/hca数量下降但这个节点没有出现rdma.network/device-offline相关污点就直接触发告警。告警文案会直接提示“设备资源缺失但节点未隔离”这样可以避免运维团队在海量日志里重新定位。实现上并不复杂只需要写一个定时任务定期抓取节点状态和污点信息做一次交叉比对# 简易巡检命令示例 for node in $(kubectl get nodes -o name); do taints$(kubectl get $node -o jsonpath{.spec.taints[*].key}) capacity$(kubectl get $node -o jsonpath{.status.capacity.rdma\.hca}) echo $node capacity$capacity taints$taints done这个脚本虽然简陋但已经能在运维层面形成一个“资源状态-调度状态”的对照视图。4.4 远期方案把设备生命周期纳入节点生命周期而不是靠人工打污点短期手段终究依赖人工长期还是得靠自动化。我们后续的方向是开发一个专门的核心模块监听 device plugin 的上报结果。一旦发现某个节点上设备数量和预期不一致就自动向该节点注入对应污点并在设备恢复后自动移除。这个模块本质上做的事情并不复杂它把“设备数量正常”定义为节点健康的一部分而不是让节点等到 CPU 或内存耗尽时才被系统认为异常。毕竟对于 RDMA 这类专用硬件设备消失带来的影响不亚于磁盘故障甚至更隐蔽。同时还要在存储侧做联动优化。CSI 驱动在NodePublishVolume阶段发现设备不存在时可以通过事件回调通知调度器把该 Pod 标记为“需要重新调度”。目前社区中这类能力更多依赖外部控制器实现但对于追求稳定的生产环境这一步值得投入。我自己在几次类似的故障中最大的体会是高性能计算平台的稳定性不只是每个组件各自表现优异更重要的是这些组件之间的状态语义要能够互相传播。RDMA 设备从节点消失本身并不可怕可怕的是整个平台对此“无感”——kubelet 无感、调度器无感、CSI 无感直到业务真的挂掉才把问题暴露出来。污点与容忍在这里起的作用就是让“节点已经异常”这个信息被其他组件看见给它们足够的上下文去做出正确决策。最后分享一个很有用的排查小技巧以后再遇到“资源没了”和“挂载失败”一起出现时先查一下节点describe里的Taints字段如果 Taints 为空这本身就是一条重磅线索。它意味着平台缺少一层关键的故障隔离逻辑而补上这层逻辑往往比修复任何一个组件都更值钱。
📌 标签:
工业官网
设计趋势
AI 建站
SEO
获取完整报告 →
RELATED ARTICLES
推荐阅读
2026/10/10 19:58:49
Java开发必会:Dom4j解析XML,从读写到XPath实战避坑
2026/10/10 19:58:49
Dom4j实战:Java XML解析、节点遍历与XPath定位全攻略
2026/10/10 19:58:49
Mailcow 自建邮件服务器实战:Docker 部署与收发调优
2026/10/10 20:38:54
自主AI Agent时代来临:思科为何推出“Claw”安全框架
2026/10/10 20:38:54
腾讯 QClaw 内测上手:微信操控电脑的 AI Agent,对标 OpenClaw 的 TaoToken 配置思路
2026/10/10 20:38:54
风机叶片缺陷检测数据集:18912张图与YOLO/COCO/VOC格式实战
2026/10/10 20:38:53
YOLOv5反光衣安全帽检测:DeepStream+TensorRT工业部署实战
2026/10/10 20:38:53
国赛C题农作物种植策略:线性规划建模与Python实现全解析
2026/10/10 20:33:53
环形数组上的滑动窗口:从丢手绢到单调队列优化
2026/10/10 0:03:38
工业软件标准化路线图:国产替代的落地施工图
2026/10/10 0:03:38
VCMI安卓版实操指南:原生运行英雄无敌3的3步技术落地
2026/10/10 0:03:38
稀疏多通道盲反褶积的MATLAB算法实现与参数调优
2026/10/10 3:42:06
Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化
2026/10/10 3:42:01
多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系
2026/10/10 3:41:58
hindsight:面向LLM应用的事后可观测性工程实践
2026/10/10 3:41:56
我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
2026/10/10 3:41:54
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026/10/9 11:36:17
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)