雄阔海 發表於 2019-11-5 19:50:00

Kubernetes管理GPU应用

<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>简介</li><li>GPU驱动</li><li>Nvidia-docker</li><li>Nvidia-device-plugin</li><li>在Kubernetes上运行GPU应用</li><li>附录</li></ul></div><p></p>
<h1 id="简介">简介</h1>
<p>伴随着人工智能技术的发展,机器学习的应用场景越来越广泛</p>
<p>深度学习的实现,需要多种技术进行支撑,比如服务器、GPU、集群、集群管理调度软件、深度学习框架、深度学习的具体应用等</p>
<p>随着Kubernetes的兴起,越来越多的训练任务也都直接运行在Kubernetes之上,这些基于GPU的应用也为Kubernetes的应用管理带了一定的挑战</p>
<p>我也一直在致力于推动公司业务上容器,本篇文档我们就来聊一聊在Kubernetes上如何管理GPU应用。</p>
<h1 id="gpu驱动">GPU驱动</h1>
<p>要管理GPU应用,首先要解决的自然就是GPU的驱动。</p>
<p>首先我们得有一台带有gpu的服务器。可通过如下指令查询gpu型号(我这里以nvidia为例):</p>
<pre><code># lspci|grep -i nvidia
00:08.0 3D controller: NVIDIA Corporation GP104GL (rev a1)
</code></pre>
<p>上面显示这台机器有一块nvidia的显卡,型号为Tesla P4,可以通过下面的指令查看更详细的信息:</p>
<pre><code># lspci-v -s 00:08.0
00:08.0 3D controller: NVIDIA Corporation GP104GL (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)
      Memory at e0000000 (64-bit, prefetchable)
      Memory at f2000000 (64-bit, prefetchable)
      Capabilities: Power Management version 3
      Capabilities: MSI: Enable+ Count=1/1 Maskable- 64bit+
      Capabilities: Express Endpoint, MSI 00
      Kernel driver in use: nvidia
      Kernel modules: nouveau, nvidia_drm, nvidia
</code></pre>
<blockquote>
<p>注:如果发现没有lspci命令,可通过yum install -y pciutils安装</p>
</blockquote>
<p>有了显卡,才考虑驱动的事儿。需要先检查下系统有没有开启nouveau驱动:</p>
<pre><code>lsmod |grep nouveau
</code></pre>
<p>如果命令输出为空,则代表没有开启,可直接安装nvidia驱动。如果有输出,则需要先禁用nouveau驱动,操作方法见附录</p>
<p>安装驱动有两种方式,一种是直接yum安装,一种是从nvidia官方下载指定的驱动包,手动安装。手动安装的方法可参考:https://www.cnblogs.com/breezey/p/10599705.html</p>
<p>我这里直接使用yum安装:</p>
<pre><code>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
</code></pre>
<p>安装完成后,需要重启下系统,然后执行如下指令验证:</p>
<pre><code># nvidia-smi
Tue Nov5 19:01:25 2019      
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.50       Driver Version: 430.50       CUDA Version: 10.1   |
|-------------------------------+----------------------+----------------------+
| GPUName      Persistence-M| Bus-Id      Disp.A | Volatile Uncorr. ECC |
| FanTempPerfPwr:Usage/Cap|         Memory-Usage | GPU-UtilCompute M. |
|===============================+======================+======================|
|   0Tesla 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                                                 |
+-----------------------------------------------------------------------------+
</code></pre>
<p>看到如下信息代表驱动安装完成</p>
<h1 id="nvidia-docker">Nvidia-docker</h1>
<p>要在docker中运行gpu应用,自然首先得装个docker。但是光装个docker还不够,因为GPU属于特定的厂商产品,需要特定的driver,Docker本身并不支持GPU。</p>
<p>以前如果要在Docker中使用GPU,就需要在container中安装主机上使用GPU的driver,然后把主机上的GPU设备(例如:/dev/nvidia0)映射到container中。所以这样的Docker image并不具备可移植性。为此呢,Nvidia官方开源了一个称之为nvidia-docker的项目。<br>
Nvidia-docker让Docker image不需要知道底层GPU的相关信息,而是通过启动container时mount设备和驱动文件来实现的。</p>
<p>nvidia-docker现在有两个版本:</p>
<ul>
<li>在nvidia-docker1中,invidia-docker作为一个独立的服务存在,用于劫持docker进程</li>
<li>在nvidia-docker2中,为了降低部署及管理成本,invidia-docker2只是作为docker的一个runtime存在</li>
</ul>
<p>接下来,我们来看一看安装。</p>
<ol>
<li>安装docker</li>
</ol>
<pre><code>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
</code></pre>
<ol start="2">
<li>安装nvidia-docker</li>
</ol>
<pre><code>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
</code></pre>
<ol start="3">
<li>测试:</li>
</ol>
<pre><code># # docker run --runtime=nvidia --rm nvidia/cuda:10.0-cudnn7-runtime-centos7 nvidia-smi
Tue Nov5 19:01:25 2019      
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.50       Driver Version: 430.50       CUDA Version: 10.1   |
|-------------------------------+----------------------+----------------------+
| GPUName      Persistence-M| Bus-Id      Disp.A | Volatile Uncorr. ECC |
| FanTempPerfPwr:Usage/Cap|         Memory-Usage | GPU-UtilCompute M. |
|===============================+======================+======================|
|   0Tesla 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                                                 |
+-----------------------------------------------------------------------------+
</code></pre>
<blockquote>
<p>通过--runtime指定nvidia的runtime来运行</p>
</blockquote>
<p>通过这个测试也就意味着,我们的节点以及docker已经具备了运行gpu应用的能力</p>
<ol start="4">
<li>修改docker配置文件</li>
</ol>
<p>接下来,修改docker配置文件,以让其将nvidia的runtime设置为默认的runtime,示例如下:</p>
<pre><code># 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"]
}
</code></pre>
<ol start="5">
<li>重启docker</li>
</ol>
<pre><code>systemctl restart docker
</code></pre>
<h1 id="nvidia-device-plugin">Nvidia-device-plugin</h1>
<p>要让我们的kubernetes能真正管理gpu资源,在kubernetes集群上还需要安装一个称之为nvidia-device-plugin的插件。</p>
<p>Kubernetes从1.8开始支持了Device Plugin。实际上就是提供一系列接口,用于支持GPU、FPGA、高性能NIC、InfiniBand等各种设备。<br>
厂商只需要根据Device Plugin的接口实现一个特定设备的插件,Kubernetes即可使用该设备而无需修改kubernetes代码。<br>
而nvidia-device-plugin就是nvidia针对其自己的GPU设备提供的接口实现。</p>
<p>这个插件是以daemonset的方式来运行的:</p>
<pre><code>wgethttps://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.12/nvidia-device-plugin.yml

# 执行部署
kubectl create -f nvidia-device-plugin.yml
</code></pre>
<blockquote>
<p>注1:下载地址中的v1.12与我们所使用的kubernetes版本所对应,目前支持的最新版本也就是v1.12,实测1.16版本的kubernetes也可以用</p>
</blockquote>
<p>安装完成之后,我们可以通过如下指令看到kubernetes已正常识别node的gpu资源:</p>
<pre><code># 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
</code></pre>
<h1 id="在kubernetes上运行gpu应用">在Kubernetes上运行GPU应用</h1>
<p>运行一个gpu的应用deploy测试下:</p>
<pre><code># 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
</code></pre>
<p>上面的示例,会创建一个名为tensorflow-gpu的deployment以及一个名为tensorflow-gpu的service,这个service通过nodeport对外暴露8888端口。监听在8888端口的是一个jupyter在线python编辑器,通过它可以直接运行一些gpu计算任务。</p>
<p>我们可以写一个简单的测试任务如下:</p>
<pre><code>from tensorflow.python.client import device_lib

def get_available_devices():
    local_device_protos = device_lib.list_local_devices()
    return

print(get_available_devices())
</code></pre>
<p>执行之后,输出如下:</p>
<pre><code>['/device:CPU:0', '/device:XLA_CPU:0', '/device:XLA_GPU:0', '/device:GPU:0']
</code></pre>
<p>此时,还可通过查看节点上的gpu运行状态看到gpu是否被正常调用:</p>
<pre><code># nvidia-smi
Tue Nov5 19:29:20 2019      
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.50       Driver Version: 430.50       CUDA Version: 10.1   |
|-------------------------------+----------------------+----------------------+
| GPUName      Persistence-M| Bus-Id      Disp.A | Volatile Uncorr. ECC |
| FanTempPerfPwr:Usage/Cap|         Memory-Usage | GPU-UtilCompute M. |
|===============================+======================+======================|
|   0Tesla 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      |
+-----------------------------------------------------------------------------+
</code></pre>
<p>至此,成功利用kubernetes管理到gpu应用,并实现gpu的资源调度。</p>
<h1 id="附录">附录</h1>
<p>如果nouveau驱动未被禁用,可通过如下方式禁用:</p>
<p>在/lib/modprobe.d/dist-blacklist.conf中,注释如下行:</p>
<pre><code class="language-sh">#blacklist nvidiafb
</code></pre>
<p>再添加如下配置:</p>
<pre><code>blacklist nouveau
options nouveau modeset=0
</code></pre>
<p>重建initramfs image</p>
<pre><code>mv /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r)-nouveau.img
dracut /boot/initramfs-$(uname -r).img $(uname -r)
</code></pre>
<p>重启系统</p>
<pre><code>reboot
</code></pre><br><br>
来源:https://www.cnblogs.com/breezey/p/11801122.html
頁: [1]
查看完整版本: Kubernetes管理GPU应用