Kubernetes GPU 集群十大坑:调度、网络和存储篇

📅 2026/7/28 13:30:05
Kubernetes GPU 集群十大坑:调度、网络和存储篇
Kubernetes GPU 集群十大坑调度、网络和存储篇基础设施不需要漂亮话。GPU 集群和普通 CPU 雨群的区别不只是贵了十倍而是运维难度也贵了十倍。我们团队管理一个 40 节点的 GPU 集群半年踩了十个坑每一个都花了至少一天排查。这篇文章把调度、网络和存储三个维度的坑全部列出来附带解决方案。一、背景GPU 集群为什么比 CPU 集群难管GPU 资源有三个特点昂贵、稀缺、不可细粒度共享。CPU 可以按核心分配一台 64 核的机器可以跑几十个服务。GPU 不行一个推理服务往往独占整张卡8 卡节点上最多跑 8 个服务。这三个维度的问题互相关联调度失败了可能是因为存储没准备好网络问题可能表现为 NCCL 初始化超时存储瓶颈可能被误判为调度问题。二、调度篇四大坑坑 1GPU 资源碎片化——8 卡节点只剩 1 卡可用场景一个 8 卡 A100 节点上7 张卡被不同服务占用剩 1 张空闲。新来了一个需要 2 卡的训练任务调度器找不到合适的节点任务一直 Pending。更糟糕的情况集群总共有 80 张 GPU但碎片化后任何需要 4 卡以上的任务都无法调度。GPU 利用率 87%但有效利用率可能只有 30%。解法使用 GPU 共享插件如 NVIDIA GPU Operator 的时间片模式让小推理任务填碎片。训练任务使用 Gang Scheduling要么全部 GPU 一起调度要么不调度。定期用 Descheduler 重平衡把碎片化节点上的 Pod 搬到更紧凑的位置。坑 2Pod 调度失败但不告诉你原因GPU Pod 一直 Pendingkubectl describe pod只显示 0/40 nodes are available。不告诉你是因为 GPU 数量不够、节点有污点、还是亲和性规则冲突。排查 GPU 调度失败的流程比 CPU Pod 复杂 5 倍因为 GPU 资源不在标准 Node 的allocatable字段里需要看nvidia.com/gpu这个扩展资源。解法写一个调度诊断脚本自动检查每个节点的 GPU 可用量、污点、亲和性。用kubectl get nodes -o custom-columnsNAME:.metadata.name,GPU:.status.allocatable.nvidia\\.com/gpu快速查看 GPU 分配。给关键训练任务加schedulerName使用自定义调度器记录详细的调度决策日志。坑 3扩容震荡——Cluster Autoscaler 刚扩完就缩GPU 节点从云厂商按需购买一台 A100 节点每小时 30-50 元。Autoscaler 在高峰期扩了 5 个节点高峰过后 10 分钟内就把这 5 个节点缩掉了。但下一个高峰 30 分钟后就来又扩 5 个节点。一天扩缩 8 次每次扩容要等 3-5 分钟节点初始化。结果业务方在每次扩容窗口期间请求全部排队而云厂商按整小时计费缩了又扩等于白花钱。解法设置scale-down-delay-after-add至少 30 分钟扩容后不急着缩。GPU 节点组单独配置和 CPU 节点组的扩缩策略分开。使用预留实例Reserved Instance覆盖基线负载按需实例只做弹性补充。坑 4优先级抢占导致训练中断在线推理服务设了高优先级训练任务设了低优先级。高峰期推理服务扩容抢占训练任务的 GPU。训练任务被驱逐已经跑了 12 小时的训练从头再来。解法训练任务使用 PodDisruptionBudget最少保留一定数量的 Pod 不被驱逐。推理和训练分不同节点池物理隔离优先级抢占。训练任务实现 checkpoint 定期保存被驱逐后可以从最近的 checkpoint 恢复不用从头开始。三、网络篇三大坑坑 5多卡推理的 NCCL 通信卡死多卡分布式推理依赖 NCCL 进行 GPU 间通信。NCCL 初始化时要发现所有参与 GPU 的拓扑关系然后建立通信通道。如果网络配置不对NCCL 初始化可能卡 10 分钟然后超时退出。常见原因CNI 插件没有正确配置 GPU 节点间的路由或者 firewall 规则阻断了 NCCL 使用的端口范围通常是 50000-60000。解法GPU 节点间使用 RDMA 网络RoCE 或 InfiniBandNCCL 优先用 RDMA 绕过 CPU。确认 CNI 配置允许 GPU Pod 间的直连通信不要走 NAT。在 NCCL 环境变量中设置NCCL_DEBUGINFO初始化失败时能看到详细的拓扑发现日志。给多卡 Pod 设置hostNetwork: true减少一层网络封装开销。坑 6GPU Pod 间直连通信被 Service 阻断Kubernetes Service 默认用 iptables 或 IPVS 做负载均衡会把流量分散到不同 Pod。但多卡推理需要指定 GPU 之间的通信对不能被负载均衡打散。解法多卡推理 Pod 使用 StatefulSet每个 Pod 有稳定的网络标识。GPU 间通信使用 Pod IP 直连不走 Service。如果必须走 Service用 Headless Service 返回所有 Pod IP客户端自己选择目标。坑 7大规模 Pod 的 DNS 解析变慢一个 GPU 集群上跑 200 推理服务 Pod每个 Pod 启动时要做 DNS 解析发现其他服务。CoreDNS 单副本扛不住这个解析压力Pod 启动时间从 5 秒变成 30 秒其中 25 秒在等 DNS。解法CoreDNS 部署多个副本用 HPA 根据 QPS 自动扩缩。调整 NodeLocal DNSCache在每个节点上缓存 DNS 结果减少对 CoreDNS 的直接查询。Pod 的/etc/resolv.conf设置ndots:2减少不必要的搜索域查询。四、存储篇三大坑坑 8模型权重 PVC 挂载失败模型权重文件 10-50GB存储在 NFS 或 Ceph 上。Pod 启动时挂载 PVC如果存储后端响应慢挂载可能要 60 秒以上。Kubernetes 默认的 Pod 启动超时可能比这个时间短导致 Pod 被杀掉重启。更常见的问题多个 Pod 同时挂载同一个 PVC只读模式存储后端扛不住并发读第一个 Pod 挂载成功后面的 Pod 挂载超时。解法模型权重用 Local PV 节点预分发。每个 GPU 节点本地有一份模型文件Pod 启动直接从本地磁盘加载。对于必须用分布式存储的场景用 CSI 驱动的mountOptions设置更长的超时时间。PVC 挂载完成后再触发模型加载不要在容器启动脚本里假设挂载已经完成。坑 9本地缓存和分布式存储的取舍推理服务加载模型后会在内存中缓存。但模型更新时怎么保证所有副本同时更新分布式存储方案所有 Pod 从同一个 PVC 读更新一次所有 Pod 都能看到。但读取速度慢。本地缓存方案每个节点本地存一份读取快但更新要逐节点同步可能出现短暂版本不一致。解法混合策略。模型权重文件预分发到每个节点的本地 NVMe 盘上通过 ConfigMap 或 CRD 管理当前版本。更新时发一个通知所有节点异步拉取新版本到本地拉取完成后再触发滚动更新。坑 10GPU 节点存储 IO 瓶颈GPU 推理的瓶颈不在计算而在数据喂给 GPU 的速度。如果存储 IO 慢GPU 就在等数据利用率显示 30% 但并不是因为模型小而是因为数据通道慢。实测数据NFS 挂载的读取速度约 200MB/s本地 NVMe 的读取速度约 3GB/s。7B 模型权重 14GBNFS 加载需要 70 秒本地 NVMe 只需要 5 秒。解法GPU 节点配备本地 NVMe 盘用于模型权重和推理数据的缓存。CSI 驱动选择支持拓扑感知的方案确保 PVC 在正确的节点上创建。监控存储 IO 延迟当iowait超过 10% 时触发告警。五、避坑全景图六、总结GPU 集群的运维本质上是资源管理问题。十个坑的共性规律GPU 不能像 CPU 那样灵活分配碎片化是常态需要主动管理。网络配置对 GPU 通信影响极大NCCL 问题排查要先查网络。存储 IO 是 GPU 利用率的隐形瓶颈GPU 不报错但会空等数据。调度、网络、存储问题互相关联排查时三个维度都要检查。成本管理要贯穿每一个决策GPU 太贵每个浪费都在放大成本。基础设施不需要漂亮话管好 GPU 集群就是管好公司的钱。