如何使用Kubernetes GPU叢集自動訓練和加速深度學習?

機器之心發表於2017-06-14
像 Docker 這樣的容器格式和 Kubernetes 之類的容器管理平臺正越來越受到人們的歡迎,這不僅僅是因為人們喜歡微服務,出於很多原因,公司的資訊長和工程高管都樂於接受微服務,他們也會把容器視為他們的混合雲戰略的關鍵組成部分。這是因為容器空間(Docker、Kubernetes 和 DC / OS 等)的核心技術、生態系統是全面開源的,這為使用者提供了抽象的虛擬化工具。近日,卡爾斯魯厄理工學院(KIT)的電腦科學學生 Frederic J. Tausch 在 GitHub 上釋出了一篇詳細教程,「可以幫助研究人員和愛好者們用他們的 Kubernetes GPU 叢集輕鬆地對深度學習的訓練過程進行自動操作和加速。」機器之心對本教程進行了編譯。

教程地址及相關檔案:https://github.com/Langhalsdino/Kubernetes-GPU-Guide


在這個教程中,我將要介紹如何輕鬆地在多個 Ubuntu 16.04 裸機伺服器上進行 Kubernetes GPU 叢集配置,並且提供一些有用的指令碼和.yaml 檔案,它們可以給你提供全部配置。


順便說一句:如果你是用 Kubernetes GPU 叢集做一些其他的東西,這篇教程也同樣適用於你。


我為什麼要寫這篇教程?


我現在是新創辦的 understand.ai 公司的一名實習生,我在平時的工作中注意到:先在本地設定機器學習演算法,然後把它放進雲端用不同引數和資料集去進行訓練,這一過程是很麻煩的。


第二點,把它放進雲端進行大量的訓練往往比預想的還要費時間,這是令人沮喪的,並且通常包含很多缺陷。


基於這個原因我下定決心要解決這個問題,並且讓第二部分變得容易,簡單,快捷。


這是一篇實踐教程,是關於怎樣設定我們自己的 Kubernetes GPU 叢集來提升工作速度的。


深度學習科研人員的新工作流程:


用 Kubernetes GPU 叢集進行自動化的深度學習訓練顯著地改善了在雲端進行模型訓練的流程。

此說明呈現了新的工作流程,只包含兩個簡單步驟:


如何使用Kubernetes GPU叢集自動訓練和加速深度學習?


免責宣告:


請注意,以下部分僅代表個人觀點。Kubernetes 是一個正在快速升級的環境,這意味著本篇教程可能會在將來的某個時間失效,這取決於工作者們的空餘時間和個人貢獻。由於這個原因我們也很希望大家可以群策群力,做出新的貢獻。


目錄

  • Kubernetes 的快速回顧
  • 叢集結構概覽
  • 初始化節點
  • 我的配置
  • 配置指令
  • 使用快速配置的指令碼
  • 步驟的詳細說明
  • 怎樣建立你的 GPU 容器
  • .yml 的重要部分
  • GPU 例項的使用
  • 一些有用的指令
  • 致謝
  • 作者
  • 版權

Kubernetes 的快速回顧


