从零开始的异生活初始_从零开始入门 K8s | GPU 管理和 Device Plugin 工作机制

随着近年来的发展,人工智能有了很多登陆场景,包括智能客服、人脸识别、机器翻译、地图搜索等功能事实上,机器学习或人工智能并不是一个新概念。然而,在这股热潮的背后,云计算的普及和计算能力的大幅提高是真正将人工智能从象牙塔带入工业的重要推动力。

从零开始的异生活初始

对应于此。自2016年以来,Kubernes社区收到了来自不同渠道的大量需求:希望在Kubernes集群上运行TensorFlow等机器学习框架。在这些需求中,除了管理离线任务(如前几篇文章中描述的作业)之外,还有一个巨大的挑战:深度学习所依赖的异构设备和Avida的图形处理器支持

我们不禁要问:库本内斯能给管理GPU带来什么好处?

本质上是一个成本和效率的考虑因素。由于与中央处理器相比,图形处理器的成本相对较高在云上,单个中央处理器通常每小时花费几美分,而一个图形处理器的成本从每小时10元到30元不等,这需要尽一切努力提高图形处理器的利用率。

为什么使用库本涅斯来管理以GPU为代表的异构资源?

具体包括三个方面:加速部署:通过容器概念避免机器学习复杂环境的重复部署;提高集群资源利用率:统一调度和分配集群资源;确保资源的独占使用:使用容器隔离异构设备,避免相互影响。

首先加快部署,避免在环境准备中浪费时间。通过容器镜像技术,整个部署过程得以固化和重用。如果学生关注机器学习领域,他们会发现许多框架提供容器镜像。我们可以提高图形处理器的效率

通过分时复用提高了GPU的效率当GPU卡的数量达到一定数量时,库本内斯需要统一的调度能力,使资源用户能够尽快申请,并在完成后尽快释放,从而激活整个GPU的资源库。

,此时需要Docker的设备隔离能力,以防止不同应用程序的进程在同一设备上运行并相互影响。在高效率、低成本的同时,系统的稳定性也得到了保证。上面的

了解通过Kubernetes运行GPU应用程序的好处。我们还从前面的一系列文章中了解到,Kubernetes是一个容器调度平台,调度单元是一个容器。因此,在学习如何使用库本内斯之前,让我们先了解如何在容器环境中运行GPU应用程序。

1。在容器环境中使用图形处理器应用程序

在容器环境中使用图形处理器应用程序实际上并不复杂主要分为两个步骤:构建支持图形处理器的容器图像;图像由Docker运行,图形处理器设备和依赖库被映射到容器中。

2。准备GPU容器映像

有两种方式:直接使用正式的深度学习容器映像

,例如直接从docker.hub或ariyun image service中查找正式的GPU映像,包括流行的机器学习框架,如TensorFlow、Caffe、PyTorch等。都提供标准图像。优点是简单、方便、安全可靠。基于Nvidia的CUDA镜像基础构建

当然,如果官方映像不能满足要求,例如,如果您对TensorFlow框架进行了自定义修改,您需要重新编译并构建自己的TensorFlow映像。在这种情况下,我们的最佳做法是继续以英伟达的官方形象为基础,而不是从头开始。下图中的TensorFlow示例显示了

。这是开始建立自己的图形处理器图像基于Cuda图像。

从零开始的异生活初始

3。图形处理器容器镜像原理

要理解如何构建图形处理器容器镜像,首先需要知道如何在主机上安装图形处理器应用程序下图左侧显示了

。底层是首先安装Nvidia硬件驱动程序。上面是通用Cuda工具库。顶部是机器学习框架,如PyTorch和TensorFlow。CUDA工具库两层与

上应用程序的耦合度相对较高。在应用程序版本更改后,相应的CUDA版本将很有可能更新。最低的Nvidia驱动程序通常相对稳定,不会像CUDA和应用程序那样频繁更新

从零开始的异生活初始

同时Nvidia驱动需要内核源代码编译。如上图右侧所示,英伟达的GPU容器方案是在主机上安装英伟达驱动程序,而CUDA之上的软件则交给容器映像来完成。同时,Nvidia驱动程序中的链接以装载绑定的方式映射到容器。

的一个优点是,当您安装新的Nvidia驱动程序时,您可以在同一机器节点上运行不同版本的CUDA映像。

4。如何使用容器

