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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM