Nvidia GPU如何在Kubernetes 里工作

简介: # Nvidia GPU如何在Kubernetes 里工作 本文介绍Nvidia GPU设备如何在Kubernetes中管理调度。 整个工作流程分为以下两个方面: * 如何在容器中使用GPU * Kubernetes 如何调度GPU ### 如何在容器中使用GPU 想要在容器中的应用可以操作GPU, 需要实两个目标 1.

Nvidia GPU如何在Kubernetes 里工作

本文介绍Nvidia GPU设备如何在Kubernetes中管理调度。 整个工作流程分为以下两个方面:

  • 如何在容器中使用GPU
  • Kubernetes 如何调度GPU

如何在容器中使用GPU

想要在容器中的应用可以操作GPU, 需要实两个目标

  1. 容器中可以查看GPU设备
  2. 容器中运行的应用,可以通过Nvidia驱动操作GPU显卡

详细介绍可见: https://devblogs.nvidia.com/gpu-containers-runtime/

Nvidia-docker

GitHub: https://github.com/NVIDIA/nvidia-docker
Nvidia提供Nvidia-docker项目,它是通过修改Docker的Runtime为nvidia runtime工作,当我们执行 nvidia-docker create 或者 nvidia-docker run    时,它会默认加上 --runtime=nvidia 参数。将runtime指定为nvidia。
当然,为了方便使用,可以直接修改Docker daemon 的启动参数,修改默认的 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维护的容器 Runtime,它在runc的基础上,维护了一份 Patch, 我们可以看到这个patch的内容非常简单, 唯一做的一件事情就是在容器启动前,注入一个 prestart  的hook 到容器的Spec中(hook的定义可以查看 OCI规范 )。这个hook 的执行时机是在容器启动后(Namespace已创建完成),容器自定义命令(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  是一个简单的二进制包,定义在Nvidia container runtime的hook中执行。 目的是将当前容器中的信息收集并处理,转换为参数调用 nvidia-container-cli  。
主要处理以下参数:

  • 根据环境变量 NVIDIA_VISIBLE_DEVICES 判断是否会分配GPU设备,以及挂载的设备ID。如果是未指定或者是 void ,则认为是非GPU容器,不做任何处理。   否则调用 nvidia-container-cli , GPU设备作为 --devices  参数传入
  •  环境环境变量 NVIDIA_DRIVER_CAPABILITIES 判断容器需要被映射的 Nvidia 驱动库。
  • 环境变量 NVIDIA_REQUIRE_*  判断GPU的约束条件。 例如 cuda>=9.0 等。 作为 --require= 参数传入
  • 传入容器进程的Pid

gpu-containers-runtime-hook  做的事情,就是将必要的信息整理为参数,传给 nvidia-container-cli configure 并执行。

nvidia-container-cli

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

  • list:  打印 nvidia 驱动库及路径
  • info:  打印所有Nvidia GPU设备
  • configure: 进入给定进程的命名空间,执行必要操作保证容器内可以使用被指定的GPU以及对应能力(指定 Nvidia 驱动库)。 configure是我们使用到的主要命令,它将Nvidia 驱动库的so文件 和 GPU设备信息, 通过文件挂载的方式映射到容器中。

代码如下: 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的容器启动的所有步骤。

1

当我们安装了nvidia-docker, 我们可以通过以下方式启动容器

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

在容器中执行 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)

我们可以执行nvidia-smi查看容器中被映射的GPU卡
2

Kubernetes 如何调度GPU

之前我们介绍了如何在容器中使用Nvidia GPU卡。 那么当一个集群中有成百上千个节点以及GPU卡,我们的问题变成了如何管理和调度这些GPU。

Device plugin

Kubernetes 提供了Device Plugin 的机制,用于异构设备的管理场景。原理是会为每个特殊节点上启动一个针对某个设备的DevicePlugin pod, 这个pod需要启动grpc服务, 给kubelet提供一系列接口。