运行图形处理器程序有以前的基础,我们可以很容易地理解图形处理器容器的工作机制下图是使用Docker运行图形处理器容器的示例

从零开始的异生活初始

我们可以观察到,运行时GPU容器和普通容器之间的区别只是主机设备和Nvidia驱动程序库需要映射到容器中。

上方的右图反映了启动后图形处理器容器中的图形处理器配置。右上角显示设备映射的结果,右下角显示驱动程序库通过绑定映射到容器后可以看到的更改人们通常使用Nvidia-docker来运行GPU容器,Nvidia-docker的实际工作是将这两项任务自动化其中,安装设备相对简单,但更复杂的是GPU应用程序所依赖的驱动程序库。

针对不同场景使用不同的驱动程序库,例如深度学习和视频处理。这反过来又依赖于Nvidia的领域知识,这些知识贯穿Nvidia的容器。

1。如何部署GPU Kubernetes

首先看一下如何向Kubernes节点添加GPU功能,让我们以CentOS节点为例

从零开始的异生活初始

如上图所示:首先安装Nvidia驱动程序

由于Nvidia驱动程序需要内核编译,在安装Nvidia驱动程序之前需要安装gcc和内核源代码第二步是通过百胜源安装Nvidia docker2

。安装Nvidia docker2后,您需要重新加载docker。您可以检查Docker守护程序. json中的默认启动引擎是否已被nvidia替换,或者您可以通过docker info命令检查运行时使用的runC是否是Nvidia的runC。第三步是部署英伟达设备插件

。从Nvidia的git repo下载设备插件的部署声明文件,并通过kubectl create命令进行部署

设备插件在这里以无声的方式部署这样,我们知道如果我们需要解决库本内节点无法调度GPU应用程序的问题,我们需要从这些模块开始。例如,我想检查设备插件的日志,Nvidia的runC是否被配置为docker默认runC,以及Nvidia驱动程序是否安装成功。

2。GPU部署的验证库本内斯结果

当GPU节点部署成功时,我们可以从节点状态信息中找到相关的GPU信息一个是图形处理器的名字,这是nvidia.com/gpu.,另一个是它的对应号码,如下图所示,是2,表示这个节点有两个图形处理器

从零开始的异生活初始

3。在库本内斯使用图形处理器的yaml样本

站在用户的角度。在库本内斯使用图形处理器容器仍然非常简单。

只需在Pod资源配置的限制字段中指定nvidia.com/gpu使用的GPU数量,我们在下面的示例中设置的数量为1;然后,通过库贝尔创建命令完成GPU的Pod部署。

从零开始的异生活初始

4。查看运行结果

部署后,您可以登录容器并执行nvidia-smi命令。观察结果,发现容器中使用了T4图形处理器卡。这表明节点中的两个图形处理器卡中的一个已经可以在容器中使用,但是节点的另一个卡对容器完全透明,不能被访问,这表明图形处理器是隔离的。

从零开始的异生活初始

1。通过扩展

kubernes管理图形处理器资源通过插件扩展机制本身管理图形处理器资源,特别是这里有两个独立的内部机制

从零开始的异生活初始

首先是扩展资源,它允许用户自定义资源名称该资源的度量是整数级别。这样做的目的是通过通用模式支持不同的异构设备,包括RDMA、现场可编程门阵列、AMD GPU等,而不仅仅是为英伟达GPU设计的。设备插件框架允许第三方设备提供商从外部管理设备的整个生命周期,而设备插件框架则在库本内斯和设备插件模块之间建立了一座桥梁。一方面,它负责向库本内斯报告设备信息,另一方面,它负责设备的调度和选择。

2 . extended resources

extended resources属于节点级api,可以完全独立于devicplugin使用。但是,要报告扩展资源,只需要一个PACTH应用编程接口来更新节点对象的状态部分,这个PACTH操作可以通过一个简单的curl命令来完成这样,该节点的GPU类型可以记录在库本内调度器中,其对应的资源量为1

从零开始的异生活初始

当然,如果使用设备插件(Device Plugin),则不需要这个PACTH操作,只需要遵循设备插件的编程模型,设备插件将在设备报告的工作中完成这个操作。

3。设备插件工作机制

介绍设备插件的工作机制。设备插件的整个工作过程可以分为两部分:一是启动时的资源报告;二是用户使用时间的调度和操作。

从零开始的异生活初始

