简介

伴随着人工智能技术的发展,机器学习的应用场景越来越广泛

深度学习的实现,需要多种技术进行支撑,比如服务器、GPU、集群、集群管理调度软件、深度学习框架、深度学习的具体应用等

随着Kubernetes的兴起,越来越多的训练任务也都直接运行在Kubernetes之上,这些基于GPU的应用也为Kubernetes的应用管理带了一定的挑战

我也一直在致力于推动公司业务上容器,本篇文档我们就来聊一聊在Kubernetes上如何管理GPU应用。

GPU驱动

要管理GPU应用,首先要解决的自然就是GPU的驱动。

首先我们得有一台带有gpu的服务器。可通过如下指令查询gpu型号(我这里以nvidia为例):

# lspci  |grep -i nvidia
00:08.0 3D controller: NVIDIA Corporation GP104GL [Tesla P4] (rev a1)

上面显示这台机器有一块nvidia的显卡,型号为Tesla P4,可以通过下面的指令查看更详细的信息:

# lspci  -v -s 00:08.0
00:08.0 3D controller: NVIDIA Corporation GP104GL [Tesla P4] (rev a1)
Subsystem: NVIDIA Corporation Device 11d8
Physical Slot: 8
Flags: bus master, fast devsel, latency 0, IRQ 39
Memory at fd000000 (32-bit, non-prefetchable) [size=16M]
Memory at e0000000 (64-bit, prefetchable) [size=256M]
Memory at f2000000 (64-bit, prefetchable) [size=32M]
Capabilities: [60] Power Management version 3
Capabilities: [68] MSI: Enable+ Count=1/1 Maskable- 64bit+
Capabilities: [78] Express Endpoint, MSI 00
Kernel driver in use: nvidia
Kernel modules: nouveau, nvidia_drm, nvidia

注:如果发现没有lspci命令,可通过yum install -y pciutils安装

有了显卡,才考虑驱动的事儿。需要先检查下系统有没有开启nouveau驱动:

lsmod |grep nouveau

如果命令输出为空,则代表没有开启,可直接安装nvidia驱动。如果有输出,则需要先禁用nouveau驱动,操作方法见附录

安装驱动有两种方式,一种是直接yum安装,一种是从nvidia官方下载指定的驱动包,手动安装。手动安装的方法可参考:https://www.cnblogs.com/breezey/p/10599705.html

我这里直接使用yum安装:

rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
yum install -y kmod-nvidia

安装完成后,需要重启下系统,然后执行如下指令验证:

# nvidia-smi
Tue Nov 5 19:01:25 2019
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.50 Driver Version: 430.50 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla P4 Off | 00000000:00:08.0 Off | 0 |
| N/A 44C P0 25W / 75W | 7403MiB / 7611MiB | 7% Default |
+-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+

看到如下信息代表驱动安装完成

Nvidia-docker

要在docker中运行gpu应用,自然首先得装个docker。但是光装个docker还不够,因为GPU属于特定的厂商产品,需要特定的driver,Docker本身并不支持GPU。

以前如果要在Docker中使用GPU,就需要在container中安装主机上使用GPU的driver,然后把主机上的GPU设备(例如:/dev/nvidia0)映射到container中。所以这样的Docker image并不具备可移植性。为此呢,Nvidia官方开源了一个称之为nvidia-docker的项目。

Nvidia-docker让Docker image不需要知道底层GPU的相关信息,而是通过启动container时mount设备和驱动文件来实现的。

nvidia-docker现在有两个版本:

  • 在nvidia-docker1中,invidia-docker作为一个独立的服务存在,用于劫持docker进程
  • 在nvidia-docker2中,为了降低部署及管理成本,invidia-docker2只是作为docker的一个runtime存在

接下来,我们来看一看安装。

  1. 安装docker
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum -y install docker-ce
systemctl start docker
  1. 安装nvidia-docker
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.repo | sudo tee /etc/yum.repos.d/nvidia-docker.repo yum install -y nvidia-docker2 pkill -SIGHUP dockerd
  1. 测试:
# # docker run --runtime=nvidia --rm nvidia/cuda:10.0-cudnn7-runtime-centos7 nvidia-smi
Tue Nov 5 19:01:25 2019
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.50 Driver Version: 430.50 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla P4 Off | 00000000:00:08.0 Off | 0 |
| N/A 44C P0 25W / 75W | 7403MiB / 7611MiB | 7% Default |
+-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+

通过--runtime指定nvidia的runtime来运行

通过这个测试也就意味着,我们的节点以及docker已经具备了运行gpu应用的能力

  1. 修改docker配置文件

