技術分享:基於 Kubernetes 的 AI 訓練實踐

2017 China KEUC(Kubernetes End User Conference)秉承開放協作、技術共享的宗旨,致力於爲業界帶來最新 Kubernetes 技術、行業應用案例展示與最佳實踐,同時將中國已有的優秀實踐經驗推廣到全球,這對於 Kubernetes 從理論到落地推廣、並走向國際化將有着極爲深遠的意義。近日,七牛雲亮相Kubernetes 中國用戶大會,來自七牛容器雲部門的後端研發的陸龍文,聚焦 Kubernetes 新特性,發表精彩的主題演講。

七牛雲的 AI 部門屬於容器雲部門的客戶,針對於 AI 訓練這樣一個特殊的訓練場景,具體落實到 k8s 的實踐上具體實施工作怎樣做的,帶給七牛怎樣的好處,以及從中碰到一些什麼樣的問題陸龍文對此做了分享。

1、AI 訓練的業務情況

七牛本身有一個深度學習的平臺,這是一個端到端的深度學習平臺,包括從對原始富媒體數據的打標,到製成一個可以被訓練任務讀取的樣本集,到訓練任務的觸發以及訓練成果的存儲,包括對於最後訓練出來模型的評估,評估完成以後最後將這個模型打包成你的線上業務,通過 API 形式對外提供服務一整套流程的平臺。
 

AI 訓練是這個平臺中的一個部分。AI訓練迭代是怎樣的一個事情?

AI 訓練迭代分兩個階段:

第一,樣本集的生成,任務輸入是兩個:一是來自於七牛對象存儲的原始數據,主要是一些圖片、音視頻流富媒體數據;二是 ava 平臺本身有一個打標系統,可以對原始數據進行標籤,通過樣本生成器生成樣本集,存儲到容器雲平臺的存儲當中,這是一個分佈式的網絡存儲。

第二,一旦你的樣本集生成完成以後會自動觸發或者人工觸發一個訓練任務進行一個訓練,讀取整個平臺由算法工程師事前準備的算法模型、訓練參數到你的訓練任務當中進行  。
訓練,最後將你的訓練任務輸出到存儲,最後上傳到對象存儲當中去的整個過程。

2、Kubernetes 的優勢

我們這邊遇到的痛點是什麼?

第一,使用 Kubernetes 做平臺之前,訓練流程上需要算法工程師通過腳本、控制訓練任務的觸發以及訓練任務要存儲到什麼地方,同時訓練任務可能因爲一些硬件錯誤導致失敗,失敗需要人工介入。

第二,資源規劃方面,GPU 集羣是很多人共享的,其中 GPU 資源需要人爲協調,耗費掉很多精力。

第三,訓練任務完成以後並沒有把佔用的 GPU 釋放掉,造成一定的資源浪費。

第四,存儲,訓練任務的存儲往往是非常大的樣本集,需要容量非常大的網絡存儲支撐,在此之前我是用的是 NFS,服務可用性沒有辦法達到需求,水平擴展以及性能也沒有辦法滿足訓練任務的要求。

k8s 主要有兩個優勢:

第一,k8s 支持 GPU 調度的,我們積極將整個實踐過程當中取得的成果回饋到社區;

第二,k8s 支持多種 Workload 的調度方式,適應不同的業務場景,JOB 與訓練任務兩者切合度非常高。

k8s 和現在開源社區結合非常好,包括監控日誌方案社區已經取得了相當成果,在搭建平臺的時候這個部分省了很多人力。

3、基於 Kubernetes 的 AI 訓練

 
AI 訓練-生成樣本集

整個調度僅僅利用 k8s 調度沒有辦法很好的滿足業務需求,我們對樣本集的生成有 SampleJobController 做整個樣本集生成任務的調度,生成任務從對象存儲和 mongo 數據庫中讀取輸入數據,產出一個樣本集輸入到 CEPH 存儲。
 

 
AI 訓練-啓動訓練任務

