問題背景
全球主要的容器集群服務(wù)廠商的Kubernetes服務(wù)都提供了Nvidia GPU容器調(diào)度能力,但是通常都是將一個(gè)GPU卡分配給一個(gè)容器蛾方。這可以實(shí)現(xiàn)比較好的隔離性,確保使用GPU的應(yīng)用不會(huì)被其他應(yīng)用影響;對(duì)于深度學(xué)習(xí)模型訓(xùn)練的場(chǎng)景非常適合桩砰,但是如果對(duì)于模型開發(fā)和模型預(yù)測(cè)的場(chǎng)景就會(huì)比較浪費(fèi)拓春。 大家的訴求是能夠讓更多的預(yù)測(cè)服務(wù)共享同一個(gè)GPU卡上,進(jìn)而提高集群中Nvidia GPU的利用率亚隅。而這就需要提供GPU資源的劃分硼莽,而這里GPU資源劃分的維度指的就是GPU顯存和Cuda Kernel線程的劃分。通常在集群級(jí)別談支持共享GPU煮纵,通常是兩件事情:
1.調(diào)度
2.隔離懂鸵,我們這里主要討論的是調(diào)度,隔離的方案未來會(huì)基于Nvidia的MPS來實(shí)現(xiàn)行疏。
而對(duì)于細(xì)粒度的GPU卡調(diào)度匆光,目前Kubernetes社區(qū)并沒有很好的方案,這是由于Kubernetes對(duì)于GPU這類擴(kuò)展資源的定義僅僅支持整數(shù)粒度的加加減減酿联,無法支持復(fù)雜資源的分配终息。比如用戶希望使用Pod A占用半張GPU卡,這在目前Kubernetes的架構(gòu)設(shè)計(jì)中無法實(shí)現(xiàn)資源分配的記錄和調(diào)用贞让。這里挑戰(zhàn)是多卡GPU共享是實(shí)際矢量資源問題周崭,而Extened Resource是標(biāo)量資源的描述。
針對(duì)此問題震桶,我們?cè)O(shè)計(jì)了一個(gè)outoftree的共享GPU調(diào)度方案休傍,該方案依賴于Kubernetes的現(xiàn)有工作機(jī)制:
Extended Resource定義
Scheduler Extender機(jī)制
Device Plugin機(jī)制
用戶場(chǎng)景
作為集群管理員,我想提高集群的GPU使用率;在開發(fā)過程中蹲姐,多個(gè)用戶共享模型開發(fā)環(huán)境
作為應(yīng)用開發(fā)人員,我希望能夠同時(shí)在Volta GPU上運(yùn)行多個(gè)推理任務(wù)
目標(biāo)
能夠讓使用者通過API描述對(duì)于一個(gè)可共享資源的申請(qǐng)人柿, 并能實(shí)現(xiàn)該種資源的調(diào)度
非目標(biāo)
不支持該共享資源的隔離
不支持超賣
設(shè)計(jì)原則
明確問題簡(jiǎn)化設(shè)計(jì)柴墩,第一步只負(fù)責(zé)調(diào)度和部署,后續(xù)再實(shí)現(xiàn)運(yùn)行時(shí)顯存管控凫岖。
有很多的客戶明確的訴求是首先可以支持多AI應(yīng)用可以調(diào)度到同一個(gè)GPU上江咳,他們可以接受從應(yīng)用級(jí)別控制顯存的大小,利用類似gpu_options.per_process_gpu_memory_fraction控制應(yīng)用的顯存使用量哥放。那我們要解決的問題就先簡(jiǎn)化到以顯存為調(diào)度標(biāo)尺歼指,并且把顯存使用的大小以參數(shù)的方式傳遞給容器內(nèi)部甥雕。
不做侵入式修改
本設(shè)計(jì)中不會(huì)修改Kubernetes核心的Extended Resource的設(shè)計(jì), Scheduler的實(shí)現(xiàn)社露,Device Plugin的機(jī)制以及Kubelet的相關(guān)設(shè)計(jì)。重用Extended Resource描述共享資源的申請(qǐng)API。這樣的好處在于提供一個(gè)可以移植的方案附鸽,用戶可以在原生Kubernetes上使用這個(gè)方案。
按顯存和按卡調(diào)度的方式可以在集群內(nèi)并存坷备,但是同一個(gè)節(jié)點(diǎn)內(nèi)是互斥的省撑,不支持二者并存丁侄;要么是按卡數(shù)目,要么是按顯存分配石景。
詳細(xì)設(shè)計(jì)
前提:
依舊延用Kubernetes Extended Resource定義,但是衡量維度最小單位從1個(gè)GPU卡變?yōu)镚PU顯存的MiB潮孽。如果所節(jié)點(diǎn)使用的GPU為單卡16GiB顯存,它對(duì)應(yīng)的資源就是16276MiB
由于用戶對(duì)于共享GPU的訴求在于模型開發(fā)和模型預(yù)測(cè)場(chǎng)景筷黔,在此場(chǎng)景下往史,用戶申請(qǐng)的GPU資源上限不會(huì)超過一張卡,也就是申請(qǐng)的資源上限為單卡
而我們的工作首先是定義了兩個(gè)新的Extended Resource: 第一個(gè)是gpu-mem佛舱, 對(duì)應(yīng)的是GPU顯存;第二個(gè)是gpu-count椎例,對(duì)應(yīng)的是GPU卡數(shù)。 通過兩個(gè)標(biāo)量資源描述矢量資源, 并且結(jié)合這一資源请祖,提供支持共享GPU的工作機(jī)制订歪。下面是基本的架構(gòu)圖:
核心功能模塊:
GPU Share Scheduler Extender: 利用Kubernetes的調(diào)度器擴(kuò)展機(jī)制,負(fù)責(zé)在全局調(diào)度器Filter和Bind的時(shí)候判斷節(jié)點(diǎn)上單個(gè)GPU卡是否能夠提供足夠的GPU Mem肆捕,并且在Bind的時(shí)刻將GPU的分配結(jié)果通過annotation記錄到Pod Spec以供后續(xù)Filter檢查分配結(jié)果刷晋。
GPU Share Device Plugin: 利用Device Plugin機(jī)制,在節(jié)點(diǎn)上被Kubelet調(diào)用負(fù)責(zé)GPU卡的分配慎陵,依賴scheduler Extender分配結(jié)果執(zhí)行眼虱。
具體流程:
1. 資源上報(bào)
GPU Share Device Plugin利用nvml庫查詢到GPU卡的數(shù)量和每張GPU卡的顯存, 通過ListAndWatch()將節(jié)點(diǎn)的GPU總顯存(數(shù)量 *顯存)作為另外Extended Resource匯報(bào)給Kubelet席纽; Kubelet進(jìn)一步匯報(bào)給Kubernetes API Server捏悬。 舉例說明,如果節(jié)點(diǎn)含有兩塊GPU卡胆筒,并且每塊卡包含16276MiB邮破,從用戶的角度來看:該節(jié)點(diǎn)的GPU資源為16276 *2 = 32552; 同時(shí)也會(huì)將節(jié)點(diǎn)上的GPU卡數(shù)量2作為另外一個(gè)Extended Resource上報(bào)诈豌。
2. 擴(kuò)展調(diào)度
GPU Share Scheduler Extender可以在分配gpu-mem給Pod的同時(shí)將分配信息以annotation的形式保留在Pod spec中,并且在過濾時(shí)刻根據(jù)此信息判斷每張卡是否包含足夠可用的gpu-mem分配抒和。
2.1Kubernetes默認(rèn)調(diào)度器在進(jìn)行完所有過濾(filter)行為后會(huì)通過http方式調(diào)用GPU Share Scheduler Extender的filter方法, 這是由于默認(rèn)調(diào)度器計(jì)算Extended Resource時(shí)矫渔,只能判斷資源總量是否有滿足需求的空閑資源,無法具體判斷單張卡上是否滿足需求摧莽;所以就需要由GPU Share Scheduler Extender檢查單張卡上是否含有可用資源庙洼。
以下圖為例, 在由3個(gè)包含兩塊GPU卡的節(jié)點(diǎn)組成的Kubernetes集群中镊辕,當(dāng)用戶申請(qǐng)gpu-mem=8138時(shí)油够,默認(rèn)調(diào)度器會(huì)掃描所有節(jié)點(diǎn),發(fā)現(xiàn)N1所剩的資源為 (16276 * 2 - 16276 -12207 = 4069 )不滿足資源需求征懈,N1節(jié)點(diǎn)被過濾掉石咬。
而N2和N3節(jié)點(diǎn)所剩資源都為8138MiB,從整體調(diào)度的角度看卖哎,都符合默認(rèn)調(diào)度器的條件;此時(shí)默認(rèn)調(diào)度器會(huì)委托GPU Share Scheduler Extender進(jìn)行二次過濾焕窝,在二次過濾中它掂,GPU Share Scheduler Extender需要判斷單張卡是否滿足調(diào)度需求虐秋,在查看N2節(jié)點(diǎn)時(shí)發(fā)現(xiàn)該節(jié)點(diǎn)雖然有8138MiB可用資源熟妓,但是落到每張卡上看译仗,GPU0和分別GPU1只有4069MiB的可用資源,無法滿足單卡8138MiB的訴求笛辟。而N3節(jié)點(diǎn)雖然也是總共有8138MiB可用資源手幢,但是這些可用資源都屬于GPU0,滿足單卡可調(diào)度的需求。由此胀蛮,通過GPU Share Scheduler Extender的篩選就可以實(shí)現(xiàn)精準(zhǔn)的條件篩選粪狼。
2.2當(dāng)調(diào)度器找到滿足條件的節(jié)點(diǎn)不跟,就會(huì)委托GPU Share Scheduler Extender的bind方法進(jìn)行節(jié)點(diǎn)和Pod的綁定,這里Extender需要做的是兩件事情
以binpack的規(guī)則找到節(jié)點(diǎn)中最優(yōu)選擇的GPU卡id,此處的最優(yōu)含義是對(duì)于同一個(gè)節(jié)點(diǎn)不同的GPU卡吴趴,以binpack的原則作為判斷條件厢拭,優(yōu)先選擇空閑資源滿足條件但同時(shí)又是所剩資源最少的GPU卡,并且將其作為ALIYUN_COM_GPU_MEM_IDX保存到Pod的annotation中薄坏;同時(shí)也保存該P(yáng)od申請(qǐng)的GPU Memory作為ALIYUN_COM_GPU_MEM_POD和ALIYUN_COM_GPU_MEM_ASSUME_TIME保存至Pod的annotation中,并且在此時(shí)進(jìn)行Pod和所選節(jié)點(diǎn)的綁定涵但。
注意:這時(shí)還會(huì)保存ALIYUN_COM_GPU_MEM_ASSIGNED的Pod annotation,它被初始化為“false”。它表示該P(yáng)od在調(diào)度時(shí)刻被指定到了某塊GPU卡哨啃,但是并沒有真正在節(jié)點(diǎn)上創(chuàng)建該P(yáng)od。ALIYUN_COM_GPU_MEM_ASSUME_TIME代表了指定時(shí)間。
如果此時(shí)發(fā)現(xiàn)分配節(jié)點(diǎn)上沒有GPU資源符合條件莱找,此時(shí)不進(jìn)行綁定,直接不報(bào)錯(cuò)退出浮定,默認(rèn)調(diào)度器會(huì)在assume超時(shí)后重新調(diào)度。
調(diào)用Kubernetes API執(zhí)行節(jié)點(diǎn)和Pod的綁定
以下圖為例悯辙,當(dāng)GPU Share Scheduler Extender要把gpu-mem:8138的Pod和經(jīng)過篩選出來的節(jié)點(diǎn)N1綁定,首先會(huì)比較不同GPU的可用資源击费,分別為GPU0(12207),GPU1(8138),GPU2(4069),GPU3(16276),其中GPU2所剩資源不滿足需求,被舍棄掉;而另外三個(gè)滿足條件的GPU中, GPU1恰恰是符合空閑資源滿足條件但同時(shí)又是所剩資源最少的GPU卡,因此GPU1被選出歪沃。
3. 節(jié)點(diǎn)上運(yùn)行
當(dāng)Pod和節(jié)點(diǎn)綁定的事件被Kubelet接收到后萎羔,Kubelet就會(huì)在節(jié)點(diǎn)上創(chuàng)建真正的Pod實(shí)體育灸,在這個(gè)過程中, Kubelet會(huì)調(diào)用GPU Share Device Plugin的Allocate方法,Allocate方法的參數(shù)是Pod申請(qǐng)的gpu-mem。而在Allocate方法中,會(huì)根據(jù)GPU Share Scheduler Extender的調(diào)度決策運(yùn)行對(duì)應(yīng)的Pod
3.1會(huì)列出該節(jié)點(diǎn)中所有狀態(tài)為Pending并且ALIYUN_COM_GPU_MEM_ASSIGNED為false的GPU Share Pod
3.2選擇出其中Pod Annotation的ALIYUN_COM_GPU_MEM_POD的數(shù)量與Allocate申請(qǐng)數(shù)量一致的Pod蒋譬。如果有多個(gè)符合這種條件的Pod,就會(huì)選擇其中ALIYUN_COM_GPU_MEM_ASSUME_TIME最早的Pod惠爽。
3.3將該P(yáng)od的annotationALIYUN_COM_GPU_MEM_ASSIGNED設(shè)置為true租副,并且將Pod annotation中的GPU信息轉(zhuǎn)化為環(huán)境變量返回給Kubelet用以真正的創(chuàng)建Pod。
相關(guān)項(xiàng)目
目前項(xiàng)目已經(jīng)開源到github.com上
部署
請(qǐng)參照部署文檔
測(cè)試樣例
1. 首先創(chuàng)建一個(gè)使用aliyun.com/gpu-mem的應(yīng)用
apiVersion: apps/v1kind: Deploymentmetadata:? name: binpack-1? labels:? ? app: binpack-1spec:? replicas: 1? selector:# define how the deployment finds the pods it managesmatchLabels:? ? ? app: binpack-1? template:# define the pods specificationsmetadata:? ? ? labels:? ? ? ? app: binpack-1? ? spec:? ? ? containers:? ? ? - name: binpack-1? ? ? ? image: cheyang/gpu-player:v2? ? ? ? resources:? ? ? ? ? limits:# MiBaliyun.com/gpu-mem: 1024
使用
請(qǐng)參照使用文檔
構(gòu)建
請(qǐng)參照如何構(gòu)建
視頻Demo
Demo 1:部署多個(gè)GPU Share的Pod人弓,發(fā)現(xiàn)他們以binpack的方式被放置到同一個(gè)GPU卡上
視頻地址:http://cloud.video.taobao.com//play/u/2987821887/p/2/e/6/t/1/214292079721.mp4
Demo 2:避免錯(cuò)誤調(diào)度申請(qǐng)資源超過單個(gè)GPU可用資源的Pod
視頻地址:http://cloud.video.taobao.com//play/u/2987821887/p/2/e/6/t/1/214235285109.mp4
Roadmap
利用nvidia MPS實(shí)現(xiàn)隔離
支持該方案可以在由kubeadm初始化的Kubernetes集群自動(dòng)化部署
Scheduler Extener的高可用性
為GPU, RDMA 和彈性網(wǎng)卡提供通用方案
本文作者:必嘫
作者:阿里云云棲社區(qū)
鏈接:http://www.reibang.com/p/99f3b21b534b
來源:簡(jiǎn)書
簡(jiǎn)書著作權(quán)歸作者所有意蛀,任何形式的轉(zhuǎn)載都請(qǐng)聯(lián)系作者獲得授權(quán)并注明出處。