在机器学习,深度学习中,使用GPU加快对模型的训练是不可避免的。由于公司的搜索实验室和人工智能研究院都想使用容器服务平台已容器的方式部署他们的服务,前提就是需要kubernetes对GPU支持。值得高兴的是kubernetes从1.6版本就已经支持了对GPU的支持(只支持单容器单卡),并且kubernetes团队在1.9版本支持了多容器多卡及对GPU监控指标的暴露。

注意: 现在kubernetes只支持Nvidia GPU.

深度学习在部署上面临的一些问题

  • 不同的训练框架(如:caffe, tensorflow…),可能对依赖库版有不同版本的需求。
  • 在训练模型的时候,对底层的运行时有不同的需求(如: CentOS, Ubuntu…)。
  • 不同的学习模型需要不同版本的Nvidia GPU(如: k80, k40m, p4,p40,v100)和驱动。
  • 如何能快速的对服务进行弹性扩缩容。
  • 高效的使用GPU资源。(对于这点,现在容器对GPU的资源浪费还是没有根本性的解决,官方还没有支持多容器同卡的使用,等待官方后期支持)。

针对上面提出的这些问题,我们下面介绍下如何使用容器方式来逐一解决这些问题。

为什么以容器的方式部署GPU服务

  • 基于容器技术,用户可以根据自己的需要选择自己的训练框架(caffe, tensorflow…),底层的运行时(CentOS, Ubuntu)来针对自己的场景制作镜像,并且可以基于Kubernetes的lable机制来选择需要使用的Nvidia GPU型号并对容器进行快速的扩缩容。
  • 基于容器技术,可以对GPU的设备进行隔离。每个容器只能看到它使用的GPU设备。

    如: 在容器的resources(manifest文件)处指定该容器使用的GPU数量, 并创建该容器,进入(exec)到容器中查看使用的GPU卡的数量是2:


gpu
并且在容器中可以看到容器已经对GPU进行了隔离:

gpu
  • 底层的Nvidia Driver对用户不可见,用户只需要关心上层的业务逻辑即可。使用容器的方式,容器服务平台的管理员可以在部署GPU机器的时候,将驱动安装完成,用户端在创建容器的时候,会以卷(volume)的形式将Cuda库挂载到容器里面,供上层的服务使用。如下图是传统方式和容器化方式的一个对比图:

gpu
  • 多维度(Deployment, Pod, Container)的对GPU的资源使用情况进行监控,kubernetes 1.9版本暴露了针对GPU容器的显存和使用率的指标(而不需要直接通过调用NVML库来获取GPU卡的使用情况)。kubernetes暴露出来的metrics如下:

    • container_accelerator_memory_used_bytes
    • container_accelerator_duty_cycle

如何实现GPU容器作为服务

GPU集群部署

  1. 安装 Nvidia Driver
  2. 安装 docker
  3. 安装 nvidia-docker1.0(暂时还没有使用nvidia-docker 2.0)
  4. 验证
  5. 存在的问题,及解决方案

安装 Nvidia Driver

Nvidia Driver驱动在宿主机上的示意图:


gpu

从ELrepo源中安装驱动,添加ELrepo数据源:http://elrepo.org/tiki/tiki-index.php

1
2
sudo rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
sudo rpm -Uvh https://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm

安装显卡检查程序:

1
sudo yum install nvidia-detect

检查显卡型号,并选择对应的驱动:

1
2
3
4
nvidia-detect -v
Probing for supported NVIDIA devices...
[10de:06dd] NVIDIA Corporation GF100GL [Quadro 4000]
This device requires the current 384.98 NVIDIA driver kmod-nvidia

根据nvidia-detest的输出信息,可以知道显卡的型号,以及要使用的驱动程序版本.如384.98

1
yum install kmod-nvidia-384.98-1.el7_4.elrepo.x86_64

重启服务器:

1
reboot

检查nvidia模块是否加载成功:

