Docker和Kubernetes:设备插件和GPU管理
中国籍高级技术专家Che Yang将解释普通设备插件以及如何使用Docker和Kubernetes来使用GPU。
作者:阿里巴巴的高级技术专家,Che Yang(Biran)先生
2016年,AlphaGo和TensorFlow将人工智能技术革命从学术界引入了工业界。人工智能受益于云计算和计算能力的支持。
要求的事情
经过多年的开发,人工智能(AI)已经应用于许多场景,如智能客户服务、机器翻译、图像搜索等。机器学习和人工智能有着悠久的历史,并且随着云计算的普及和计算能力的大幅增加,使得人工智能的应用成为可能。

自2016年以来,Kubernetes社区收到了来自各种渠道的需求,希望能够在Kubernetes集群上运行诸如TensorFlow等机器学习框架。为了满足这些需求,必须解决作业和其他离线任务的管理、需要的异构设备以及对NVIDIA图形处理单元(GPU)的支持等挑战。
通过使用Kubernetes来管理GPU,可以实现成本减少和效率提高。相比于CPU,GPU的成本较高。在离线场景下,每小时的CPU成本在1元以下,而GPU的成本则在每小时10至30元之间,因此需要提高GPU的利用率。
通过使用Kubernetes来管理GPU等异构资源,可以实现以下内容。
-
- デプロイメントの高速化:コンテナを利用することで、機械学習のための複雑な環境を何度も導入する手間を省くことができます。
-
- クラスタリソースの利用率の向上:集中的なスケジューリングと割り当てにより、これを実現することができます。
- リソースへの排他的なアクセスを確保:異種のデバイスをコンテナで隔離し、干渉を防ぐことができます。
通过最小化环境准备所需的时间,可以加速部署并通过容器镜像技术使部署流程更加可靠和可重复利用。许多机器学习框架都提供容器镜像,通过利用容器镜像可以提高GPU的利用效率。
此外,通过分时分割多路复用,可以提高GPU的利用率。为了集中调度大量的GPU以实现用户根据需要申请资源并在使用后立即释放资源的能力,需要使用Kubernetes。这样一来,可以灵活地利用GPU资源池。
为了防止在同一设备上运行的不同应用程序之间的干涉,我们需要Docker提供的设备隔离功能。这样可以确保高效性、成本效益和系统的稳定性。
GPU容器化
在中文环境中,Kubernetes是适用于GPU应用程序运行的容器调度平台,它以容器为调度单位。在学习如何使用Kubernetes之前,让我们先学习如何在容器环境中运行GPU应用程序。
在容器环境中运行GPU应用程序。
在容器环境中运行GPU应用程序并不复杂。这可以通过两个步骤来完成。
-
- GPUをサポートするコンテナイメージを構築する
- このイメージをDockerで実行し、GPUデバイスと依存ライブラリをコンテナにマッピングする
2. 准备 GPU 容器镜像
GPU容器映像可通过以下任一方法进行准备。
-
- 深層学習用の公式コンテナイメージを使用する
-
- Docker HubまたはAlibaba Cloud Container Registryから公式のGPUイメージを選択します。TensorFlow、Caffe、PyTorchなどの一般的な機械学習フレームワークに対応した標準的なイメージが用意されています。公式GPUイメージは、使いやすく、安全で、信頼性の高いものです。
-
- NVIDIA CUDAをベースにしたGPUコンテナイメージを構築します。
- 公式イメージがニーズを満たさない場合、たとえば、TensorFlowフレームワークにカスタム変更を加えた場合などは、カスタムTensorFlowイメージをコンパイルする必要があります。NVIDIAの公式イメージをベースに、カスタムイメージを作成することをお勧めします。
以下的代码是用TensorFlow编写的。它用于基于CUDA镜像创建自定义GPU镜像。

3. GPU 容器映像的机制
在构建 GPU 容器镜像之前,需要学习如何在主机上安装 GPU 应用程序。
如下图左侧所示,首先在底层安装NVIDIA硬件驱动程序。在上层安装CUDA工具库。而诸如PyTorch和TensorFlow等机器学习框架则安装在最顶层的层次上。
CUDA工具库与应用程序紧密合作。当应用程序版本变更时,相关的CUDA版本也可能会更新。NVIDIA驱动程序较为稳定。

在上述的图中,右侧部分展示了NVIDIA GPU容器解决方案。这个解决方案中,NVIDIA驱动程序被安装在主机上,并且在CUDA工具库之上的软件通过容器镜像实现。NVIDIA驱动程序的连接通过Mount Bind映射到容器中。
安装新的NVIDIA驱动程序后,您可以在同一节点上运行不同版本的CUDA图像。
在容器中运行GPU应用程序。
从这里开始,我们来看一下GPU容器的机制。下图展示了使用Docker来运行GPU容器的示例。

在运行时,需要将主机设备和NVIDIA驱动程序库映射到GPU容器中。这与普通容器不同。
前文中提到的图表右侧展示了GPU容器在启动后的GPU配置。上方是设备映射的结果,下方则显示了在绑定模式下,将驱动库映射到容器后所产生的变化。
NVIDIA Docker通常用于运行GPU容器,自动化设备映射和驱动库映射的过程。设备挂载很容易,但GPU应用程序依赖的驱动库却较为复杂。
在不同的具体场景中,如深度学习和图像处理等,会使用不同的驱动库。要使用驱动库,需要对NVIDIA,尤其是NVIDIA容器有所了解。
使用Kubernetes进行GPU管理。
1. 部署 GPU Kubernetes
在Kubernetes节点上按以下方式配置GPU功能。这里以CentOS节点为例。

如前所述,我们必须做以下事情。
-
- 1、 NVIDIAドライバをインストール
-
- NVIDIAドライバをインストールするには、カーネルのコンパイルが必要です。NVIDIAドライバをインストールする前に、GNU Compiler Collection(GCC)とカーネルのソースコードをインストールする必要があります。
-
- 2、 yumソースを使ってNVIDIA Docker 2をインストール
-
- NVIDIA Docker 2がインストールされたら、Dockerをリロードします。Dockerのdaemon.jsonにあるデフォルトの起動エンジンをNVIDIAに置き換えます。docker info」コマンドを実行して、ランタイム中にNVIDIA runCが使用されているかどうかを確認します。
-
- 3、NVIDIA Device Pluginをインストール
- NVIDIAのgit repoからデバイスプラグインのデプロイ宣言ファイルをダウンロードし、「kubectl create」コマンドを実行してプラグインをデプロイします。
我们在这里使用deamonset来部署设备插件。如果在Kubernetes节点上无法调度GPU应用程序,则需要检查设备插件等模块。例如,可以查看设备插件的日志,确认Docker的默认runC是否设置为NVIDIA runC,是否已安装NVIDIA驱动程序等。
确认GPU Kubernetes部署的结果
当部署部署GPU节点后,我们会通过节点状态信息来确认以下的GPU信息。
-
- GPU名(この例ではnvidia.com/gpu)
- GPUの数:次の図では2で、ノードに2つのGPUがあることを示しています。

使用Kubernetes GPU yaml示例。
在Kubernetes中使用GPU容器很简单。
在Pod资源配置的limit字段中,根据所需的GPU数量设置nvidia.com/gpu。在下面的图中,它被设置为1,然后使用”kubectl create”命令部署目标Pod。

3. 查看结果
完成部署后,登录到容器中并执行“nvidia-smi”命令来确认结果。您可以看到T4 GPU正在容器中被使用。其中一个GPU正在被容器使用,而另一个GPU对于容器来说是透明的,无法通过GPU隔离功能进行访问。

在Kubernetes中使用GPU资源。
1. 通过扩展进行GPU资源管理
在Kubernetes中,GPU资源是通过插件扩展进行管理的,但这是通过两个独立的内部机制来实现的。

