Kubernetes在CPU集群中的自动扩缩容已经比较成熟,但到了GPU集群,情况会复杂得多。原因并不是简单的“GPU比CPU贵”,而是GPU工作负载通常具有资源粒度特殊、节点启动成本高、任务持续时间长、镜像和模型体积大以及GPU类型存在差异等特点。一个Pod等待GPU资源,并不意味着增加一台节点以后马上就能运行,中间还有一整套节点初始化和资源注册过程。
首先要理解Kubernetes到底在扩什么。HPA主要负责根据指标增加或减少Pod副本数量,它并不直接负责创建GPU节点。当新的Pod因为没有足够的GPU资源而处于Pending状态时,Cluster Autoscaler或者云厂商提供的节点自动扩缩容系统,才可能根据调度结果增加GPU节点。因此GPU自动扩缩容实际上是两层甚至多层控制系统协同工作的结果:工作负载扩缩容、Kubernetes调度以及节点供应系统必须彼此配合。
GPU资源的特殊性首先体现在资源粒度上。NVIDIA GPU通常通过device plugin向Kubernetes注册为类似nvidia.com/gpu的扩展资源,Pod可以请求一定数量的GPU。传统GPU资源一般不像CPU那样可以随意按照millicore进行共享,因此一个需要整张GPU的任务,必须等待拥有可用GPU的节点出现。
但“GPU不能切分”又说得太绝对。部分NVIDIA GPU支持MIG(Multi-Instance GPU),可以把一张支持MIG的GPU划分成多个隔离的GPU实例;一些环境也采用时间共享、MPS或其他共享机制。问题在于,不同技术提供的资源语义不同,调度器看到的资源也不同。于是GPU扩缩容首先遇到的不是单纯的容量问题,而是“需要什么类型的GPU”。
例如,一个Pod要求某种GPU资源,但集群新增的节点提供的是另一种GPU,即使节点上还有空闲GPU,也不一定能够满足这个Pod。实际生产环境通常需要结合节点标签、taint/toleration、node affinity以及GPU型号等条件进行调度。这也是GPU集群比普通CPU节点池更容易出现“明明还有机器,却调度不上去”的原因之一。
GPU节点启动速度也是自动扩缩容的重要瓶颈。普通CPU节点启动后,只需要完成操作系统、网络、kubelet以及必要的容器运行时初始化,就可以逐渐进入可调度状态。GPU节点则还需要GPU驱动、容器运行时GPU支持、NVIDIA device plugin等组件正确工作。只有GPU资源已经被Kubernetes注册并进入可调度状态,等待中的Pod才真正有机会运行。
因此,云平台控制面显示“GPU实例已经创建”,并不等于Kubernetes已经拥有一张可以使用的GPU。真正决定扩容延迟的是从节点创建开始,到Node Ready,再到GPU device plugin成功注册资源,最后到Pod完成调度这一整条链路。
GPU节点还有一个经常被低估的问题,就是容器镜像和模型准备时间。很多GPU工作负载使用大型CUDA基础镜像,同时还需要下载数GB甚至数十GB的模型、数据集或者Python依赖。假设节点已经Ready,但镜像还在拉取,或者启动脚本仍在准备模型,那么从用户角度看,这台GPU节点仍然没有真正提供服务。
这也是为什么GPU集群不能只盯着Node启动时间。实际应该测量一个完整指标,例如从Pod进入Pending开始,到Pod真正获得GPU并进入Running状态所需要的时间。这个指标才真正反映用户感受到的扩容延迟。
GPU任务的持续时间也会影响自动扩缩容策略。CPU Web服务可能几秒钟内完成一次请求,Pod副本数可以比较快地上下变化;GPU训练任务则可能运行几十分钟、几小时甚至几天。如果自动扩容系统反应过于迟钝,新GPU节点可能迟迟不到;如果缩容过于激进,又可能在训练任务即将继续使用GPU时提前回收节点。
因此GPU集群通常需要更加谨慎的scale-down策略。正在运行训练、推理或批处理任务的节点不能简单按照CPU利用率判断是否可以删除。节点上的Pod是否能够被安全驱逐、任务是否支持checkpoint恢复、GPU作业是否已经完成,往往比CPU利用率更加重要。
GPU监控同样不能只看一个“GPU利用率”。例如,GPU计算利用率达到90%,并不意味着显存也接近满载;反过来,一张GPU可能长期占用大量显存,但计算单元却处于低利用率状态。对于推理服务,还需要观察请求队列、tokens/s、batch size、显存占用、GPU utilization以及请求延迟等指标。
Prometheus本身并不是无法监控GPU。通常可以通过NVIDIA DCGM Exporter等组件把GPU指标暴露给Prometheus,再由Prometheus Adapter或其他指标系统提供给Kubernetes控制器。真正困难的是选择哪个指标用于扩缩容。
例如,GPU utilization持续达到90%并不一定意味着应该增加Pod,因为瓶颈可能来自显存、CPU预处理、网络或者模型本身。反过来,如果GPU利用率只有40%,但请求队列不断增加,增加GPU副本可能仍然有意义。因此生产环境更适合把业务指标与GPU指标结合起来,而不是简单复制CPU的HPA阈值。
节点供应本身也是GPU集群特有的问题。GPU云实例通常比普通CPU实例更加依赖具体硬件库存。即使Kubernetes已经判断需要增加节点,云平台也可能暂时没有目标GPU型号的可用容量。于是自动扩缩容链路可能变成:Pod Pending、Autoscaler发现资源不足、请求云平台创建节点、云平台寻找GPU容量、实例启动、驱动初始化、节点加入Kubernetes、GPU注册、镜像拉取,最后Pod才能运行。
这条链路中的任何一个环节出现延迟,用户都会看到“GPU扩容很慢”。
因此,GPU集群通常需要提前设计节点池,而不是只建立一个巨大的GPU节点池。不同GPU型号、不同容量以及不同用途可以通过多个Node Pool进行管理,并结合标签、taint和调度规则,让训练、推理和批处理任务进入适合自己的节点池。对于对启动延迟敏感的推理业务,还可以保留一定数量的warm GPU nodes,让部分GPU容量始终在线。
GPU资源的碎片化也是另一个实际问题。假设一个节点拥有8张GPU,已经运行了几个任务,剩下的GPU数量可能看起来足够,但如果Pod要求特定GPU类型、特定MIG profile或者多个GPU同时位于同一节点,剩余资源就未必能够满足调度条件。这种情况下,集群总GPU数量并不能代表真正的可用容量。
对于多GPU训练任务,问题会更加明显。一个任务可能需要4张或8张GPU,并且对GPU之间的通信拓扑有要求。PCIe、NVLink、NUMA以及GPU拓扑都会影响实际性能。一个节点“有8张GPU”与“能够按照任务要求提供8张合适的GPU”并不是完全相同的概念。
因此,GPU自动扩缩容真正需要优化的不是某一个启动步骤,而是整个资源生命周期。应该从Pod提交开始跟踪Pending时间、调度时间、节点创建时间、Node Ready时间、GPU资源注册时间、镜像拉取时间以及应用真正Ready的时间。只有把这些时间拆开,才能知道扩容到底慢在哪里。
在架构设计上,一个比较可靠的GPU自动扩缩容体系通常包括GPU device plugin或相应资源管理组件、合理的节点池、Cluster Autoscaler或其他节点自动扩缩容系统、DCGM等GPU监控、Prometheus指标体系,以及针对训练和推理业务设计的扩缩容指标。对于需要快速响应的服务,还需要考虑预留GPU容量,而不是完全依赖“出现请求以后才开机器”。
最终,GPU Kubernetes集群的核心问题不是“能不能自动扩容”,而是“从需求出现到GPU真正可用,中间需要多长时间,以及这段时间是否能够满足业务要求”。CPU集群可以依靠快速创建节点和Pod副本应对短周期流量,而GPU集群面对的是更加昂贵、更稀缺、启动链路更长的计算资源。理解这一点以后,自动扩缩容的设计重点自然会从单纯的CPU利用率,转向GPU型号、资源碎片、节点供应、任务生命周期、业务队列和端到端启动延迟。对于真正运行大规模AI训练和推理业务的团队来说,能够把这些环节测量清楚,往往比单纯增加Autoscaler的复杂规则更加重要。
Kubernetes 自动扩缩容为什么对 GPU 集群更加困难,GPU 节点启动过程有哪些特殊问题
图片说明:示意图 图片来源:Public Domain(公有领域)
喜欢这篇报道?
使用下面的功能,方便以后继续阅读和分享 MNewsTV
关于文章收藏
收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。
删除收藏请进入「我的收藏」进行管理。
捐助(Paypal): https://www.paypal.me/observeccp 订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP