• Kubernetes管理GPU应用


    简介

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

    深度学习的实现,需要多种技术进行支撑,比如服务器、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
    
  • 相关阅读:
    运用Unity实现依赖注入[结合简单三层实例]
    利用WCF与Android实现图片上传并传参
    如何修改被编译后DLL文件
    ASP.NET基础之HttpHandler学习
    ASP.NET基础之HttpContext学习
    ASP.NET基础之HttpModule学习
    WCF学习笔记之事务编程
    WCF学习笔记之传输安全
    WCF心跳判断服务端及客户端是否掉线并实现重连接
    CLR_Via_C#学习笔记之事件
  • 原文地址:https://www.cnblogs.com/breezey/p/11801122.html
Copyright © 2020-2023  润新知