zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    【数据结构】线性表&&顺序表详解和代码实例
    【智能算法】超详细的遗传算法(Genetic Algorithm)解析和TSP求解代码详解
    【智能算法】用模拟退火(SA, Simulated Annealing)算法解决旅行商问题 (TSP, Traveling Salesman Problem)
    【智能算法】迭代局部搜索(Iterated Local Search, ILS)详解
    10. js时间格式转换
    2. 解决svn working copy locked问题
    1. easyui tree 初始化的两种方式
    10. js截取最后一个斜杠后面的字符串
    2. apache整合tomcat部署集群
    1. apache如何启动
  • 原文地址:https://www.cnblogs.com/breezey/p/11801122.html
Copyright © 2011-2022 走看看