在AI 計(jì)算:從單機(jī)到集群(上)中我們介紹了任務(wù)計(jì)算容器化的概念,解決單機(jī)計(jì)算的便利性問題。當(dāng)我們進(jìn)一步深入使用,尤其是有多臺(tái)計(jì)算節(jié)點(diǎn)時(shí),會(huì)面臨一個(gè)新問題:多臺(tái) GPU 節(jié)點(diǎn)如何實(shí)現(xiàn) GPU 資源的合理自動(dòng)分配,達(dá)到共享使用 GPU 集群資源的目的。本篇介紹如何利用 Kubernetes 實(shí)現(xiàn) GPU 資源的集群化管理,我們結(jié)合 Kubernetes 相關(guān)源碼,詳細(xì)分析 Kubernetes 框架下 GPU 設(shè)備管理邏輯和方式,以及如何實(shí)現(xiàn)對(duì) GPU 資源的調(diào)度,幫助大家邁出從單機(jī)到集群的關(guān)鍵一步。
Kubernetes
容器技術(shù)簡化了計(jì)算框架單機(jī)運(yùn)行的問題,但是沒法解決多機(jī)資源分配問題。雖然目前很多計(jì)算框架支持分布式運(yùn)行,但缺少資源分配和調(diào)度的功能。這就是本篇我們所需要解決的問題,我們期望計(jì)算平臺(tái)(集群)能夠提供 GPU 任務(wù)調(diào)度、監(jiān)控、失敗重啟等全生命周期管理的功能。當(dāng)集群計(jì)算規(guī)模擴(kuò)大時(shí),如果沒有這些功能,我們很難手工地去每一個(gè)計(jì)算節(jié)點(diǎn)上啟動(dòng)計(jì)算任務(wù),也無法實(shí)時(shí)監(jiān)控任務(wù)運(yùn)行。除此之外,目前大多數(shù)分布式計(jì)算框架不支持生命周期管理,結(jié)束的訓(xùn)練進(jìn)程并不會(huì)自動(dòng)關(guān)閉,這也需要進(jìn)行額外的處理。同時(shí),當(dāng)多用戶共享使用計(jì)算資源時(shí),如果依靠人工協(xié)調(diào)資源分配,會(huì)帶來集群資源利用效率低下和使用繁瑣等問題??傊?,當(dāng)存在多機(jī)集群或者多用戶共享使用的情況時(shí),我們需要一種平臺(tái)幫助我們實(shí)現(xiàn)以下目標(biāo):
GPU 計(jì)算資源的自動(dòng)調(diào)度與管理
計(jì)算任務(wù)的全生命周期管理
自動(dòng)實(shí)現(xiàn)多用戶任務(wù)共享使用計(jì)算資源
而我們本篇將要介紹的 Kubernetes 能夠滿足我們上述要求。Kubernetes (簡稱:k8s) 是 Google 開源的容器集群管理系統(tǒng)(內(nèi)部代號(hào):Borg)。Kubernetes 是一套完備的分布式系統(tǒng)平臺(tái),具有完備的集群管理能力,以容器技術(shù)為基礎(chǔ),為容器化的應(yīng)用提供部署運(yùn)行、資源調(diào)度、服務(wù)發(fā)現(xiàn)和動(dòng)態(tài)伸縮等一系列完整功能,提高了大規(guī)模容器集群管理的便捷性,包括:容器自動(dòng)化部署、可擴(kuò)展資源自動(dòng)調(diào)度機(jī)制以及多粒度的資源配額管理等。這是 Kubernetes 針對(duì)傳統(tǒng)云服務(wù)和云計(jì)算所提供的一攬子功能。然而要實(shí)現(xiàn)我們所需要的目標(biāo),僅僅具備這些功能是不夠的。我們需要能夠?qū)?GPU 資源進(jìn)行管理和調(diào)度,包括更進(jìn)一步的配額管理功能等。
Kubernetes 從 1.6 版本開始,逐漸開始支持 GPU 資源的調(diào)度,而且功能實(shí)現(xiàn)也在快速更新迭代,大致分為兩個(gè)階段:
在 1.8 版本之前,GPU 的管理在功能實(shí)現(xiàn)上比較簡單粗暴,處于試驗(yàn)階段,具備初步的基本功能,但還不能大規(guī)模的應(yīng)用在生產(chǎn)環(huán)境。
在 1.8 版本之后,Kubernetes 重構(gòu)了 GPU 的管理邏輯,引入 Device Manager 和 Device Plugin 組件,以更加規(guī)范完善的框架實(shí)現(xiàn)對(duì)擴(kuò)展硬件的支持,不局限于只支持 GPU 硬件資源,還支持 FPGA,InfiniteBand 等。除此之外,還添加了設(shè)備健康檢查等新功能。
本篇以 Kubernetes 1.10 版本為例,介紹 Kubernetes 如何實(shí)現(xiàn) GPU 資源管理與調(diào)度,以及用戶如何利用 Kubernetes 提交 GPU 任務(wù)。
Kubernetes 的 GPU 資源管理與調(diào)度
Kubernetes 1.8 版本之后,由 Device Manager 管理擴(kuò)展硬件資源,包括 GPU,F(xiàn)PGA,InfiniteBand 等。不同硬件資源或者同一種硬件的不同廠商均可開發(fā)對(duì)應(yīng)設(shè)備的 Device Plugin。Device Plugin 按照約定的 API 與 Kubernetes 中的 Device Manager 進(jìn)行交互,實(shí)現(xiàn)對(duì)設(shè)備的管理、分配、回收以及運(yùn)行狀態(tài)監(jiān)控和健康檢查。
我們通過 Kubernetes 的代碼可以發(fā)現(xiàn),Device Manager 的功能邏輯集成在 Kubernetes 的核心組件 kubelet 代碼中。Device Manager 與 Device Plugin 交互方式如下圖所示。圖中左側(cè)是 Device Manager 的功能邏輯組件(綠色),右側(cè)是 Device Plugin 的功能邏輯組件(紅色),其中 Device Plugin 的紅色色塊代表功能執(zhí)行,Device Manager 的綠色色塊代表功能發(fā)起,空心矩形框?yàn)殡p方的 gRPC Server 邏輯功能。雙方的 gPRC 交互過程分為四種,具體包括:
設(shè)備注冊(cè)
設(shè)備監(jiān)控
設(shè)備分配
設(shè)備回收
我們以 Nvidia GPU 設(shè)備為例,詳細(xì)介紹 Device Manager 和 Device Plugin 如何通過這四個(gè)交互過程實(shí)現(xiàn)對(duì) GPU 的資源管理和調(diào)度。Nvidia 官方發(fā)布了k8s-device-plugin(github.com/NVIDIA/k8s-device-plugin),我們以此作為 Device Plugin 的示例,下文簡稱插件。
一、Device Plugin
準(zhǔn)備工作
k8s-device-plugin 在運(yùn)行之前,需要準(zhǔn)備好 GPU 驅(qū)動(dòng),確保 GPU 能夠正常工作。k8s-device-plugin 并不提供 GPU 驅(qū)動(dòng)安裝工作,需要管理員在每一個(gè)計(jì)算節(jié)點(diǎn)提前安裝好 GPU 驅(qū)動(dòng)。
k8s-device-plugin 以容器方式或者直接運(yùn)行在計(jì)算節(jié)點(diǎn)上,推薦以 daemon set 方式,插件啟動(dòng)的 YAML 參考官方推薦配置文件(github.com/NVIDIA/k8s-device-plugin/blob/v1.10/nvidia-device-plugin.yml)。
k8s-device-plugin 需要和 Nvidia runtime 配合使用,在集群使用之前,每一個(gè) GPU 計(jì)算節(jié)點(diǎn)上安裝 Nvidia runtime,并修改 /etc/docker/daemon.json,設(shè)置 Nvidia runtime 為默認(rèn)的 docker runtime,如下所示:
{ "default-runtime": "nvidia", "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [] } } }
Kubernetes 版本 1.8、1.9 需要添加 kubelet 參數(shù) --feature-gates=DevicePlugins=true 開啟 Device Plugin 功能,在 1.10 版本,此功能已經(jīng)默認(rèn)開啟,無需再添加 kubelet 參數(shù)。
設(shè)備注冊(cè)
Device Manager 內(nèi)部維護(hù)一個(gè)供插件注冊(cè)的 gRPC server,k8s-device-plugin 利用 gRPC 協(xié)議,并通過 /var/lib/kubelet/device-plugins/kubelet.sock 向 Device Manager 發(fā)起注冊(cè)請(qǐng)求,對(duì)應(yīng)的是圖中紅色色塊的 Register 向左邊的 Registry gRPC Server 發(fā)送注冊(cè)信息,k8s-device-plugin 注冊(cè)過程如下:
k8s-device-plugin 向 Device Manager 發(fā)起 RegisterRequest gRPC 請(qǐng)求,匯報(bào) GPU 設(shè)備的信息:
設(shè)備名稱 nvidia.com/gpu
API 版本號(hào)
k8s-device-plugin 的 gPRC server unix socket: /var/lib/kubelet/device-plugins/nvidia.sock
Device Manager 響應(yīng) RegisterRequest,利用 RegisterResponse 返回響應(yīng)結(jié)果,如果設(shè)備注冊(cè)成功后,更新節(jié)點(diǎn)擴(kuò)展設(shè)備資源狀態(tài)信息。
如果 Device Manager 響應(yīng)成功,k8s-device-plugin 啟動(dòng)插件端的 gPRC Server,供 Device Manager 與 k8s-device-plugin 通信。
k8s-device-plugin 通過 kubelet.sock 持續(xù)監(jiān)控 kubelet 的運(yùn)行狀態(tài),當(dāng) kubelet 重啟后,k8s-device-plugin 需要向 Device Manager 重新注冊(cè)。由于雙方需要通過 socket 通訊,當(dāng)k8s-device-plugin 以容器的方式運(yùn)行時(shí),需要掛載主機(jī)的 /var/lib/kubelet/device-plugins/ 目錄。
設(shè)備發(fā)現(xiàn)
當(dāng)插件注冊(cè)成功后,Device Manager 通過 ListAndWatch gRPC 請(qǐng)求獲取當(dāng)前設(shè)備的列表和健康狀態(tài),這個(gè)交互是雙向的,如果設(shè)備狀態(tài)發(fā)生改變,比如當(dāng) Device Plugin 檢測到某個(gè)設(shè)備不健康的時(shí)候,就會(huì)主動(dòng)通知 Device Manager。如果這個(gè)不健康的設(shè)備處于空閑狀態(tài),Device Manager 就會(huì)將其挪出可分配列表。如果該設(shè)備已經(jīng)被某個(gè)任務(wù)使用,kubelet 中止此任務(wù)的使用。
設(shè)備發(fā)現(xiàn)的功能依賴每個(gè)插件根據(jù)不同設(shè)備的具體情況做出不同的處理。k8s-device-plugin 的設(shè)備發(fā)現(xiàn)過程調(diào)用如下:getDevices 函數(shù)獲取 GPU UUID ,并傳遞給 Device Manager。GPU UUID 由 k8s-device-plugin 調(diào)用 Nvidia 的 NVML 庫獲取。NVIDIA Management Library (NVML)(developer.nvidia.com/nvidia-management-library-nvml)是 Nvidia 官方發(fā)布的基于 C 語言接口,用于監(jiān)控和管理 Nvidia GPU 的工具庫。其編譯版隨 GPU 驅(qū)動(dòng)一起發(fā)布。Nvidia 的 nvidia-smi 和其他常用的第三方工具均使用 NVML 作為管理 GPU 的底層接口,k8s-device-plugin 由于是基于 go 語言的實(shí)現(xiàn),所以直接使用了 nvidia-docker 1.0 中 NVML go 語言 Binding(github.com/NVIDIA/nvidia-docker/tree/1.0/src/nvml)。
funcgetDevices()[]*pluginapi.Device{n,err:=nvml.GetDeviceCount()check(err)vardevs[]*pluginapi.Devicefori:=uint(0);i
設(shè)備分配
設(shè)備分配由插件實(shí)現(xiàn) Allocate 功能,負(fù)責(zé)配置硬件環(huán)境。kubelet 創(chuàng)建任務(wù)時(shí),通過 gPRC 調(diào)用插件的 Allocate,完成設(shè)備的分配,以及確保設(shè)備在容器中能正常使用。常見的操作包括設(shè)置環(huán)境變量、掛載 volume、初始化容器所需的設(shè)備等。
k8s-device-plugin 是如何實(shí)現(xiàn) GPU 設(shè)備分配呢?借助于AI 計(jì)算:從單機(jī)到集群(上)介紹的 Nvidia runtime,極大簡化了 GPU 的分配邏輯,所以 k8s-device-plugin 的 Allocate 實(shí)現(xiàn)非常優(yōu)雅,如下面代碼所示,只需要設(shè)置容器的環(huán)境變量即可。其具體過程是:
Device Manager 傳遞待分配 GPU UUID 列表,調(diào)用 k8s-device-plugin 的 Allocate 模塊。
k8s-device-plugin 的 Allocate 模塊設(shè)置 Nvidia runtime 的環(huán)境變量 NVIDIA_VISIBLE_DEVICES。
response:=pluginapi.ContainerAllocateResponse{Envs:map[string]string{"NVIDIA_VISIBLE_DEVICES":strings.Join(req.DevicesIDs,","),},}
設(shè)備回收
在設(shè)備回收階段,插件可以做一些比如驅(qū)動(dòng)卸載等收尾工作。由于 GPU 不需要每次任務(wù)結(jié)束時(shí)卸載驅(qū)動(dòng),k8s-device-plugin 無需處理設(shè)備回收工作,任務(wù)資源的釋放由 kubelet 控制。
二、Device Manager
Device Manager 的主要功能點(diǎn)包括:
提供注冊(cè) gRPC Server, 接受 Device Plugin 的注冊(cè)請(qǐng)求,獲取并維護(hù)節(jié)點(diǎn)上的設(shè)備列表。
與 Device Plugin 保持長連接通信,為 Device Plugin 提供回調(diào)函數(shù),當(dāng)節(jié)點(diǎn)設(shè)備狀態(tài)改變時(shí),Device Plugin 通知 Device Manager 根據(jù)設(shè)備列表信息,更新節(jié)點(diǎn)設(shè)備狀態(tài)。
設(shè)備的分配與管理,維護(hù)當(dāng)前運(yùn)行任務(wù)與已使用設(shè)備的映射關(guān)系,提供待分配設(shè)備列表,并通過調(diào)用 Device Plugin 的 Allocate,協(xié)助 kubelet 完成任務(wù)設(shè)備分配相關(guān)的工作。
Device Manager 實(shí)現(xiàn)結(jié)構(gòu)體如下,包括:
通信 socket 文件
負(fù)責(zé)注冊(cè)的 gRPC Server
activePods 獲取當(dāng)前運(yùn)行任務(wù)
sourceReady 用于從 checkpoint 移除不活動(dòng)任務(wù)
callback 提供回調(diào)給 Device Plugin,用于設(shè)備監(jiān)控狀態(tài)
healthyDevices 健康設(shè)備列表,unhealthyDevices 問題設(shè)備列表,allocatedDevices 已使用設(shè)備列表
podDevices 記錄運(yùn)行任務(wù)和已使用的設(shè)備映射關(guān)系
//ManagerImplisthestructureinchargeofmanagingDevicePlugins.typeManagerImplstruct{socketnamestring socketdirstring endpointsmap[string]endpoint//KeyisResourceName mutexsync.Mutexserver*grpc.Server//activePodsisamethodforlistingactivepodsonthenode//sotheamountofpluginResourcesrequestedbyexistingpods//couldbecountedwhenupdatingallocateddevices activePodsActivePodsFunc//sourcesReadyprovidesthereadinessofkubeletconfigurationsourcessuchasapiserverupdatereadiness.//Weuseittodeterminewhenwecanpurgeinactivepodsfromcheckpointedstate. sourcesReadyconfig.SourcesReady//callbackisusedforupdatingdevices'statesinonetimecall.//e.g.anewdeviceisadvertised,twoolddevicesaredeletedandarunningdevicefails. callbackmonitorCallback //healthyDevicescontainsalloftheregisteredhealthyresourceNamesandtheirexporteddeviceIDs. healthyDevicesmap[string]sets.String //unhealthyDevicescontainsalloftheunhealthydevicesandtheirexporteddeviceIDs. unhealthyDevicesmap[string]sets.String //allocatedDevicescontainsallocateddeviceIds,keyedbyresourceName. allocatedDevicesmap[string]sets.String //podDevicescontainspodtoallocateddevicemapping. podDevicespodDevicesstoreutilstore.StorepluginOptsmap[string]*pluginapi.DevicePluginOptions }
由于篇幅限制,這里對(duì) Device Manager 的實(shí)現(xiàn)細(xì)節(jié)不多做介紹,展開說一下 Device Manager 如何維護(hù)當(dāng)前運(yùn)行任務(wù)與已使用設(shè)備的映射關(guān)系。每個(gè)計(jì)算節(jié)點(diǎn)上的 Device Manager 創(chuàng)建保存當(dāng)前運(yùn)行任務(wù)與已使用設(shè)備映射關(guān)系的 checkpoint 文件 /var/lib/kubelet/device-plugins/kubelet_internal_checkpoint ,其內(nèi)容如下,分為兩部分:
PodDeviceEntries 保存節(jié)點(diǎn)正在運(yùn)行任務(wù)的 PodID,ContainerName,ResourceName, 正在使用的 DeviceIDs 列表,以及 Device Plugin 返回的消息 AllocResp。其中,DeviceIDs 中多個(gè) GPU UUID 代表多卡任務(wù)。
RegisteredDevices 保存節(jié)點(diǎn)處于健康狀態(tài)的設(shè)備列表,以 ResourceName 為 key,其值為 DeviceIDs 列表。
將設(shè)備使用映射關(guān)系通過 checkpoint 文件的方式保存到硬盤上,其目的是為了解決由于 kubelet 重啟帶來的設(shè)備映射關(guān)系信息丟失的問題。當(dāng) kubelet 重啟時(shí),自動(dòng)讀取硬盤上的 checkpoint 文件以獲得重啟前的設(shè)備使用映射關(guān)系,保證設(shè)備映射關(guān)系與實(shí)際任務(wù)使用的一致性,避免將已經(jīng)分配的設(shè)備當(dāng)做未使用設(shè)備重新分配使用的問題。
{"PodDeviceEntries":[ {"PodUID":"51a38fdb-3ef0-11e8-b8fe-0cc47ae55a2c","ContainerName":"task1","ResourceName":"nvidia.com/gpu","DeviceIDs":[ "GPU-77ccee89-7bbc-8838-a56e-f0ca79518232" ],"AllocResp":"CkIKFk5WSURJQV9WSVNJQkxFX0RFVklDRVMSKEdQVS03N2NjZWU4OS03YmJjLTg4MzgtYTU2ZS1mMGNhNzk1MTgyMzI="}, {"PodUID":"e7f290e2-3be0-11e8-b8fe-0cc47ae55a2c","ContainerName":"task2","ResourceName":"nvidia.com/gpu","DeviceIDs":["GPU-93d815e1-0bda-ea1f-08d9-0864e895553d","GPU-ffd50dfd-2578-342e-9a53-19b0f3d40852","GPU-68aed792-9550-6ef7-bd91-f8422efd7b5a","GPU-a6ec8254-2bd0-3237-142a-496fa2059d73" ],"AllocResp":"Cr4BChZOVklESUFfVklTSUJMRV9ERVZJQ0VTEqMBR1BVLTkzZDgxNWUxLTBiZGEtZWExZi0wOGQ5LTA4NjRlODk1NTUzZCxHUFUtZmZkNTBkZmQtMjU3OC0zNDJlLTlhNTMtMTliMGYzZDQwODUyLEdQVS02OGFlZDc5Mi05NTUwLTZlZjctYmQ5MS1mODQyMmVmZDdiNWEsR1BVLWE2ZWM4MjU0LTJiZDAtMzIzNy0xNDJhLTQ5NmZhMjA1OWQ3Mw==" }],"RegisteredDevices":{"nvidia.com/gpu":["GPU-68aed792-9550-6ef7-bd91-f8422efd7b5a","GPU-02a18b6f-3098-7c10-33f9-ededd1b150b8","GPU-e4ce184a-d4a9-8b90-9ba1-9f40ec4cc2d7","GPU-68258d71-d70e-f8bd-9c9a-b7b5240c8b58","GPU-a6ec8254-2bd0-3237-142a-496fa2059d73","GPU-6d8322d9-b8b5-89ce-2804-5cbaacc7b6ef","GPU-93d815e1-0bda-ea1f-08d9-0864e895553d","GPU-ffd50dfd-2578-342e-9a53-19b0f3d40852","GPU-77ccee89-7bbc-8838-a56e-f0ca79518232","GPU-69bf1feb-66bc-67b9-c38e-c5a38ac93e20" ]} }
用戶使用
我們從用戶角度看一下,從任務(wù)提交開始的整個(gè)交互工作流程:
用戶提交任務(wù)申請(qǐng),通過在 YAML 文件里指定nvidia.com/gpu申請(qǐng) X 個(gè) GPU 卡
Scheduler 過濾滿足條件的候選節(jié)點(diǎn)
任務(wù) Pod 被分發(fā)到節(jié)點(diǎn),該節(jié)點(diǎn) Device Manager 決定待分配設(shè)備的 GPU UUID 列表
Device Manager 調(diào)用 gPRC Allocate,通知 Device Plugin 將 GPU UUID 列表中的設(shè)備映射到任務(wù) Pod 中使用(比如上面介紹的:k8s-device-plugin 設(shè)置 Nvidia runtime 的環(huán)境變量 NVIDIA_VISIBLE_DEVICES)
任務(wù)完成創(chuàng)建
我們也給出 YAML 文件示例,如下面的 YAML 文件所示,用戶提交 GPU 任務(wù)時(shí),只需要通過nvidia.com/gpu指定 GPU 使用數(shù)量,Kubernetes 的 scheduler 查找合適的節(jié)點(diǎn)資源,并自動(dòng)調(diào)度到滿足要求的節(jié)點(diǎn)上,由節(jié)點(diǎn)上的 kubelet 完成任務(wù)的啟動(dòng)和運(yùn)行。如果沒有資源空余,則任務(wù)會(huì)處于 Pending 狀態(tài),等待任務(wù)需求的資源滿足,則自動(dòng)轉(zhuǎn)入運(yùn)行狀態(tài)。
apiVersion:v1 kind:Pod metadata:name:tensorflow spec:containers:-name:tensorflowargs:["sleep1d"]command:["/bin/sh","-c"]image:tensorflow/tensorflow:latest-gpuresources:limits:nvidia.com/gpu:"1"
Kubernetes 支持對(duì)不同的 GPU 資源需求做篩選,比如,可以根據(jù) GPU 型號(hào)做任務(wù)選擇調(diào)度。如下所示,指定使用 Tesla P100 卡,則 Kubernetes 會(huì)自動(dòng)調(diào)度任務(wù)到 P100 卡的節(jié)點(diǎn)上。
apiVersion:v1 kind:Pod metadata:name:tensorflow spec:containers:-name:tensorflowargs:["sleep1d"]command:["/bin/sh","-c"]image:tensorflow/tensorflow:latest-gpuresources:limits:nvidia.com/gpu:"1"nodeSelector:accelerator:nvidia-tesla-p100
這里需要進(jìn)一步說明下使用 k8s-device-plugin 的一個(gè)小 bug,由于 GPU 計(jì)算節(jié)點(diǎn)上的 docker runtime 默認(rèn)設(shè)置為 Nvidia runtime,而 Nvidia runtime 的 NVIDIA_VISIBLE_DEVICES 環(huán)境變量默認(rèn)值為 all。所以,當(dāng)用戶提交非 GPU 任務(wù)時(shí),如下所示,在 YAML 文件中沒有指定nvidia.com/gpu,則此時(shí),在任務(wù)容器中能使用該節(jié)點(diǎn)上的所有 GPU 資源。這顯然不是我們期望的,繞過了原有的資源分配邏輯。一種解決方式是在 YAML 文件中顯式設(shè)置容器的環(huán)境變量 NVIDIA_VISIBLE_DEVICES,如下所示:
apiVersion:v1 kind:Pod metadata:name:tensorflowspec:containers:-name:tensorflowargs:["sleep1d"]command:["/bin/sh","-c"]image:tensorflow/tensorflow:latest-gpuenv:-name:NVIDIA_VISIBLE_DEVICES回顧與展望
本文開始提到 Kubernetes 1.8 之前版本的 GPU 管理比較簡單,這里對(duì) 1.8 之前版本的實(shí)現(xiàn)邏輯簡單介紹一下,并與本文介紹的 1.8 版本及之后的實(shí)現(xiàn)做對(duì)比,方便讀者了解 Kubernetes GPU 資源管理和調(diào)度的演進(jìn)歷史,并能對(duì)當(dāng)前實(shí)現(xiàn)方式的特點(diǎn)有直觀的認(rèn)識(shí)。
設(shè)備發(fā)現(xiàn):1.8 之前版本是通過直接匹配計(jì)算節(jié)點(diǎn)上的設(shè)備文件 /dev/nvidia* 、/dev/nvidia-uvm 和 /dev/nvidiactl。這是一種折中做法,并不是真實(shí)的查詢?cè)O(shè)備信息,存在不可靠的問題。資源的名稱alpha.kubernetes.io/nvidia-gpu,和當(dāng)前的nvidia.com/gpu也有區(qū)別。
設(shè)備分配:1.8 之前版本用戶需要在 YAML 文件中顯式掛載驅(qū)動(dòng)相關(guān)動(dòng)態(tài)庫,1.8 之后版本用戶不需要掛載。除此之外,在 Allocate 這部分,1.8 之前版本是通過 docker 的 API 實(shí)現(xiàn),這其實(shí)不滿足軟件通用性的要求,也是一個(gè)臨時(shí)的折中做法。1.8 之后版本是通過 Device Manager + Device Plugin 實(shí)現(xiàn)。
代碼耦合:1.8 之前版本 GPU 資源管理的代碼耦合在 Kubernetes 代碼中,不利于社區(qū)貢獻(xiàn),而且增加了 Kubernetes 穩(wěn)定運(yùn)行的風(fēng)險(xiǎn)。
基于 Device Manager + Device Plugin 方式管理擴(kuò)展硬件設(shè)備,不局限于 GPU,還可以管理 InfiniBand,高性能網(wǎng)卡,F(xiàn)PGA 等。
1.8 之后的版本新增了設(shè)備健康檢查,此功能依賴于具體設(shè)備的 Device Plugin 實(shí)現(xiàn),1.8 之前版本無健康監(jiān)控功能。
目前,Kubernetes 社區(qū)對(duì) GPU 的功能實(shí)現(xiàn)也在快速迭代,大致集中在兩個(gè)方向:
當(dāng)前 GPU 調(diào)度的數(shù)量均以整數(shù)為單位,考慮到利用 Kubernetes 做 GPU Inference,在后續(xù)功能改進(jìn)上,將來有可能實(shí)現(xiàn)類似 0.5 這種非整數(shù)的調(diào)度單位,多容器之間共享 GPU 計(jì)算資源。
除了繼續(xù)完善 GPU 管理調(diào)度的功能外,Kubernetes 與常用 AI 計(jì)算框架的結(jié)合也是社區(qū)工作的重點(diǎn),兩者的緊密配合將會(huì)帶來更加便捷和高效的 AI 計(jì)算。
總結(jié)
在利用容器技術(shù)簡化 AI 計(jì)算框架單機(jī)運(yùn)行的基礎(chǔ)上,本文詳細(xì)介紹了利用 Kubernetes 實(shí)現(xiàn)集群的 GPU 資源調(diào)度和管理,重點(diǎn)介紹了當(dāng)前的 Device Plugin + Device Manager 實(shí)現(xiàn)邏輯。并以 Nvidia 官方的 k8s-device-plugin 為例,分析了 k8s-device-plugin 與 Device Manager 的功能交互過程。在介紹 Device Manager 功能點(diǎn)之后,我們從用戶的角度梳理了在 Kubernetes 上 GPU 任務(wù)提交的工作流程,并針對(duì)不同的應(yīng)用場景,給出了三個(gè)示例。最后,我們回顧了 Kubernetes GPU 功能的演進(jìn)歷史,對(duì)比了 1.8 前后兩個(gè)版本實(shí)現(xiàn)的優(yōu)缺點(diǎn),并展望了未來的發(fā)展方向。
-
云計(jì)算
+關(guān)注
關(guān)注
39文章
7973瀏覽量
139664 -
人工智能
+關(guān)注
關(guān)注
1805文章
48913瀏覽量
248039 -
代碼
+關(guān)注
關(guān)注
30文章
4894瀏覽量
70462
發(fā)布評(píng)論請(qǐng)先 登錄
ADI版的Multisim11拷到單機(jī)上使用安裝后無法激活
Linux下單機(jī)版的安裝流程概述
Firefly集群服務(wù)器解決方案
K8s 從懵圈到熟練 – 集群網(wǎng)絡(luò)詳解
從 Android 到 AI 之路:Java與Python 攜手同行
色環(huán)電阻計(jì)算單機(jī)版
深入了解AI計(jì)算從單機(jī)到集群的概括

從弱AI進(jìn)階到強(qiáng)AI,意味著經(jīng)典計(jì)算機(jī)過渡到量子計(jì)算機(jī)
Meta發(fā)布采用NVIDIA系統(tǒng)的AI研究超級(jí)集群
云計(jì)算和集群計(jì)算有何區(qū)別?
高性能計(jì)算集群的能耗優(yōu)化

科技云報(bào)到:從大模型到云端,“AI+云計(jì)算”還能講出什么新故事
從云端到單機(jī)的數(shù)據(jù)匿名化全攻略

高性能計(jì)算集群在AI領(lǐng)域的應(yīng)用前景

評(píng)論