-
- Kubernetesでは、カスタムリソースを作成できるように拡張リソースを提供しています。拡張リソースは整数レベルで計測されるため、RDMA(Remote Direct Memory Access)、FPGA(Field Programmable Gate Array)、AMD GPUなどの一般的なモードを使用することで、異なる異機種のデバイスをサポートすることができます。この機能は、NVIDIA GPUに限定されるものではありません。
- Kubernetesは、サードパーティのデバイスプロバイダがデバイスをスケジュールし、ライフサイクル全体を管理できるよう、デバイスプラグインフレームワークを提供しています。デバイスプラグインフレームワークは、Kubernetesとデバイスプラグインモジュールを接続します。また、デバイス情報をKubernetesに報告し、スケジューリングのためにデバイスを選択します。
2. 扩展资源的报告 de
扩展资源是一种节点级别的API,与设备插件独立使用。要报告扩展资源,可以使用PATCH API来更新节点对象的状态字段。PATCH操作可以使用简单的curl命令执行。这样,Kubernetes调度器就可以记录使用一个GPU的节点的GPU类型。

如果使用设备插件,就不需要进行PATCH操作。只需要实现设备插件的编程模型,让设备插件在报告扩展资源时执行PATCH操作就可以了。
3. 设备插件的机制
设备插件的工作流程可以分为两个部分。
-
- 起動時のリソース報告
- 使用中のスケジューリングと実行

开发设备插件很简单。它涉及两个事件方法。
-
- ListAndWatchは、リソースの報告に使用され、ヘルスチェックのメカニズムを提供します。不健全なデバイスは、Kubernetesのunhealthy device IDリストに報告され、デバイスプラグインフレームワークがこのデバイスをスケジューリング可能なデバイスリストから削除するようにします。
- Allocateメソッドは、コンテナのデプロイ時にデバイスプラグインから呼び出されます。入力パラメータには、コンテナが使用するデバイスのIDが含まれます。返されるパラメータには、コンテナの起動に必要なデバイス、データボリューム、環境変数が含まれます。
报告和监控资源
每个硬件设备都由相关的设备插件进行管理。设备插件作为客户端通过gRPC连接到kubelet的设备插件管理器,并向kubelet报告监听的UNIX套接字API版本和设备名称。
以下图表展示了设备插件报告资源的过程。该过程分为四个步骤。前三个步骤在节点上进行,第四个步骤在kubelet和API服务器之间进行。

- ステップ1:Kubernetesと対話するために、デバイスプラグインを登録します。1つのノードに複数のデバイスが存在する可能性があります。デバイスプラグインは、クライアントとして、以下の情報をkubletに報告します。
(1) 设备插件所管理的设备的名称,如GPU和RDMA。
(2) 设备插件监听的UNIX套接字文件路径,以供Cubelet调用设备插件。
(3) 互动协议的版本即API的版本。
-
- ステップ2: デバイス・プラグインは、gRPCサーバーを起動します。そして、デバイス・プラグインは、gRPC サーバを代行して、kubelet にサービスを提供します。リスニング・アドレスと API バージョンは、ステップ 1 で提供されます。
-
- ステップ3: gRPCサーバの起動後、kubeletはデバイス・プラグインのListAndWatchへの持続的な接続を確立し、デバイスIDの検出とデバイスの健全性の確認を行います。デバイス・プラグインは、デバイスが不健全である場合、kubeletに通知します。不健全なデバイスがアイドル状態の場合、kubelet はそのデバイスをスケジューリング可能なデバイスリストから削除します。不健全なデバイスがPodで使用されている場合、Podを殺すのは高リスクのアクションであるため、kubeletは何もしません。
- ステップ4: キューブレットは、これらのデバイスをノードのステータスに公開し、デバイスの数量をKubernetes APIサーバーに送信します。スケジューラは、この情報に基づいてスケジューリングを実施します。
Cubelet仅向Kubernetes API服务器报告GPU的数量。Cubelet设备插件管理器保存GPU ID列表并将GPU ID分配给设备。Kubernetes的全局调度程序只关注GPU的数量,不查看GPU ID列表。
因此,如果使用设备插件,Kubernetes全局调度器将仅基于GPU数量进行调度。同一节点上的两个GPU将使用NVLINK通信比PCIe通信更有效地交换数据。在这种情况下,设备插件不支持基于GPU亲和性的调度。
5. Pod的排程和执行

