在很久以前,有一个老爷爷,种下了一棵葫芦,变成了七个各有绝学的葫芦娃。可惜葫芦变成的七个葫芦娃为了保卫和平,救出爷爷,逐一被蛇精和蝎子精抓到了。蛇精和蝎子精想把七个葫芦娃炼成七心丹,没想到七个葫芦娃合体成为了葫芦小金刚,踢碎了炼丹炉,经过艰苦的战斗,最后打败了各路妖魔鬼怪,让山谷恢复了往日的和平。
时光流淌到了计算机与移动互联网时代,葫芦娃的故事又再次变身。
在《植物大战僵尸》中,玩家可以种植各类植物,发挥它们的长处,齐心协力打败各类僵尸,最后击败僵尸博士取得胜利。
小H发现,《植物大战僵尸》和《葫芦娃》的故事最大的差异,就在于,在《植物大战僵尸》中,可以根据业务需求场景,来快速创建或销毁各类植物实例,而《葫芦娃》中具备每个功能的葫芦娃都只有一个,不能基于场景弹性扩容,才会被蛇精和蝎子精挨个捉住。
小H突然明白了,所谓的“云原生”,最大的特点就是,可以做到在业务压力下,快速克隆一批应用实例,在业务压力过去后又可以销毁实例释放资源。
实现快速克隆实例的方法有两种:
一种是使用虚拟机,从开始创建虚拟机到虚拟机网络可达,其极限时间大约是分钟级别;
另一种是使用容器,从容器启动到容器服务可用,需要的时间为秒级;
显然,选择容器更容易实现快速的服务弹性伸缩,在AI与大模型时代,使用容器化方式部署训练和推理应用也成为了一种流行的架构方案,也就是将AI相关的应用打包为容器镜像部署,并可以快速弹性伸缩,利用容器的特性来高效调度GPU。
在前几篇,我们研究了如何实现把GPU通过PCI-E设备直通方式分配给虚拟机,通过虚拟化程序来调度GPU。那么,有没有类似的方案将GPU直通给容器呢?
在早期Kubernetes版本中,在程序代码中实现了把NVidia的GPU分配给容器使用,也就是在创建容器时,允许这个容器的namespace访问GPU。这种方式叫做in-tree方式,也就是在程序代码中对GPU做特殊处理。这种实现的缺点非常明显:随着NVidia的GPU推陈出新,需要不定期对Kubernetes的主干代码进行修改,才可以添加对新款型GPU的支持。如果还需要对其他硬件进行直通,则又需要修改Kubernetes的代码。
显然,这违反了基础架构的两大设计原则:
第一点是“对修改封闭,对扩展开放”,也就是尽量在避免修改代码基础逻辑,不增加更多if-else判断的情况下扩展更多功能;
第二点是“提供机制而不提供策略”,也就是像Kubernetes这样的基础架构软件更多地应当提供机制给用户和开发者使用,而不是代替用户和开发者做策略方面的判断;
因此,在2018年,NVidia对Kubernetes做了一项革新:把GPU针对容器的驱动抽象出来,建立Kubernetes的一个插件模型——Device Plugin。
Device Plugin 可以让工作节点上的GPU设备(其实在Linux下就是一个文件)能够直接被容器使用,同时其他容器无法使用该设备。它的工作原理是:
4. kubelet把收到的路径/文件名指定namespace,与这个容器的namespace一致,使得其他容器无法访问到这个路径/文件名,也就是让GPU被这个容器独占。
我们发现,Device Plugin实际上的工作,是将Linux下的一个设备指定给容器使用,这个设备并不限于必须是GPU。因此,业界也出现了各类其他Device Plugin,包括网卡、SSD、FPGA卡等。但Nvidia对Kubernetes的这一贡献也将被铭记史册。
无论是虚拟机直通,还是device plugin,调度的颗粒度都是整张GPU卡。这就引发了另一个非常有趣的领域——
请看下期。