type DevicePluginClient interface {
    // GetDevicePluginOptions returns options to be communicated with Device
    // Manager
    GetDevicePluginOptions(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 list
    ListAndWatch(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 container
    Allocate(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 container
    PreStartContainer(ctx context.Context, in *PreStartContainerRequest, opts ...grpc.CallOption) (*PreStartContainerResponse, error)
}

DevicePlugin 注册一个 socket 文件到 /var/lib/kubelet/device-plugins/ 目录下,kubelet 通过这个目录下的socket文件向对应的 Device plugin 发送grpc请求。
本文不过多介绍Device Plugin 的设计, 感兴趣可以阅读这篇文章: https://yq.aliyun.com/articles/498185

Nvidia plugin

Github: https://github.com/NVIDIA/k8s-device-plugin
为了能够在Kubernetes中管理和调度GPU, Nvidia提供了Nvidia GPU的Device Plugin。 主要功能如下

  • 支持ListAndWatch 接口,上报节点上的GPU数量
  • 支持Allocate接口, 支持分配GPU的行为。 

Allocate 接口只做了一件事情,就是给容器加上 NVIDIA_VISIBLE_DEVICES  环境变量。 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.devs
    responses := 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  根据容器的 NVIDIA_VISIBLE_DEVICES 环境变量,会决定这个容器是否为GPU容器,并且可以使用哪些GPU设备。 而Nvidia GPU device plugin做的事情,就是根据kubelet 请求中的GPU DeviceId, 转换为 NVIDIA_VISIBLE_DEVICES 环境变量返回给kubelet, kubelet收到返回内容后,会自动将返回的环境变量注入到容器中。当容器中包含环境变量,启动时 gpu-container-runtime  会根据 NVIDIA_VISIBLE_DEVICES 里声明的设备信息,将设备映射到容器中,并将对应的Nvidia Driver Lib 也映射到容器中。

总体流程

整个Kubernetes调度GPU的过程如下:

  • GPU Device plugin 部署到GPU节点上,通过 ListAndWatch  接口,上报注册节点的GPU信息和对应的DeviceID。 
  • 当有声明 nvidia.com/gpu  的GPU Pod创建出现,调度器会综合考虑GPU设备的空闲情况,将Pod调度到有充足GPU设备的节点上。
  • 节点上的kubelet 启动Pod时,根据request中的声明调用各个Device plugin 的 allocate接口, 由于容器声明了GPU。 kubelet 根据之前 ListAndWatch 接口收到的Device信息,选取合适的设备,DeviceID 作为参数,调用GPU DevicePlugin的 Allocate 接口
  • GPU DevicePlugin ,接收到调用,将DeviceID 转换为 NVIDIA_VISIBLE_DEVICES 环境变量,返回kubelet
  • kubelet将环境变量注入到Pod, 启动容器
  • 容器启动时, gpu-container-runtime 调用 gpu-containers-runtime-hook 
  • gpu-containers-runtime-hook  根据容器的 NVIDIA_VISIBLE_DEVICES 环境变量,转换为 --devices 参数,调用 nvidia-container-cli prestart  
  • nvidia-container-cli 根据 --devices ,将GPU设备映射到容器中。 并且将宿主机的Nvidia Driver Lib 的so文件也映射到容器中。 此时容器可以通过这些so文件,调用宿主机的Nvidia Driver。
相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
27天前
|
弹性计算 人工智能 Serverless
阿里云ACK One:注册集群云上节点池(CPU/GPU)自动弹性伸缩,助力企业业务高效扩展
在当今数字化时代,企业业务的快速增长对IT基础设施提出了更高要求。然而,传统IDC数据中心却在业务存在扩容慢、缩容难等问题。为此,阿里云推出ACK One注册集群架构,通过云上节点池(CPU/GPU)自动弹性伸缩等特性,为企业带来全新突破。
|
3月前
|
机器学习/深度学习 Kubernetes 调度
Kubernetes与GPU的调度:前世今生
本文详细探讨了Kubernetes与GPU的结合使用,阐述了两者在现代高性能计算环境中的重要性。Kubernetes作为容器编排的佼佼者,简化了分布式系统中应用程序的部署与管理;GPU则凭借其强大的并行计算能力,在加速大规模数据处理和深度学习任务中发挥关键作用。文章深入分析了Kubernetes如何支持GPU资源的检测与分配,并介绍了热门工具如NVIDIA GPU Device Plugin和Kubeflow的应用。
|
6月前
|
机器学习/深度学习 人工智能 弹性计算
阿里云GPU服务器全解析_GPU服务器租用费用_NVIDIA A10、V100、T4、P4、P100 GPU卡
阿里云GPU云服务器提供NVIDIA A10、V100、T4、P4、P100等多种GPU卡,结合高性能CPU,单实例计算性能高达5PFLOPS。支持2400万PPS及160Gbps内网带宽。实例规格多样,如A10卡GN7i(3213.99元/月)、V100-16G卡GN6v(3830.00元/月)等。适用于深度学习、科学计算、图形处理等场景。GPU软件如AIACC-Training、AIACC-Inference助力性能优化。购买方式灵活,客户案例包括深势科技、流利说、小牛翻译。
723 0
|
6月前
|
XML 机器学习/深度学习 监控
性能监控之Telegraf+InfluxDB+Grafana NVIDIA GPU实时监控
【6月更文挑战12天】性能监控之Telegraf+InfluxDB+Grafana NVIDIA GPU实时监控
151 0
|
7月前
|
Kubernetes 调度 异构计算
Kubernetes 调用 GPU解析
Kubernetes (K8s) 支持调用GPU以利用其统一调度和分配集群资源的能力,管理异构计算,如加速部署、提高资源使用率和保证资源独享。通过容器化和设备隔离,K8s确保GPU高效、安全地被应用使用。要调用GPU,需安装NVIDIA GPU驱动、CUDA工具包和Device Plugin,然后在Pod配置中指定GPU需求。安装步骤包括:确保GPU节点、安装GPU驱动和NVIDIA容器运行时、创建GPU资源要求的Pod并部署到集群。
|
7月前
|
Kubernetes 监控 调度
Kubernetes(K8s)与虚拟GPU(vGPU)协同:实现GPU资源的高效管理与利用
本文探讨了如何使用Kubernetes和虚拟GPU(vGPU)实现异构GPU的协同调度。Kubernetes是一个容器编排平台,通过设备插件、资源规格、调度器扩展和节点标签实现GPU资源管理。vGPU技术允许物理GPU资源在多个虚拟机或容器中共享。文章详细介绍了vGPU的部署配置步骤,并提出了GPU资源调度、负载均衡和监控调优的方法。强调虚拟GPU的性能取决于硬件和驱动支持,合理配置能提供高性能计算环境。参考文献包括Kubernetes和NVIDIA官方文档及相关研究论文。
|
7月前
|
弹性计算 并行计算 UED
带你读《弹性计算技术指导及场景应用》——4. 自动安装NVIDIA GPU驱动和CUDA组件
带你读《弹性计算技术指导及场景应用》——4. 自动安装NVIDIA GPU驱动和CUDA组件
151 0
|
4月前
|
机器学习/深度学习 编解码 人工智能
阿里云gpu云服务器租用价格:最新收费标准与活动价格及热门实例解析
随着人工智能、大数据和深度学习等领域的快速发展,GPU服务器的需求日益增长。阿里云的GPU服务器凭借强大的计算能力和灵活的资源配置,成为众多用户的首选。很多用户比较关心gpu云服务器的收费标准与活动价格情况,目前计算型gn6v实例云服务器一周价格为2138.27元/1周起,月付价格为3830.00元/1个月起;计算型gn7i实例云服务器一周价格为1793.30元/1周起,月付价格为3213.99元/1个月起;计算型 gn6i实例云服务器一周价格为942.11元/1周起,月付价格为1694.00元/1个月起。本文为大家整理汇总了gpu云服务器的最新收费标准与活动价格情况,以供参考。
阿里云gpu云服务器租用价格:最新收费标准与活动价格及热门实例解析
|
12天前
|
人工智能 弹性计算 编解码
阿里云GPU云服务器性能、应用场景及收费标准和活动价格参考
GPU云服务器作为阿里云提供的一种高性能计算服务,通过结合GPU与CPU的计算能力,为用户在人工智能、高性能计算等领域提供了强大的支持。其具备覆盖范围广、超强计算能力、网络性能出色等优势,且计费方式灵活多样,能够满足不同用户的需求。目前用户购买阿里云gpu云服务器gn5 规格族(P100-16G)、gn6i 规格族(T4-16G)、gn6v 规格族(V100-16G)有优惠,本文为大家详细介绍阿里云gpu云服务器的相关性能及收费标准与最新活动价格情况,以供参考和选择。
|
17天前
|
机器学习/深度学习 人工智能 弹性计算
什么是阿里云GPU云服务器?GPU服务器优势、使用和租赁费用整理
阿里云GPU云服务器提供强大的GPU算力,适用于深度学习、科学计算、图形可视化和视频处理等多种场景。作为亚太领先的云服务提供商,阿里云的GPU云服务器具备灵活的资源配置、高安全性和易用性,支持多种计费模式,帮助企业高效应对计算密集型任务。