接下来,修改docker配置文件,以让其将nvidia的runtime设置为默认的runtime,示例如下:

# cat /etc/docker/daemon.json
{
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
},
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "10"
},
"bip": "169.254.123.1/24",
"oom-score-adjust": -1000,
"registry-mirrors": ["https://pqbap4ya.mirror.aliyuncs.com"],
"storage-driver": "overlay2",
"storage-opts":["overlay2.override_kernel_check=true"]
}
  1. 重启docker
systemctl restart docker

Nvidia-device-plugin

要让我们的kubernetes能真正管理gpu资源,在kubernetes集群上还需要安装一个称之为nvidia-device-plugin的插件。

Kubernetes从1.8开始支持了Device Plugin。实际上就是提供一系列接口,用于支持GPU、FPGA、高性能NIC、InfiniBand等各种设备。

厂商只需要根据Device Plugin的接口实现一个特定设备的插件,Kubernetes即可使用该设备而无需修改kubernetes代码。

而nvidia-device-plugin就是nvidia针对其自己的GPU设备提供的接口实现。

这个插件是以daemonset的方式来运行的:

wget  https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.12/nvidia-device-plugin.yml

# 执行部署
kubectl create -f nvidia-device-plugin.yml

注1:下载地址中的v1.12与我们所使用的kubernetes版本所对应,目前支持的最新版本也就是v1.12,实测1.16版本的kubernetes也可以用

安装完成之后,我们可以通过如下指令看到kubernetes已正常识别node的gpu资源:

# kubectl describe node cn-beijing.i-2ze20t9nsrhsuulfefrn
Capacity:
cpu: 8
ephemeral-storage: 51473020Ki
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 32779676Ki
nvidia.com/gpu: 1
pods: 110
Allocatable:
cpu: 8
ephemeral-storage: 47437535154
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 31755676Ki
nvidia.com/gpu: 1
pods: 110

在Kubernetes上运行GPU应用

运行一个gpu的应用deploy测试下:

# cat tensorflow-gpu-deploy.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: tensorflow-gpu
spec:
replicas: 1
template:
metadata:
labels:
name: tensorflow-gpu
spec:
containers:
- name: tensorflow-gpu
image: tensorflow/tensorflow:1.15.0-py3-jupyter
imagePullPolicy: Always
resources:
limits:
nvidia.com/gpu: 1
ports:
- containerPort: 8888
---
apiVersion: v1
kind: Service
metadata:
name: tensorflow-gpu
spec:
ports:
- port: 8888
targetPort: 8888
nodePort: 30888
name: jupyter
selector:
name: tensorflow-gpu
type: NodePort

上面的示例,会创建一个名为tensorflow-gpu的deployment以及一个名为tensorflow-gpu的service,这个service通过nodeport对外暴露8888端口。监听在8888端口的是一个jupyter在线python编辑器,通过它可以直接运行一些gpu计算任务。

我们可以写一个简单的测试任务如下:

from tensorflow.python.client import device_lib

def get_available_devices():
local_device_protos = device_lib.list_local_devices()
return [x.name for x in local_device_protos] print(get_available_devices())

执行之后,输出如下:

['/device:CPU:0', '/device:XLA_CPU:0', '/device:XLA_GPU:0', '/device:GPU:0']

此时,还可通过查看节点上的gpu运行状态看到gpu是否被正常调用:

# nvidia-smi
Tue Nov 5 19:29:20 2019
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.50 Driver Version: 430.50 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla P4 Off | 00000000:00:08.0 Off | 0 |
| N/A 44C P0 25W / 75W | 7403MiB / 7611MiB | 1% Default |
+-------------------------------+----------------------+----------------------+ +-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 173877 C tensorflow_server 105MiB |
+-----------------------------------------------------------------------------+

至此,成功利用kubernetes管理到gpu应用,并实现gpu的资源调度。

附录

如果nouveau驱动未被禁用,可通过如下方式禁用:

在/lib/modprobe.d/dist-blacklist.conf中,注释如下行:

#blacklist nvidiafb

再添加如下配置:

blacklist nouveau
options nouveau modeset=0

重建initramfs image

mv /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r)-nouveau.img
dracut /boot/initramfs-$(uname -r).img $(uname -r)

重启系统

reboot