以上任務完成以後會觸發一個 Training Job Controller 的訓練任務,這個訓練任務從剛剛的樣本集裏讀取數據,同時配合算法模型和訓練參數,對於算法模型的權重進行計算,最後訓練完成以後再將新的算法模型輸出到 CEPH 存儲當中,如果評估下來比較好的話可以上傳到對象存儲當中,CEPH 這部分存儲資源可以釋放掉了。

 
AI 訓練-使用 CEPH 存儲

使用的 CEPH 存儲訓練 AI 訓練任務場景主要有三個好處:

第一,數據規模可以支持非常大,最大樣本集可以達到一個樣本集 10T 數據,需要讀取數據服務一定需要有一個網絡共享來支撐,這樣在物理機發生故障時,pod 在別處被重啓後仍然能訪問之前的數據;

第二, CEPH 存儲是分佈式存儲,水平擴展性非常良好,訓練級規模上升以後可以很快速的進行水平擴展;

第三,讀寫控制,Kubernetes 一個獨佔的讀寫和多個 Pod 同時讀取的模型,適用於訓練模型的整個流程,包括之前樣本集生成有一個樣本生成,一旦完成以後可以進入只讀模式,多個任務同時讀取進行併發訓練。CEPH 使用過程中我們把積極地改進回饋給社區,比如說 ImageFormat2 的支持,還有 k8s 對 CEPH 調度需要有一個 Provisioner 去支持的,現在整個社區演進方向希望將這些存儲 Provisioner 全部變成獨立部署的形式,便於它的升級擴展。

GPU資源規劃採用Node Label+Node Selector,對訓練任務進行調度,我們的 GPU 卡可能有不同的型號,對不同訓練任務會有型號上的偏好,這個時候可以爲每一臺機器上裝的具體型號的顯卡幫助它打上一個標籤,之後進行訓練任務調度的時候可以使用 Node Selector 將這個任務調度上去。

關於資源方面的,Kubernetes 提供了比較好的 Limits+request 資源分配模型,Limits 表示這個 Pod 最多使用多少資源,Request 是說要將這個任務調度起來最少需要多少資源,目前對於 GPU 這樣的模型沒有辦法很好的工作,我們缺少一個有效的機制監控 GPU 使用多少,限制對 GPU 使用,對於 CPU 和 Memory 可以有效的使用這樣的模型,進行合理超賣,提資源的利用率。

關於 Nvidia GPU Driver,訓練任務需要在 Pod 當中使用具體顯卡的驅動,每一臺機器安裝不  
同型號的顯卡驅動版本也是不一樣的,但是我們 Pod 並不關心這個版本,只是調度到這臺機器上就需要這臺機器上對應型號顯卡的驅動,我就可以通過 k8s 的 Hostpath 方式掛載到 Pod上去,打包鏡像的時候完全不需要關心 GPU 驅動這個事情。

物理機監控
基於 Prometheus Node Exporter

獲取 CPU、內存、磁盤、網絡維度信息

容器監控
kubelet 內嵌 cadvisor

監控註冊
Prometheus 從 kubernetes apiserver 獲取需監控的資源

GPU 監控
GPU 使用率

現存使用率

GPU核心使用率

關於監控和日誌方案採用的是 Prometheus,它本身提供的 Prometheus Node Exporter 可以很好的幫助我們關注整個集羣裏物理機結構的信息,kubelet 裏已經集成 cadvisor 幫助我們提供容器內部的監控信息,我們還在上面做了一個改進就是將 GPU 的監控信息添加到監控方案當中去,並且貢獻給社區。

關於日誌方案我們採用了由七牛自主研發的分片的 Elastic Search 自研的 Sharding 集羣,承載了目前所有七牛的業務數據以及包括外部客戶的數據,把 Elastic Search 運維的工作完全交付給七牛 pandora 日誌存儲分析平臺。
 

4、一次踩坑經歷

