1. 程式人生 > >基於 Kubernetes 的 AI 訓練實踐_Kubernetes中文社群

基於 Kubernetes 的 AI 訓練實踐_Kubernetes中文社群

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 版本。