作者:左宇鹏
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节点加入到集群中。
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以上
1.确认主机有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)
2.安装依赖包
# zypper install -y gcc make
3.安装与kernel版本一致的kernel development packages
# zypper install -y kernel-<variant>-devel=<version>
其中,上面的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
4.nvidia官网下载驱动
登录nvidia官网https://www.nvidia.com/download/index.aspx设置检索条件下载相应的驱动。
# sh NVIDIA-Linux-x86_64-390.87.run -a -s -q
6.验证是否安装成功
# nvidia-smi
nvidia-docker是nvidia为了提高Nvidia GPU在docker中的易用性, 通过对原生docker的封装实现了自己的 nvidia-docker 工具。
nvidia-docker 对于使用GPU资源的docker容器支持的层次关系如下图所示:
# 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
2.修改docker的default runtime
编辑/etc/docker/daemon.json文件,添加如下内容:
{
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
1.在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
2.在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.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_node>
为了进一步验证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的亲和性等等。总之,这只是我们前期的初步探索,未来会根据进展情况再与大家分享。
转自微信公众号:民生运维
如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!
赞3
添加新评论0 条评论