内容提要
Kubernetes调度与Cilium网络策略因拓扑感知差异,导致分布式训练协调器与GPU工作节点跨可用区隔离,训练停滞且GPU闲置。修复无需改动CNI,仅通过节点亲和性和拓扑分布约束将Pod同区部署,即可消除网络阻断、延迟和跨区成本,GPU利用率从40%提升至85%。
延伸解读
两个正确系统为何会集体出错
Kubernetes调度器默认不考虑拓扑,只按资源分配Pod;而Cilium网络策略则基于可用区划分边界,两者各自正确却互不知情。当协调器与GPU工作节点被分到不同可用区时,网络策略会静默阻断通信,导致训练停滞、GPU闲置。这种“集体错误”在分布式系统中并不罕见,关键在于缺乏一个能同时看到Pod位置和网络策略的全局视图。
故障的三种表现与排查难度
同一根因在现实中表现为三种症状:硬阻断(训练立即失败)、跨区延迟(吞吐量下降30-60%但无报错)、跨区流量成本(账单增加)。硬阻断容易发现,但后两种需要数小时甚至数天才能察觉。作者强调,监控GPU利用率和Pod所在可用区指标至关重要,否则问题可能长期潜伏,造成资源浪费和成本超支。
修复思路:不改CNI,只调调度
修复方案出奇简单:无需修改Cilium或Kubernetes,只需在Pod规格中添加节点亲和性和拓扑分布约束,将协调器与工作节点强制部署在同一可用区。这样流量变为区内通信,硬阻断、延迟和跨区成本全部消失。作者还提供了可复现的实验室环境,帮助读者验证问题并观察GPU利用率从40%提升至85%的效果。
Q&A
Kubeflow与Cilium结合时,为什么会出现GPU闲置但训练不启动的情况?
因为Kubernetes调度器是拓扑无关的,它只根据资源(如CPU、内存、GPU数量)调度Pod,不考虑可用区;而Cilium网络策略是拓扑感知的,会按可用区设置网络隔离。当协调器Pod和GPU工作节点Pod被调度到不同可用区时,Cilium策略会阻断它们之间的网络连接,导致训练无法开始,GPU闲置。
如何修复Kubeflow与Cilium导致的GPU闲置问题?
修复方法是在工作负载的YAML中添加节点亲和性(nodeAffinity)和拓扑分布约束(topologySpreadConstraints),将协调器和GPU工作节点调度到同一个可用区,并添加容忍度(toleration)使协调器能调度到有GPU污点的节点。这样流量变为区内流量,网络阻断、延迟和跨区成本都会消失。
Cilium网络策略导致的问题有哪些表现形式?
有三种表现形式:1. 硬阻断:网络策略直接拒绝跨区连接,训练无法启动,立即被发现;2. 跨区延迟:没有硬阻断,但梯度同步(如NCCL AllReduce)需要跨区往返,吞吐量下降30-60%,无错误提示,数小时后才被注意;3. 跨区出口成本:流量跨可用区产生数据传输费用,数天后在账单上体现。
为什么说Kubernetes调度器对Cilium的网络策略是盲目的?
因为Kubernetes调度器在设计上是拓扑无关的,它只考虑资源可用性,不考虑Pod会被调度到哪个可用区;而Cilium网络策略是拓扑感知的,它根据可用区设置网络隔离。调度器无法感知Cilium的策略,因此可能将Pod调度到被网络策略隔离的可用区,导致通信失败。
修复这个问题需要修改CNI或Kubernetes吗?
不需要。修复完全基于Kubernetes原生特性,只需在工作负载的YAML中添加节点亲和性、拓扑分布约束和容忍度,无需修改Cilium或Kubernetes本身。
如何在不硬编码可用区名称的情况下实现Pod同区部署?
可以使用podAffinity,以可用区作为拓扑键,将工作节点Pod调度到协调器Pod所在的可用区。这样通过关系而非硬编码实现同区部署,且可跨集群移植。
修复后GPU利用率提升了多少?
在实验室环境中,修复后GPU利用率从约40%提升到约85%。
如何监控和发现这类问题?
建议提前监控GPU利用率和Pod所在可用区等指标,使用Prometheus和Grafana可以快速暴露问题。文章中提到,没有这些监控,问题可能需要数天才能被发现。