接下來分享一下我們在運維當中碰到的問題,最後造成很嚴重後果的事故,首先介紹要一下 k8s 使用 CEPH 存儲是怎樣一個過程?我們知道 CEPH 存儲是通過 CEPH 的 RBD 命令,將 CEPH 的 image attach 到你的宿主機成爲一個塊設備,k8s 將這個設備 Mount 到 Kubelet 的Pulgins 文件夾下面,再次通過 Mount rbind 的方式綁定到對應需要的 POD 的目錄下,這是 CEPH image 綁定到 POD 的過程。 mount rbind 是掛載命令,本身是有三種模式: Shared、slave、private,k8s 在使用的時候是 1.6,僅僅支持 Private 模式。

因爲這樣一個原因導致了故障的發生:我們有一個容器 A 已經運行起來了,是隻讀的方式掛載了一個存儲,接下來 Node Exporter 要進行監控採集,爲了獲取某些監控數據,會以 Make-private 掛載整個宿主機根目錄,剛纔提到已經有容器 A 將 RBD Volume 掛在起來了,勢必之後的掛載也將這個帶到了 Promethus 的 Node Exporter,導致了 A 容器運行完成以後將容器銷燬了,卸載 RBD Volume 成功,但是 RBD umap 失敗,主要是因爲 Node-Exporter 仍在在 RO 掛載。我們也沒有發現這個問題。
 

又一個新的容器 B 要試圖讀取這個 Volume 的時候,發現這個 Volume 這個設備已經存在物理機上,再次以讀取的方式掛載,導致了掛載失敗,k8s 在這種情況下會試圖獲取設備的文件系統信息,因爲我們之前犯的另外一個錯誤,獲取文件信息就失敗了,k8s 獲取文件信息是空的,處理方式也比較簡單粗暴,認爲獲取失敗這個盤就是沒有格式化過的,就觸發了格式化,把我們之前訓練好的數據直接全部格式化掉了。

整個故障原因就是 Node-exporter 掛載根目錄方式比較危險,導致了之後掛載 ceph 卷失敗。掛載卷失敗這原本不是一個太嚴重的問題,也是因爲我們之前部署上的問題導致了 ceph 服務端和客戶端版本不一致,致使獲取文件信息失敗,本身 k8s 對這種情況處理方式簡單粗暴,種種原因放在一起導致了整個事故的發生。反思這次事故,主要有幾個點:

第一,部署流程需要固化,因爲我們每次部署都要需要人手工操作,一些配置文件都是當時修改出來的,要把整個部署流程固化下來,在部署完成以後要檢查相應的版本。

第二,即便你真正犯了錯誤的時候,需要有一個完整的機制把系統組件的日誌抓取出來,配置成告警的形式及時的跟進,因爲回顧排查的時候由於版本不一致的問題已經在日常工作中產生了錯誤日誌,但是我們並沒有引起重視,一直到事故發生,發生數據丟掉的時候回過頭來看的時候才發現這個問題。

第三,對於 Kubernetes 使用知識瞭解不夠,這些知識也是對整個事故跟進的時候,發現 Kubernetes 處理邏輯是這個樣子的。團隊對於 Kubernetes 相關處理邏輯要進行梳理,避免一些潛在的隱患。最終我們通過使用二進制在物理機部署 Node Exporter 的方式來暫時緩解這個問題。

5、接下來的工作

**第一,自配置監控。**Prometheus 對 k8s 的支持是比較好的,現在已經支持自動從 k8s 的 APIServer 裏獲取 Service,發現需要抓量的 Service 自動抓取,這個已經應用到系統組件當中,但是對於我們的AI訓練服務,自動配置的監控工作還沒有落實,這是我們接下來要完善的一步。

第二,分佈式訓練。我們整個訓練模型還是單機版的模式,對於一個比較完整的深度學習平臺需要有一個分佈式學習的方式,也需要容器團隊和 AI 團隊一起梳理整個業務流程從而去支撐這樣一個訓練方式。

我們接下來的作也把我們現在關於 Kubernetes 運維經驗產品化以後變成七牛公有云的平臺,會在 11 月份上線 preview 版本。
     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章