日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Nvidia GPU如何在Kubernetes 里工作

發(fā)布時間:2024/8/23 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Nvidia GPU如何在Kubernetes 里工作 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Nvidia GPU如何在Kubernetes 里工作

本文介紹Nvidia GPU設(shè)備如何在Kubernetes中管理調(diào)度。 整個工作流程分為以下兩個方面:

  • 如何在容器中使用GPU
  • Kubernetes 如何調(diào)度GPU

如何在容器中使用GPU

想要在容器中的應(yīng)用可以操作GPU, 需要實兩個目標(biāo)

  • 容器中可以查看GPU設(shè)備
  • 容器中運(yùn)行的應(yīng)用,可以通過Nvidia驅(qū)動操作GPU顯卡
  • 詳細(xì)介紹可見:?https://devblogs.nvidia.com/gpu-containers-runtime/

    Nvidia-docker

    GitHub:?https://github.com/NVIDIA/nvidia-docker
    Nvidia提供Nvidia-docker項目,它是通過修改Docker的Runtime為nvidia runtime工作,當(dāng)我們執(zhí)行?nvidia-docker create?或者?nvidia-docker run?? ?時,它會默認(rèn)加上?--runtime=nvidia?參數(shù)。將runtime指定為nvidia。
    當(dāng)然,為了方便使用,可以直接修改Docker daemon 的啟動參數(shù),修改默認(rèn)的 Runtime為?nvidia-container-runtime?

    cat /etc/docker/daemon.json {"default-runtime": "nvidia","runtimes": {"nvidia": {"path": "/usr/bin/nvidia-container-runtime","runtimeArgs": []}} }

    gpu-containers-runtime

    GitHub:??https://github.com/NVIDIA/nvidia-container-runtime
    gpu-containers-runtime? 是一個NVIDIA維護(hù)的容器 Runtime,它在runc的基礎(chǔ)上,維護(hù)了一份?Patch, 我們可以看到這個patch的內(nèi)容非常簡單, 唯一做的一件事情就是在容器啟動前,注入一個?prestart? 的hook?到容器的Spec中(hook的定義可以查看?OCI規(guī)范?)。這個hook 的執(zhí)行時機(jī)是在容器啟動后(Namespace已創(chuàng)建完成),容器自定義命令(Entrypoint)啟動前。nvidia-containers-runtime?定義的 prestart 的命令很簡單,只有一句??nvidia-container-runtime-hook prestart??

    gpu-containers-runtime-hook

    GitHub:?https://github.com/NVIDIA/nvidia-container-runtime/tree/master/hook/nvidia-container-runtime-hook?
    gpu-containers-runtime-hook? 是一個簡單的二進(jìn)制包,定義在Nvidia container runtime的hook中執(zhí)行。 目的是將當(dāng)前容器中的信息收集并處理,轉(zhuǎn)換為參數(shù)調(diào)用?nvidia-container-cli? 。
    主要處理以下參數(shù):

    • 根據(jù)環(huán)境變量?NVIDIA_VISIBLE_DEVICES?判斷是否會分配GPU設(shè)備,以及掛載的設(shè)備ID。如果是未指定或者是?void?,則認(rèn)為是非GPU容器,不做任何處理。? ?否則調(diào)用?nvidia-container-cli?, GPU設(shè)備作為?--devices? 參數(shù)傳入
    • ?環(huán)境環(huán)境變量?NVIDIA_DRIVER_CAPABILITIES?判斷容器需要被映射的 Nvidia 驅(qū)動庫。
    • 環(huán)境變量?NVIDIA_REQUIRE_*? 判斷GPU的約束條件。 例如?cuda>=9.0?等。 作為?--require=?參數(shù)傳入
    • 傳入容器進(jìn)程的Pid

    gpu-containers-runtime-hook? 做的事情,就是將必要的信息整理為參數(shù),傳給?nvidia-container-cli configure?并執(zhí)行。

    nvidia-container-cli

    nvidia-container-cli 是一個命令行工具,用于配置Linux容器對GPU 硬件的使用。支持

    • list:? 打印 nvidia 驅(qū)動庫及路徑
    • info:? 打印所有Nvidia GPU設(shè)備
    • configure: 進(jìn)入給定進(jìn)程的命名空間,執(zhí)行必要操作保證容器內(nèi)可以使用被指定的GPU以及對應(yīng)能力(指定 Nvidia 驅(qū)動庫)。 configure是我們使用到的主要命令,它將Nvidia 驅(qū)動庫的so文件 和 GPU設(shè)備信息, 通過文件掛載的方式映射到容器中。

    代碼如下:?https://github.com/NVIDIA/libnvidia-container/blob/master/src/cli/configure.c#L272

    /* Mount the driver and visible devices. */if (perm_set_capabilities(&err, CAP_EFFECTIVE, ecaps[NVC_MOUNT], ecaps_size(NVC_MOUNT)) < 0) {warnx("permission error: %s", err.msg);goto fail;}if (nvc_driver_mount(nvc, cnt, drv) < 0) {warnx("mount error: %s", nvc_error(nvc));goto fail;}for (size_t i = 0; i < dev->ngpus; ++i) {if (gpus[i] != NULL && nvc_device_mount(nvc, cnt, gpus[i]) < 0) {warnx("mount error: %s", nvc_error(nvc));goto fail;}}

    如果對其他模塊感興趣,可以在?https://github.com/NVIDIA/libnvidia-container? 閱讀代碼。

    以上就是一個nvidia-docker的容器啟動的所有步驟。

    當(dāng)我們安裝了nvidia-docker, 我們可以通過以下方式啟動容器

    docker run --rm -it -e NVIDIA_VISIBLE_DEVICES=all ubuntu:18.04

    在容器中執(zhí)行?mount? 命令,可以看到名為?libnvidia-xxx.so?和?/proc/driver/nvidia/gpus/xxx? 映射到容器中。 以及?nvidia-smi?和?nvidia-debugdump?等nvidia工具。

    # mount ## .... /dev/vda1 on /usr/bin/nvidia-smi type ext4 (ro,nosuid,nodev,relatime,data=ordered) /dev/vda1 on /usr/bin/nvidia-debugdump type ext4 (ro,nosuid,nodev,relatime,data=ordered) /dev/vda1 on /usr/bin/nvidia-persistenced type ext4 (ro,nosuid,nodev,relatime,data=ordered) /dev/vda1 on /usr/bin/nvidia-cuda-mps-control type ext4 (ro,nosuid,nodev,relatime,data=ordered) /dev/vda1 on /usr/bin/nvidia-cuda-mps-server type ext4 (ro,nosuid,nodev,relatime,data=ordered) /dev/vda1 on /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered) /dev/vda1 on /usr/lib/x86_64-linux-gnu/libnvidia-cfg.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered) /dev/vda1 on /usr/lib/x86_64-linux-gnu/libcuda.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered) /dev/vda1 on /usr/lib/x86_64-linux-gnu/libnvidia-opencl.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered) /dev/vda1 on /usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered) /dev/vda1 on /usr/lib/x86_64-linux-gnu/libnvidia-fatbinaryloader.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered) /dev/vda1 on /usr/lib/x86_64-linux-gnu/libnvidia-compiler.so.396.37 type ext4 (ro,nosuid,nodev,relatime,data=ordered) devtmpfs on /dev/nvidiactl type devtmpfs (ro,nosuid,noexec,relatime,size=247574324k,nr_inodes=61893581,mode=755) devtmpfs on /dev/nvidia-uvm type devtmpfs (ro,nosuid,noexec,relatime,size=247574324k,nr_inodes=61893581,mode=755) devtmpfs on /dev/nvidia-uvm-tools type devtmpfs (ro,nosuid,noexec,relatime,size=247574324k,nr_inodes=61893581,mode=755) devtmpfs on /dev/nvidia4 type devtmpfs (ro,nosuid,noexec,relatime,size=247574324k,nr_inodes=61893581,mode=755) proc on /proc/driver/nvidia/gpus/0000:00:0e.0 type proc (ro,nosuid,nodev,noexec,relatime)

    我們可以執(zhí)行nvidia-smi查看容器中被映射的GPU卡

    Kubernetes 如何調(diào)度GPU

    之前我們介紹了如何在容器中使用Nvidia GPU卡。 那么當(dāng)一個集群中有成百上千個節(jié)點(diǎn)以及GPU卡,我們的問題變成了如何管理和調(diào)度這些GPU。

    Device plugin

    Kubernetes 提供了Device Plugin 的機(jī)制,用于異構(gòu)設(shè)備的管理場景。原理是會為每個特殊節(jié)點(diǎn)上啟動一個針對某個設(shè)備的DevicePlugin pod, 這個pod需要啟動grpc服務(wù), 給kubelet提供一系列接口。

    type DevicePluginClient interface {// GetDevicePluginOptions returns options to be communicated with Device// ManagerGetDevicePluginOptions(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*DevicePluginOptions, error)// ListAndWatch returns a stream of List of Devices// Whenever a Device state change or a Device disapears, ListAndWatch// returns the new listListAndWatch(ctx context.Context, in *Empty, opts ...grpc.CallOption) (DevicePlugin_ListAndWatchClient, error)// Allocate is called during container creation so that the Device// Plugin can run device specific operations and instruct Kubelet// of the steps to make the Device available in the containerAllocate(ctx context.Context, in *AllocateRequest, opts ...grpc.CallOption) (*AllocateResponse, error)// PreStartContainer is called, if indicated by Device Plugin during registeration phase,// before each container start. Device plugin can run device specific operations// such as reseting the device before making devices available to the containerPreStartContainer(ctx context.Context, in *PreStartContainerRequest, opts ...grpc.CallOption) (*PreStartContainerResponse, error) }

    DevicePlugin 注冊一個 socket 文件到?/var/lib/kubelet/device-plugins/?目錄下,kubelet 通過這個目錄下的socket文件向?qū)?yīng)的 Device plugin 發(fā)送grpc請求。
    本文不過多介紹Device Plugin 的設(shè)計, 感興趣可以閱讀這篇文章:?https://yq.aliyun.com/articles/498185

    Nvidia plugin

    Github:?https://github.com/NVIDIA/k8s-device-plugin
    為了能夠在Kubernetes中管理和調(diào)度GPU, Nvidia提供了Nvidia GPU的Device Plugin。 主要功能如下

    • 支持ListAndWatch 接口,上報節(jié)點(diǎn)上的GPU數(shù)量
    • 支持Allocate接口, 支持分配GPU的行為。?

    Allocate 接口只做了一件事情,就是給容器加上?NVIDIA_VISIBLE_DEVICES? 環(huán)境變量。?https://github.com/NVIDIA/k8s-device-plugin/blob/v1.11/server.go#L153

    // Allocate which return list of devices. func (m *NvidiaDevicePlugin) Allocate(ctx context.Context, reqs *pluginapi.AllocateRequest) (*pluginapi.AllocateResponse, error) {devs := m.devsresponses := pluginapi.AllocateResponse{}for _, req := range reqs.ContainerRequests {response := pluginapi.ContainerAllocateResponse{Envs: map[string]string{"NVIDIA_VISIBLE_DEVICES": strings.Join(req.DevicesIDs, ","),},}for _, id := range req.DevicesIDs {if !deviceExists(devs, id) {return nil, fmt.Errorf("invalid allocation request: unknown device: %s", id)}}responses.ContainerResponses = append(responses.ContainerResponses, &response)}return &responses, nil }

    前面我們提到, Nvidia的?gpu-container-runtime? 根據(jù)容器的?NVIDIA_VISIBLE_DEVICES?環(huán)境變量,會決定這個容器是否為GPU容器,并且可以使用哪些GPU設(shè)備。 而Nvidia GPU device plugin做的事情,就是根據(jù)kubelet 請求中的GPU DeviceId, 轉(zhuǎn)換為?NVIDIA_VISIBLE_DEVICES?環(huán)境變量返回給kubelet, kubelet收到返回內(nèi)容后,會自動將返回的環(huán)境變量注入到容器中。當(dāng)容器中包含環(huán)境變量,啟動時?gpu-container-runtime? 會根據(jù)?NVIDIA_VISIBLE_DEVICES?里聲明的設(shè)備信息,將設(shè)備映射到容器中,并將對應(yīng)的Nvidia Driver Lib 也映射到容器中。

    總體流程

    整個Kubernetes調(diào)度GPU的過程如下:

    • GPU Device plugin 部署到GPU節(jié)點(diǎn)上,通過?ListAndWatch? 接口,上報注冊節(jié)點(diǎn)的GPU信息和對應(yīng)的DeviceID。?
    • 當(dāng)有聲明?nvidia.com/gpu? 的GPU Pod創(chuàng)建出現(xiàn),調(diào)度器會綜合考慮GPU設(shè)備的空閑情況,將Pod調(diào)度到有充足GPU設(shè)備的節(jié)點(diǎn)上。
    • 節(jié)點(diǎn)上的kubelet 啟動Pod時,根據(jù)request中的聲明調(diào)用各個Device plugin 的 allocate接口, 由于容器聲明了GPU。 kubelet 根據(jù)之前?ListAndWatch?接口收到的Device信息,選取合適的設(shè)備,DeviceID 作為參數(shù),調(diào)用GPU DevicePlugin的?Allocate?接口
    • GPU DevicePlugin ,接收到調(diào)用,將DeviceID 轉(zhuǎn)換為?NVIDIA_VISIBLE_DEVICES?環(huán)境變量,返回kubelet
    • kubelet將環(huán)境變量注入到Pod, 啟動容器
    • 容器啟動時,?gpu-container-runtime?調(diào)用?gpu-containers-runtime-hook?
    • gpu-containers-runtime-hook? 根據(jù)容器的?NVIDIA_VISIBLE_DEVICES?環(huán)境變量,轉(zhuǎn)換為?--devices?參數(shù),調(diào)用?nvidia-container-cli prestart??
    • nvidia-container-cli?根據(jù)?--devices?,將GPU設(shè)備映射到容器中。 并且將宿主機(jī)的Nvidia Driver Lib 的so文件也映射到容器中。 此時容器可以通過這些so文件,調(diào)用宿主機(jī)的Nvidia Driver。


    原文鏈接
    本文為云棲社區(qū)原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載。

    總結(jié)

    以上是生活随笔為你收集整理的Nvidia GPU如何在Kubernetes 里工作的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。