Kubernetes管理GPU应用的更多相关文章

  1. 这么高颜值的Kubernetes管理工具Lens,难道还不能C位出道吗

    1 前言 欢迎访问南瓜慢说 www.pkslow.com获取更多精彩文章! Docker & Kubernetes相关文章:容器技术 一直使用官方的Kubernetes Dashboard来管 ...

  2. kubernetes管理之使用yq工具截取属性

    系列目录 前面我们讲解过使用go-template或者jsonpath格式(kubectl get 资源 --output go-tempalte(或jsonpath))来截取属性的值,并且我们比较了 ...

  3. kubernetes管理存储

    一.Kubernetes 如何管理存储资源: 理解volume 首先我们学习 Volume,以及 Kubernetes 如何通过 Volume 为集群中的容器提供存储:然后我们会实践几种常用的 Vol ...

  4. kubernetes管理机密信息

    一.启动应用安全信息的保护: Secret介绍: 应用启动过程中可能需要一些敏感信息,比如访问数据库的用户名密码或者秘钥.将这些信息直接保存在容器镜像中显然不妥,Kubernetes 提供的解决方案是 ...

  5. crictl 命令 - Kubernetes 管理命令详解

    描述:crictl 是 CRI 兼容的容器运行时命令行对接客户端, 你可以使用它来检查和调试 Kubernetes 节点上的容器运行时和应用程序.由于该命令是为k8s通过CRI使用containerd ...

  6. Cockpit 容器&&kubernetes 管理可视化工具

    安装 在k8s 的master 上 yum install -y cockpit cockpit-ws cockpit-kubernetes cockpit-bridge cockpit-dashbo ...

  7. 在ubuntu上部署Kubernetes管理docker集群示例, vxlan,gre

    http://www.chenshake.com/openstack-folsom-guide-for-ubuntu-12-04/ http://www.cnblogs.com/sammyliu/p/ ...

  8. 使用kubernetes管理包的常用命令

    常用命令是: ## 获取指定命名空间(rubikt)下所有的部署的服务 kubectl.exe get deployments --namespace rubikt ## 获取制定命名空间(rubik ...

  9. 从零开始入门 K8s | GPU 管理和 Device Plugin 工作机制

    作者 | 车漾  阿里巴巴高级技术专家 本文整理自<CNCF x Alibaba 云原生技术公开课>第 20 讲. 关注"阿里巴巴云原生"公众号,回复关键词" ...

随机推荐

  1. 如何使用Charles让手机访问PC自定义域名?

    需求:移动端访问PC上的自定义域名,如在Nginx上配置的域名 ​ 如vv.zzcloud.com这个域名在pc上是通过host映射的方式访问,现在需要在手机上访问到这个域名. 工具:Charles代 ...

  2. 前端开发HTML5——基础标签

    什么是HTML? HTML是HyperText Markup Language(超文本标记语言)的简写,他不是一种编程语言,而是一种标记语言,用于告诉浏览器如何构造你的页面.“超文本”就是指页面可以包 ...

  3. Git上传到码云及其常见问题详解

    1.git init 初始化 2.git  remote origin add https://gitee.com/su_yong_qing/SyqSystem.git 这里注意把链接替换为自己的仓库 ...

  4. Linux 和 Windows多线程函数对应表

    Linux Pthread API Windows SDK 库对应 API 创建 pthread_create CreateThread 退出 pthread_exit ThreadExit 等待 p ...

  5. ios--NavigationViewController跳转、返回传值

      使用NavigationViewController进行页面跳转时,应该使用pushViewController方法来跳转至下一页面,这样的话,下一页面同样在NavigationViewContr ...

  6. Google Analytics 学习笔记一 —— GA简介

    GA的原理 网页页面添加GA跟踪代码,以"一像素"传递信息给服务器 hit(交互) --> sessions(会话) --> user(用户) 竞品对比 Firebas ...

  7. js 过滤字符 和检测 特殊字符【转】

    // var str1 = str.replace(/\[\\'\\"\\\\\\/\\b\\f\\n\\r\\t\]/g, '');// 去掉转义字符 // var str2= str.r ...

  8. Linux CentOS 防止SSH暴力破解

    一. 问题的发现 昨晚苦逼加班完后,今早上班继续干活时,SSH连接服务器发现异常的提示,仔细看了一下吓一小跳,昨晚9点钟到现在,一夜之间被人尝试连接200+,慌~~~ 1. 速度查一下log [roo ...

  9. VUE 直接通过JS 修改html对象的值导致没有更新到数据中去

    业务场景 我们在使用vue 编写 代码时,我们有一个 多行文本框控件,希望在页面点击一个按钮 在 文本框焦点位置插入一个 {pk}的数据. 发现插入 这个数据后,这个数据并没有同步到 数据中,但是直接 ...

  10. [Go] golang设置运行的cpu数

    package main import( "fmt" "runtime" ) func main() { cpuNum:=runtime.NumCPU() fm ...