1. 程式人生 > >民生銀行基於Kubernetes+GPU構建Tensorflow應用實踐_Kubernetes中文社群

民生銀行基於Kubernetes+GPU構建Tensorflow應用實踐_Kubernetes中文社群

左宇鵬

2014年畢業於北京工業大學計算機學院,曾就職於某大型國企從事資料庫運維工作。2018年3月加入民生銀行資訊科技部系統管理中心團隊,目前主要致力於基於kubernetes和docker的容器平臺和ceph分散式儲存的研究和運維工作。

背景

近年來,隨著人工智慧、機器學習、深度學習等技術的火熱,GPU也得到了快速的發展。GPU的使用可以從很大程度上加快深度學習任務的執行速度,而諸如tensorflow框架的出現和應用更是離不開對GPU資源的依賴。
民生銀行在一個深度學習專案中,部署了一套支援GPU的Kubernetes叢集,開始了Kubernetes+GPU+Tensorflow的深度學習之旅。

Kubernetes(以下簡稱k8s)在版本1.6後正式支援對Nvidia GPU的排程功能,在版本1.9後又加入了對AMD GPU的支援。本文以Nvidia GPU為例,具體介紹k8s叢集GPU節點的部署與使用實踐,供大家參考借鑑。

二、環境介紹

作業系統版本:SUSE12SP3
K8s版本:1.9
Docker版本:17.06
Nvidia GPU型號:GeForce GTX 1080 Ti
K8s叢集已提前部署好,並且將GPU節點加入到叢集中。

三、Device Plugin概述

K8s從1.8版本開始到1.10版本之前,為了支援GPU的排程,必須設定–feature-gates=”DevicePlugins=true”引數來開啟DevicePlugins功能,從1.10版本開始不再需要設定該引數。
Device Plugin實際上是一個gRPC介面,裝置廠商只需要根據Device Plugin的介面實現一個特定裝置的外掛,而不需要修改k8s的核心程式碼。
Nvidia GPU Device Plugin需要k8s叢集的GPU節點具備如下條件:
節點必須預先安裝好nvidia 驅動
節點必須預先安裝好nvidia-docker 2.0
docker的default runtime必須配置成nvidia-container-runtime,而不是runc
nvidia驅動版本在361.93以上

四、GPU節點驅動安裝


確認主機有nvidia顯示卡
# lspci |grep -i nvidia
04:00.0 VGA compatible controller: NVIDIA Corporation Device 1b06 (rev a1)
04:00.1 Audio device: NVIDIA Corporation Device 10ef (rev a1)


安裝依賴包
# zypper install -y gcc make


安裝與kernel版本一致的kernel development packages
# zypper install -y kernel–devel=
其中,上面的variant和version需要與當前執行的kernel的variant和version保持一致。
# uname -r
4.4.92-6.18-default
從上面的結果可以確定,variant=default,version=4.4.92-6.18,所以安裝如下devel package
# zypper install -y kernel-default-devel=4.4.92-6.18
由於kernel-default-devel依賴於kernel-devel,所以需要先安裝相同版本的kernel-devel
# zypper install -y kernel-devel=4.4.92-6.18


nvidia官網下載驅動
登入nvidia官網https://www.nvidia.com/download/index.aspx設定檢索條件下載相應的驅動。

這裡下載的驅動版本是NVIDIA-Linux-x86_64-390.87.run


安裝nvidia驅動
# sh NVIDIA-Linux-x86_64-390.87.run -a -s -q


驗證是否安裝成功
# nvidia-smi
顯示如下結果,說明安裝成功。

五、nvidia-docker安裝配置

nvidia-docker是nvidia為了提高Nvidia GPU在docker中的易用性, 通過對原生docker的封裝實現了自己的 nvidia-docker 工具。
nvidia-docker 對於使用GPU資源的docker容器支援的層次關係如下圖所示:

nvidia-docker 使得 docker 對於 GPU 資源的使用更加容易。截止到目前 nvidia-docker 官方經過了兩次大版本的迭代,nvidia-docker和nvidia-docker2。nvidia-docker2在 nvidia-docker的基礎上易用性和架構層面做了更多的優化。nvidia-docker2目前官方支援的作業系統版本主要包括Ubuntu 14.04/16.04/18.04、Debian Jessie/Stretch、Centos 7、Redhat 7.4/7.5、Amazon Linux 1/2,詳細資訊及安裝方法可參考https://nvidia.github.io/nvidia-docker。

由於nvidia-docker2目前還不支援suse作業系統,所以為了使suse環境下的docker能夠使用GPU資源,我們將nvidia-container的相關元件重新編譯以相容當前環境下的docker版本,達到與nvidia-docker2相同的效果。


安裝nvidia-container-runtime