如果你需要更新你的 Kubernetes 的相關知識,這些文章可能對你是有用處的:


  •  Introduction to Kubernetes by DigitalOcean (https://www.digitalocean.com/community/tutorials/an-introduction-to-kubernetes)
  • Kubernetes concepts (https://kubernetes.io/docs/concepts/)
  • Kubernetes by example (http://kubernetesbyexample.com/)
  • Kubernetes basics - interactive tutorial (https://kubernetes.io/docs/tutorials/kubernetes-basics/)


叢集結構的概覽


主要思想:即用一個小 CPU 作為主控節點(master node)來控制一個叢集的 GPU-工作節點(GPU-worker nodes)。


如何使用Kubernetes GPU叢集自動訓練和加速深度學習?

初始化節點


在我們使用叢集之前,先對叢集進行初始化是很重要的。因此每個節點必須被手動初始化,然後才能加入到叢集當中。


我的配置


此配置對上述案例十分適用——對其他例項或作業系統來說,往往需要一些額外的除錯。

Master 主控節點


  • 有根許可權的 Ubuntu 16.04
  • 我使用的是谷歌計算引擎 VM-Instance
  • SSH 訪問
  • ufw 停用
  • 啟用埠(udp 和 tcp)
  • 6443, 443, 8080 
  • 30000-32767(僅在你的應用需要它們的情況下)
  • 從叢集外部訪問伺服器


Worker 工作站


  • 有根許可權的 Ubuntu16.04
  •  我使用的是谷歌計算引擎
  • SSH 訪問
  • ufw 停用
  • 啟用埠(udp 和 tcp)
  •  6443, 443


關於安全性:在使用過程中你應該關閉一些防火牆——為了更加簡單,應該禁用 ufw。為實際的生產工作負載設定 Kubernetes 當然應該包括啟用一些防火牆,像 ufw, iptables 或你的雲端伺服器的防火牆。也要注意在雲端設定一個工作叢集可能更加複雜。你的雲端供應商通常會提供一個他們自己的防火牆,這是和主機防火牆相分離的。你可能必須要停用 ufw,並且也要啟用雲端供應商的防火牆,使本教程的步驟可以正常進行下去。


設定嚮導


這些說明涵蓋了我們在 Ubuntu 16.04 系統上的操作經驗,可能有些地方並不適合於轉移到其他操作平臺。


如下所示,我們構建了兩個指令碼,它們能完全啟動主控節點(master node)和工作節點(worker node)。如果你希望快速執行,那麼就只需要使用以下兩個指令碼就行。否則的話,我建議跟著設定嚮導一步步閱讀。


快速通道—設定指令碼


下面我們將利用指令碼進行快速設定。首先需要複製對應的指令碼到主節點和工作節點的機器上:


  • 主控節點:https://github.com/Langhalsdino/Kubernetes-GPU-Guide/blob/master/scripts/init-master.sh
  • 工作結點:https://github.com/Langhalsdino/Kubernetes-GPU-Guide/blob/master/scripts/init-worker.sh

主控節點


執行上面的主控節點初始化指令碼,並記下代號。代號通常看起來像:--token f38242.e7f3XXXXXXXXe231e

chmod +x init-master.shsudo ./init-master.sh


工作節點


執行上面的工作節點初始化指令碼,並要求輸入正確的主控節點代號和 IP,埠通常使用 6443。


chmod +x init-worker.shsudo ./init-worker.sh :


詳細的安裝說明


主控節點


1. 新增 Kubernetes 資源庫到軟體包管理器中:


sudo bash -c 'apt-get update && apt-get install -y apt-transport-httpscurl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -cat </etc/apt/sources.list.d/kubernetes.listdeb http://apt.kubernetes.io/ kubernetes-xenial mainEOFapt-get update'


2. 安裝 docker-engine、kubeadm、kubectl 和 kubernetes-cni 庫


sudo apt-get install -y docker-enginesudo apt-get install -y kubelet kubeadm kubectl kubernetes-cnisudo groupadd dockersudo usermod -aG docker $USERecho 'You might need to reboot / relogin to make docker work correctly'


3. 因為我們希望使用 GPU 構建一個計算機叢集,所以我們需要 GPU 能在主控節點中進行加速。當然,也許該說明會因為新版本的 Kubernetes 出現而需要更改。


3.1 將 GPU 支援新增到 Kubeadm 配置中,這個時候叢集是沒有初始化的。這一步需要在叢集每一個節點的機器中完成,即使有一些沒有 GPU。


sudo vim /etc/systemd/system/kubelet.service.d/<>-kubeadm.conf


因此,新增 flag --feature-gates="Accelerators=true" 到 ExecStart 中,命令列大概如下所示:


ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS [...] --feature-gates="Accelerators=true"


3.2 重啟 kubelet


sudo systemctl daemon-reloadsudo systemctl restart kubelet


4. 現在我們需要初始化主控節點。


這一步我們需要主控節點的 IP,同時該步驟也會提供新增其他工作結點的認證資訊,所以還是需要記住代號。代號通常看起來像:--token f38242.e7f3XXXXXXXXe231e 130.211.XXX.XXX:6443


sudo kubeadm init --apiserver-advertise-address=


5. 自從 Kubernetes 1.6 從 ABAC roll-management 改為 RBAC,我們需要通知使用者的認證資訊。每一次在登入機器時,我們都需要執行這一步驟。


sudo cp /etc/kubernetes/admin.conf $HOME/sudo chown $(id -u):$(id -g) $HOME/admin.confexport KUBECONFIG=$HOME/admin.conf


6. 安裝網路擴充套件以令 pod 能相互交流。Kubernetes 1.6 對安裝這種網路擴充套件有一些環境要求,如:

  • CNI-based 網路
  • RBAC 支援環境


下面該連結匯聚了一些合適的網路擴充套件:https://docs.google.com/spreadsheets/d/1Nqa6y4J3kEE2wW_wNFSwuAuADAl74vdN6jYGmwXRBv8/edit#gid=0

kubectl apply -f https://git.io/weave-kube-1.6


5.2 現在檢查 pod,以確定所有 pod 線上驗證了能正常執行。


kubectl get pods --all-namespaces

注意:如果你需要刪除主控節點,那麼你就需要重置它。


sudo kubeadm reset


工作節點


前面的部分和主控節點的步驟是差不多的,所以可能設定地快一些。


1. 新增 Kubernetes 資源庫到軟體包管理器中:

sudo bash -c 'apt-get update && apt-get install -y apt-transport-httpscurl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -cat </etc/apt/sources.list.d/kubernetes.listdeb http://apt.kubernetes.io/ kubernetes-xenial mainEOFapt-get update'


2. 安裝 docker-engine、kubeadm、kubectl 和 kubernetes-cni 庫


sudo apt-get install -y docker-enginesudo apt-get install -y kubelet kubeadm kubectl kubernetes-cnisudo groupadd dockersudo usermod -aG docker $USERecho 'You might need to reboot / relogin to make docker work correctly'


3. 因為我們希望使用 GPU 構建一個計算機叢集,所以我們需要 GPU 能在工作結點中進行加速。當然,也許該說明會因為更新版本的 Kubernetes 出現而需要更改。


3.1 將 GPU 支援新增到 Kubeadm 配置中,這個時候叢集是沒有初始化的。這一步需要在叢集的每一個節點中完成,即使有一些沒有 GPU。


sudo vim /etc/systemd/system/kubelet.service.d/<>-kubeadm.conf


因此,新增 flag --feature-gates="Accelerators=true" 到 ExecStart 中,命令列大概如下所示:


ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS [...] --feature-gates="Accelerators=true"

3.2 重啟 kubelet


sudo systemctl daemon-reloadsudo systemctl restart kubelet

4. 現在我們需要將工作站新增到叢集中。


因此,你需要記住主控節點的代號(token),以在工作站中新增:

sudo kubeadm join --token f38242.e7f3XXXXXXe231e 130.211.XXX.XXX:6443


5. 完成了,現在檢查你的工作結點以確保能正常執行。


kubectl get nodes


注意:如果你想刪除工作節點,那麼就需要從叢集中移除節點並重置工作節點。另外,從計算機叢集移除工作節點是有益的。


在主控節點:


kubectl delete node


在工作結點:


sudo kubeadm reset


為了控制你的叢集,比如從你的客戶端(client)到你的主控節點(master),你需要用正確的使用者來認證你的客戶端(client)。這篇指導沒有說明給客戶端建立單獨使用者的內容,我們只是從主控節點來複制使用者。


[Instruction to add custom user, will be added in the future]


在你的客戶端上安裝 kubectl。我僅用 Mac 進行了測試,在 Linux 系統裡應該也可以正常工作。但我不知道在 Windows 系統裡怎麼樣。


在 Mac 上


brew install kubectl


在 Ubuntu 上你也要遵循官方指導 https://kubernetes.io/docs/tasks/tools/install-kubectl/,或者你可以從上述關於工作站(worker)的指導(可能僅適用於 Ubuntu)中提取出你需要的步驟。


2. 從主節點複製管理許可權到你的客戶端。


scp uai@130.211.XXX.64:~/admin.conf ~/.kube/


3. 新增 admin.conf 配置和授予 Kubernetes 配置認證。你需要為每一個代理完成該步驟。


export KUBECONFIG=~/.kube/admin.conf


現在你已經準備好在本地客戶端使用 kubectl 了。


3.2 可以通過列出你所有的 pod 而測試。


kubectl get pods --all-namespaces


安裝 Kubernetes 控制皮膚


Kubernetes 控制皮膚非常美觀和簡潔,它可以令指令碼小子(script kiddies)有機會實現很多功能。為了使用控制皮膚,我們首先需要執行客戶端,而 RBAC 能確保這一點。


你可以在主節點或從客戶端直接執行下面兩個步驟:


1. 檢查控制皮膚是否已經安裝了 kubectl:get pods --all-namespaces | grep dashboard


2. 如果控制皮膚沒有安裝,請安裝:

  • kubectl create -f https://git.io/kube-dashboard


如果這沒效果,請檢查 .yaml git.io/kube-dashboard 中是否定義了容器。(這個 bug 花了我好多時間)

為了訪問你的控制皮膚(dashboard),你需要為你的客戶端授權。


3. 為你的客戶端配置控制皮膚代理


在你的客戶端執行以下程式碼:

kubectl proxy


4. 在你的瀏覽器中訪問 127.0.0.1:8001/ui 進入控制皮膚。


怎麼構建你的 GPU 容器


這個指導應該可以幫助你讓一個需要 GPU 接入的 Docker 容器執行起來。


在這個指南中,我構建了一個示例 Docker 容器,其使用了 TensorFlow GPU 二進位制檔案,且可以在一個 Jupyter Notebook 中執行 TensorFlow 程式。


記住,本指南是為 Kubernetes 1.6 編寫的,如果你的配置不一樣,可能會需要一些修改。


.yml 的關鍵部分


為了讓你帶有 CUDA 的英偉達 GPU 正常執行,你必須將英偉達驅動和 CUDA 庫傳遞到你的容器。所以我們將使用 hostPath 以確保 Kubernetes pod 可以使用它們。其實際路徑因機器不同而有所差別,因為它們是由你的英偉達驅動和 CUDA 安裝定義的。


volumes: - hostPath: path: /usr/lib/nvidia-375/bin name: bin - hostPath: path: /usr/lib/nvidia-375 name: lib


將帶有驅動和 CUDA 的卷安裝到正確的目錄,以便你的容器使用。這個目錄可能配置得不一樣,具體看你的情況:


volumeMounts: - mountPath: /usr/local/nvidia/bin name: bin - mountPath: /usr/local/nvidia/lib name: lib


因為你需要告訴 Kubernetes 你需要多少個 GPU,所以你可以在這裡定義你的需求:


resources: limits: alpha.kubernetes.io/nvidia-gpu: 1


就是這些了。這就是構建你的 Kubernetes 1.6 容器所需要的一切。


後面給出了一些筆記。這裡描述一下我的整個經歷:


Kubernetes + Docker + Machine Learning + GPUs = Pure awesomeness


GPU 部署舉例


我的 example-gpu-deployment.yaml 檔案描述了 2 個部分——一個部署(deployment)和一個服務(service),因為我想通過外部訪問這個 jupyter notebook。


執行 kubectl,使之可以外部可用:


kubectl create -f deployment.yaml

該 deployment.yaml 檔案看起來是這樣的:


---apiVersion: extensions/v1beta1kind: Deploymentmetadata: name: tf-jupyterspec: replicas: 1 template: metadata: labels: app: tf-jupyter spec: volumes: - hostPath: path: /usr/lib/nvidia-375/bin name: bin - hostPath: path: /usr/lib/nvidia-375 name: lib containers: - name: tensorflow image: tensorflow/tensorflow:0.11.0rc0-gpu ports: - containerPort: 8888 resources: limits: alpha.kubernetes.io/nvidia-gpu: 1 volumeMounts: - mountPath: /usr/local/nvidia/bin name: bin - mountPath: /usr/local/nvidia/lib name: lib---apiVersion: v1kind: Servicemetadata: name: tf-jupyter-service labels: app: tf-jupyterspec: selector: app: tf-jupyter ports: - port: 8888 protocol: TCP nodePort: 30061 type: LoadBalancer---

為了驗證該配置有效,請訪問你的 JupyterNotebook 例項:http://<IP-of-master>:30061


現在你需要驗證你的 JupyterNotebook 例項可以訪問 GPU。因此,請在一個新的 Notebook 中執行以下程式碼。這會列出所有 TensorFlow 可用的裝置。


from tensorflow.python.client import device_libdef get_available_devices(): local_device_protos = device_lib.list_local_devices() return [x.name for x in local_device_protos]print(get_available_devices())

這應該會輸出 [u'/cpu:0', u'/gpu:0'] 這樣的結果。


一些有用的指令


獲取基本輸出指令


kubectl get services # List all services in the namespacekubectl get pods --all-namespaces # List all pods in all namespaceskubectl get pods -o wide # List all pods in the namespace, with more detailskubectl get deployments # List all deploymentskubectl get deployment my-dep # List a particular deployment

使用 verbose 輸出描述指令


kubectl describe nodes kubectl describe pods

刪除資源


kubectl delete -f ./pod.yaml # Delete a pod using the type and name specified in pod.yamlkubectl delete pod,service baz foo # Delete pods and services with same names "baz" and "foo"kubectl delete pods,services -l name=


進入你的一個 pod 的 bash 控制檯:


kubectl exec -it -- /bin/bash

相關文章