如果Pod想要使用GPU,可以通过在Resource.limit中声明所需的GPU资源和数量,例如nvidia.com/gpu: 1。Kubernetes会找到满足所需GPU数量的节点,并将节点上可用的GPU数量减1,然后将Pod与该节点绑定在一起。
一旦匹配成功,符合的kubelet将创建容器。当kubelet发现Pod的容器请求中指定的资源是GPU时,它会启用内部设备插件管理器,并从GPU ID列表中选择可用的GPU,然后将该GPU分配给容器。
魔方板会向设备插件发送“Allocate”请求。该请求包含包括应分配给容器的GPU在内的设备ID列表。
接收到 Allocate 请求的设备插件会找到与设备 ID 相关联的设备路径、驱动程序目录和环境变量,并通过 Allocate 响应将信息返回给 kubelet。
kubelet会根据接收到的设备路径和驱动程序目录,为容器分配GPU。然后,Docker会根据kubelet的指示创建容器。创建的容器中将配备有GPU。最后,必要的驱动程序目录将被挂载。这样,Kubernetes上将完成将GPU分配给Pod的过程。
思维方式和实践
总结
这次我们学习了如何在Docker和Kubernetes中使用GPU。
-
- GPUコンテナ化:DockerでGPUイメージを構築し、GPUコンテナを直接実行する方法
Kubernetesを使ったGPUリソースの管理:KubernetesでGPUのスケジューリングをサポートし、GPUコンテナの設定を検証する方法
デバイスプラグイン:リソースの報告と監視の方法、Podのスケジュールと実行の方法
考え方:現在の欠陥とコミュニティでの一般的なデバイスプラグインについて
2. 设备插件的缺点
在这最后的部分,我们将进行设备插件的评估。
设备插件的设计没有充分考虑学术界和工业界的实际情况。GPU资源的调度仅由kubelet执行。
在GPU资源调度中,全局调度器是必不可少的。然而,Kubernetes调度器仅基于GPU数量来实现调度。在设备插件中,无法根据除GPU数量以外的要素来调度异构设备,例如搭载有两个NVLK兼容GPU的Pod。
设备插件不支持基于集群内设备状态的全局调度。
设备插件不支持由Allocate API和ListAndWatch API添加的可扩展参数。此外,设备插件无法通过API扩展来调度复杂设备的资源。
因此,设备插件只能适用于有限的场景。NVIDIA和其他供应商实现了基于Kubernetes上游代码的分支解决方案,这是为了这个原因。
3. 社区中异类资源调度解决方案

-
- 最も一般的に使用されているソリューションは、NVIDIAが開発したものです。
-
- Alibaba Cloudサービスチームは、共有GPUリソースをスケジューリングするためのGPU共有スケジューリングソリューションを開発しました。このソリューションをご利用いただき、改善にご協力いただけると幸いです。
-
- 他のベンダーは、RDMAとFPGAのスケジューリングソリューションを提供しています。
- Alibaba Cloud Kubernetes製品についての詳細は、https://www.alibabacloud.com/product/kubernetes
這篇部落格是從英文版翻譯而來的,您可以從這裡查看原始內容。我們部分使用了機器翻譯,如果有任何翻譯錯誤,請不吝指正。
阿里巴巴云拥有两个数据中心在日本,在全球拥有超过60个可用区,是亚太地区最大的云基础设施提供商(2019年Gartner报告)。请点击这里查看更多关于阿里巴巴云的详细信息。阿里巴巴云日本官方页面。