1
2
3
4
5
6
7
lsmod | grep nvidia
nvidia_drm 44108 0
nvidia_modeset 841676 1 nvidia_drm
drm_kms_helper 163265 2 ast,nvidia_drm
drm 370825 5 ast,ttm,drm_kms_helper,nvidia_drm
nvidia 13117469 1 nvidia_modeset
i2c_core 40756 8 ast,drm,igb,i2c_i801,ipmi_ssif,drm_kms_helper,i2c_algo_bit,nvid

安装docker

nvidia-docker1.0 对于docker的安装。不需要进行调整,但是如果使用的是nvidia-docker 2.0则需要进行相关的调整(会重写docker配置文件/etc/docker/daemon.json)。

1
# yum install docker-ce-18.01 -y

安装 nvidia-docker 1.0

  • 安装环境需求

    The list of prerequisites for running nvidia-docker is described below.
    For information on how to install Docker for your Linux distribution, please refer to the Docker documentation.

    1. GNU/Linux x86_64 with kernel version > 3.10
    2. Docker >= 1.9 (official docker-engine, docker-ce or docker-ee only)
    3. NVIDIA GPU with Architecture > Fermi (2.1)
    4. NVIDIA drivers >= 340.29 with binary nvidia-modprobe

      Your driver version might limit your CUDA capabilities (see CUDA requirements)

  • 安装nvidia-docker1.0

    1. Install the repository for your distribution by following the instructions here.https://nvidia.github.io/nvidia-docker/
    2. Install the nvidia-docker package

      1
      sudo yum install nvidia-docker

      The package installation will automatically setup the nvidia-docker-plugin and depending on your distribution, register it with the init system.

  • 启动 nvidia-docker

    编辑 nvidia-docker.service 文件:

    1
    systemctl edit nvidia-docker.service

    文件内容:

    1
    2
    3
    [Service]
    ExecStart=
    ExecStart=/usr/bin/nvidia-docker-plugin -s $SOCK_DIR -d /usr/local/nvidia-driver
    1
    systemctl start nvidia-docker

启动后,它会创建一个数据卷nvidia_driver_384. 98,且对应着宿主机上会生成1个目录/usr/local/nvidia-driver/nvidia_driver/384.98/.

1
2
3
4
5
docker volume ls
DRIVER VOLUME NAME
local 7ec8fa85b2c9a020b0591a0d397f76b3c521e2f975ea54e78d75711b8114e22f
local 976b4c8ba4136d1049e5fd3d072dc31501cb2c6a1e163d4939ba789d3c2c2c1b
nvidia-docker nvidia_driver_384. 98

如果nvidia-docker nvidia_driver_384. 98数据卷没有,则肯定是启动有问题,可以根据日志排查定位问题,如下面的错误信息:

1
Error: mkdir /usr/local/nvidia-driver/: permission denied

这个时候需要手动创建,创建方式:

1
2
3
mkdir -p /usr/local/nvidia-driver
chown -R nvidia-docker.nvidia-docker /usr/local/nvidia-driver
docker volume create -d nvidia-docker --name nvidia_driver_384.98

5.运行GPU容器检查是否正常

1
nvidia-docker run --rm nvidia/cuda nvidia-smi

能正常输出GPU信息说明安装没有问题。
输出内容如下:


gpu

存在的问题及解决方案

直接将nvidia驱动挂载到容器内部:
类似下图:


gpu

如果向现在这样直接把/usr/local/nvidia-driver/nvidia_driver/384.98/驱动已卷的形式通过kubernetes的manifest的形式挂载到容器中,只能针对384.98这种驱动型号,可能存在不同的GPU机器使用不同型号的驱动,这样做是不可行的,所有可以使用link的方式统一驱动的挂载路径,如下图所示:


gpu

通过这种方式不同型号的驱动,在kubernetes这层是无感知的。

参考:

https://www.openstack.org/assets/presentation-media/OpenStack-Boston-Summit-Presentation.pdf
https://www.openstack.org/videos/boston-2017/container-as-a-service-on-gpu-cloud-our-decision-among-k8s-mesos-docker-swarm-and-openstack-zun
https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(version-1.0))