设备插件的开发非常简单。它主要包括两种最受关注的核心事件方法:对应列表和观察的资源报告和健康检查机制当设备不正常时,不正常设备的标识可以报告给库本内斯,以便设备插件框架可以从可调度设备中删除该设备。部署容器时,设备插件将调用分配。传递参数的核心是容器将使用的设备标识。返回的参数是容器启动时所需的设备、数据量和环境变量。

4。资源报告和监控

对于每个硬件设备,它需要相应的设备插件来管理。这些设备插件通过GRPC作为客户端连接库布莱特的设备插件管理器,并向库布莱特报告它们监控的通用套接字api的版本号和设备名称,例如图形处理器。让我们来看看设备插件资源升级的整个过程一般来说,整个过程分为四个步骤,其中前三个步骤都发生在节点上,第四个步骤是kubelet和api-server之间的交互

从零开始的异生活初始

第一步是注册设备插件,库本内斯需要知道与它交互。这是因为一个节点上可能有多个设备,设备插件需要作为客户端向库布雷报告三件事:我是谁?由设备插件、GPU或RDMA管理的设备名称;?我在哪里?它是插件本身监控的unisocket的文件位置,允许kubelet调用自己。交互式协议,即应用编程接口的版本号;第二步是服务启动。设备插件将启动GRPC服务器。从那以后,设备插件一直作为库布雷访问的服务器提供服务,而监听地址和提供的应用编程接口版本已经在第一步完成。第三,在GRPC服务器启动后,库布雷将建立到设备插件列表和观察的长连接,以发现设备标识和设备的健康状态。当设备插件检测到设备不健康时,它会主动通知库布雷。此时,如果设备空闲,kubelet会将其从可分配列表中删除。然而,当这个设备已经被Pod使用时,kubelet不会做任何事情。如果此时杀死这个吊舱是一个非常危险的操作。在第四步中,库布雷将把这些设备暴露给节点节点的状态,并将设备的数量发送给库本内斯api服务器。后续调度器可以基于该信息进行调度

AllocateResponse中携带的设备路径和驱动器目录信息,一旦返回到ku blet,ku blet将根据该信息将图形处理器分配给容器,因此Docker将根据ku blet的指令创建容器,图形处理器设备将出现在该容器中。并装载它所需要的驱动程序目录,这样库本内斯将一个图形处理器分配给Pod的过程就结束了

1。这篇文章总结了

。在这篇文章中,我们学会了在Docker和Kubernetes上一起使用图形处理器。GPU的集装箱化:如何建立GPU形象;如何在码头上直接运行图形处理器容器;用库本内管理GPU资源:如何支持库本内的GPU调度:如何在库本涅斯下验证图形处理器配置;调度GPU容器的方法:设备插件的工作机制:资源的报告和监控;吊舱的调度和运行;思考:当前的缺陷;社区中常见的设备插件

2。设备插件机制

的缺陷最后,让我们考虑一个问题。当前的设备插件完美吗?

需要指出的是,设备插件的整个工作机制和过程实际上与学术界和工业界的真实场景大相径庭。这里最大的问题是GPU资源的调度实际上是在库布雷上完成的作为全局调度程序,

对此的参与非常有限。作为一个传统的库本内斯调度器,它只能处理GPU的数量一旦你的设备是异构的,不能简单地用数字来描述需求,例如,如果我的Pod想在两个带nvlink的图形处理器上运行,这个设备插件根本不能处理它。

更不用说在很多场景中,我们希望当调度器执行调度时,它会根据整个集群的设备来执行全局调度,这是当前设备插件所不能满足的。

在设备插件的设计和实现中更麻烦。像分配、列表和观察这样的应用编程接口来添加可扩展的参数也是无用的。当我们使用一些更复杂的设备使用需求时,实际上不可能通过设备插件来扩展应用编程接口

因此,当前设备插件设计覆盖的场景实际上非常单一,是一种可用但不可用的状态。这可以解释为什么像Nvidia这样的制造商已经基于Kubernetes上游代码实现了他们自己的fork解决方案,这也是最后的手段。

3。社区异构资源调度方案

从零开始的异生活初始

Nvidia贡献的第一个调度方案是最常用的调度方案。二是阿里云服务团队提出的GPU共享调度方案,旨在解决用户对共享GPU调度的需求。欢迎一起使用和改进。以下两个RDMA和现场可编程门阵列是由特定制造商提供的调度方案

大家都在看

相关专题