# rpm -ivh libnvidia-container1-1.0.0-0.1.alpha.3.x86_64.rpm
 # rpm -ivh libnvidia-container-tools-1.0.0-0.1.alpha.3.x86_64.rpm
 # rpm -ivh nvidia-container-runtime-1.1.1-99.docker17.06.2.x86_64.rpm


修改docker的default runtime
編輯/etc/docker/daemon.json檔案,新增如下內容:

{
 "default-runtime": "nvidia",
 "runtimes": {
 "nvidia": {
 "path": "/usr/bin/nvidia-container-runtime",
 "runtimeArgs": []
 }
 }
 }

六、K8s開啟DevicePlugins功能


在master各節點和GPU節點上的kubelet加入啟動引數
/etc/systemd/system/kubelet.service.d/10-kubeadm.conf檔案的配置
Environment=”KUBELET_FEATURE_GATES_ARGS=–feature-gates=DevicePlugins=true”

重啟kubelet使引數生效
# systemctl daemon-reload
# systemctl restart kubelet

檢查新增引數是否生效

# ps -ef|grep kubelet


在master各節點的kube-apiserver、kube-controller-manager、kube-scheduler加入啟動引數
各節點依次修改/etc/kubernetes/manifests目錄下的3個檔案。
分別是kube-apiserver.yaml、kube-controller-manager.yaml、kube-scheduler.yaml,新增如下內容:
– –feature-gates=DevicePlugins=true

檢查新增引數是否生效

# ps -ef|grep apiserver
 # ps -ef|grep controller
 # ps -ef|grep scheduler

七、部署nvidia-device-plugin

建立nvidia-device-plugin.yaml檔案,新增如下內容:

apiVersion: extensions/v1beta1
 kind: DaemonSet
 metadata:
 name: nvidia-device-plugin-daemonset
 namespace: kube-system
 spec:
 template:
 metadata:
 annotations:
 scheduler.alpha.K8s.io/critical-pod: ""
 labels:
 name: nvidia-device-plugin-ds
 spec:
 tolerations:
 - key: CriticalAddonsOnly
 operator: Exists
 containers:
 - image: nvidia/k8s-device-plugin:1.9
 name: nvidia-device-plugin-ctr
 securityContext:
 allowPrivilegeEscalation: false
 capabilities:
 drop: ["ALL"]
 volumeMounts:
 - name: device-plugin
 mountPath: /var/lib/kubelet/device-plugins
 volumes:
 - name: device-plugin
 hostPath:
 path: /var/lib/kubelet/device-plugins

在master節點上執行如下命令部署nvidia-device-plugin

# kubectl apply -f nvidia-device-plugin.yaml

檢視部署情況

# kubectl get pod -n kube-system|grep nvidia
 nvidia-device-plugin-mlp3com 1/1 Running 29 7d

在master節點上檢視GPU節點資訊,看k8s能否識別節點的GPU資源

# kubectl describe node

如上圖所示,表明配置成功。如果未出現GPU或者GPU後面的數字是0,說明配置失敗。至此,k8s叢集就可以排程節點上的GPU資源了。

八、Tensorflow應用部署測試

為了進一步驗證k8s可以成功排程GPU,我們部署了一個基於GPU的tensorflow應用做一下簡單的測試。
下面是應用的部署配置檔案gpu-test.yaml

 apiVersion: v1
 kind: Service
 metadata:
 name: cmbc-serving
 labels:
 app: tensorflow-serving
 spec:
 type: NodePort
 ports:
 - name: http-serving
 port: 5000
 targetPort: 5000
 selector:
 app: tensorflow-serving
 ---
 # Source: tensorflow-serving/templates/deployment.yaml
 apiVersion: extensions/v1beta1
 kind: Deployment
 metadata:
 name: cmbc-serving
 labels:
 app: tensorflow-serving
 spec:
 replicas: 1
 strategy:
 type: RollingUpdate
 template:
 metadata:
 labels:
 app: tensorflow-serving
 spec:
 hostNetwork: true
 containers:
 - name: serving
 image: "fast-style-transfer-serving:la_muse"
 imagePullPolicy: "IfNotPresent"
 env:
 command: ["python", "app.py"]
 ports:
 - containerPort: 5000
 name: http-serving
 resources:
 limits:
 nvidia.com/gpu: 1

執行下面命令建立應用:

# kubectl apply -f gpu-test.yaml

此時在GPU節點上執行nvidia-smi,檢視GPU使用情況,從下圖中可以看到,k8s會自動選擇帶有GPU的節點部署應用,並且應用成功地使用GPU資源進行計算,以處理外部的訪問請求。

九、總結

至此,使用k8s排程GPU部署tensorflow應用的主要流程已經介紹完了,還有很多需要完善的地方,比如tensorflow在k8s中的模型訓練、k8s如何支援GPU的親和性等等。總之,這只是我們前期的初步探索,未來會根據進展情況再與大家分享。

來源:民生運維