首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

【博客501】Nvidia docker runtime原理

  • 25-03-07 05:22
  • 3723
  • 6158
blog.csdn.net

Nvidia docker runtime原理

场景:

docker 本身并不原生支持GPU,但使用docker的现有功能可以对GPU的使用进行支持。

docker run \
--device /dev/nvidia0:/dev/nvidia0 \
--device /dev/nvidiactl:/dev/nvidiactl \
--device /dev/nvidia-uvm:/dev/nvidia-uvm \
-v /usr/local/nvidia:/usr/local/nvidia \
-it --privileged nvidia/cuda
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

如上所述,通过 --device 来指定挂载的GPU设备,通过 -v 来将宿主机上的 nvidia gpu 的命令行工具和相关的依赖库挂载到容器。这样,在容器中就可以看到和使用宿主机上的GPU设备了。 这样使用,对于GPU的可用性(哪些GPU是空闲的等)需要人为的判断,效率很低。为了提高Nvidia GPU在 docker 中的易用性, Nvidia 通过对原生docker的封装实现了自己的 nvidia-docker 工具。

nvidia-docker 对于使用GPU资源的docker容器支持的层次关系:

在这里插入图片描述

在这里插入图片描述

Nvidia-docker的原理图以及各个部分的作用解析

在这里插入图片描述

在这里插入图片描述
libnvidia-container:

libnvidia-container提供了一个库和简单的CLI工具,以实现在容器当中支持使用GPU设备的目标。

nvidia-container-toolkit:

nvidia-container-toolkit是一个实现了runC prestart hook接口的脚本,该脚本在runC创建一个容器之后,启动该容器之前调用,其主要作用就是修改与容器相关联的config.json,注入一些在容器中使用NVIDIA GPU设备所需要的一些信息(比如:需要挂载哪些GPU设备到容器当中)。

nvidia-container-runtime:

nvidia-container-runtime主要用于将容器runC spec作为输入,然后将nvidia-container-toolkit脚本作为一个prestart hook注入到runC spec中,将修改后的runC spec交给runC处理。

nvidia-container-runtime 才是真正的核心部分,它在原有的docker容器运行时runc的基础上增加一个prestart hook,用于调用libnvidia-container库。

RunC:

RunC 是一个轻量级的工具,它是用来运行容器的,只用来做这一件事,并且这一件事要做好。我们可以认为它就是个命令行小工具,可以不用通过 docker 引擎,直接运行容器。事实上,runC 是标准化的产物,它根据 OCI 标准来创建和运行容器。而 OCI(Open Container Initiative)组织,旨在围绕容器格式和运行时制定一个开放的工业化标准。
直接使用RunC的命令行即可以完成创建一个容器,并提供了简单的交互能力。

容器创建

正常创建一个容器的流程是这样的:

docker --> dockerd --> containerd–> containerd-shim -->runc --> container-process

docker客户端将创建容器的请求发送给dockerd, 当dockerd收到请求任务之后将请求发送给containerd, containerd经过查看校验启动containerd-shim或者自己来启动容器进程。

创建一个使用GPU的容器

docker–> dockerd --> containerd --> containerd-shim–> nvidia-container-runtime --> nvidia-container-runtime-hook --> libnvidia-container --> runc – > container-process

基本流程和不使用GPU的容器差不多,只是把docker默认的运行时替换成了NVIDIA自家的nvidia-container-runtime。

这样当nvidia-container-runtime创建容器时,先执行nvidia-container-runtime-hook这个hook去检查容器是否需要使用GPU(通过环境变NVIDIA_VISIBLE_DEVICES来判断)。如果需要则调用libnvidia-container来暴露GPU给容器使用。否则走默认的runc逻辑。

NVIDIA Docker 整体工作架构

1、硬件,服务器上安装了英伟达 GPU

2、宿主机,安装了操作系统和 Cuda Driver,以及 Docker 引擎

3、容器,包含容器 OS 用户空间,Cuda Toolkit,以及用户应用程序

最重要的是,宿主机上需要安装 cuda driver,容器内需要安装 cuda toolkit。容器内无需安装 cuda driver。

NVIDIA 提供了一些官方镜像,其中已经安装好了 cuda toolkit,但还是需要在宿主机安装 cuda driver。

CUDA 结构图如下:
在这里插入图片描述

提供了 cuda driver api,cuda runtime api 和 cuda liabaries 三层 API

CUDA Driver API:
GPU设备的抽象层,通过提供一系列接口来操作GPU设备,性能最好,但编程难度高,
一般不会使用该方式开发应用程序。

CUDA Runtime API:
对CUDA Driver API进行了一定的封装,调用该类API可简化编程过程,降低开发难度;

CUDA Libraries:
是对CUDA Runtime API更高一层的封装,通常是一些成熟的高效函数库,
开发者也可以自己封装一些函数库便于使用;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

CUDA调用关系:

应用程序可调用CUDA Libraries或者CUDA Runtime API来实现功能,当调用CUDA Libraries时,CUDA Libraries会调用相应的CUDA Runtime API,CUDA Runtime API再调用CUDA Driver API,CUDA Driver API再操作GPU设备。

如何实现CUDA容器化:

目标:CUDA容器化的目标就是要能让应用程序可以在容器内调用CUDA API来操作GPU。

因此需要实现:

1、在容器内应用程序可调用CUDA Runtime API和CUDA Libraries

2、在容器内能使用CUDA Driver相关库。因为CUDA Runtime API其实就是CUDA Driver API的封装,底层还是要调用到CUDA Driver API

3、在容器内可操作GPU设备

因此容器中访问 GPU 资源过程为:

要在容器内操作GPU设备,需要将GPU设备挂载到容器里,Docker可通过 --device 挂载需要操作的设备,或者直接使用特权模式(不推荐)。NVIDIA Docker是通过注入一个 prestart 的hook 到容器中,在容器自定义命令启动前就将GPU设备挂载到容器中。至于要挂载哪些GPU,可通过 NVIDIA_VISIBLE_DEVICES 环境变量控制。

挂载GPU设备到容器后,还要在容器内可调用CUDA API。CUDA Runtime API和CUDA Libraries通常跟应用程序一起打包到镜像里,而CUDA Driver API是在宿主机里,需要将其挂载到容器里才能被使用。NVIDIA Docker挂载CUDA Driver库文件到容器的方式和挂载GPU设备一样,都是在runtime hook里实现的。

注意:

该方案也有一些问题,即容器内的 cuda toolkit 同宿主机的 cuda driver 可能存在版本不兼容的问题。

NVIDIA Docker CUDA容器化分析:

这里主要分析下NVIDIA Docker 2.0的实现

修改Docker daemon 的启动参数,将默认的 Runtime修改为 nvidia-container-runtime后,可实现将GPU设备,CUDA Driver库挂载到容器中。

cat /etc/docker/daemon.json 
{
    "default-runtime": "nvidia",
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

nvidia-container-runtime实现如下:
在这里插入图片描述

nvidia-container-runtime其实就是在runc基础上多实现了nvidia-container-runime-hook,该hook是在容器启动后(Namespace已创建完成),容器自定义命令(Entrypoint)启动前执行。当检测到NVIDIA_VISIBLE_DEVICES环境变量时,会调用libnvidia-container挂载GPU Device和CUDA Driver。如果没有检测到NVIDIA_VISIBLE_DEVICES就会执行默认的runc。

NVIDIA Container Toolkit

在这里插入图片描述

如上图所示, NVIDIA 将原来 CUDA 应用依赖的API环境划分为两个部分:

1、驱动级API:由libcuda.so.major.minor动态库和内核module提供支持,图中表示为CUDA Driver

驱动级API属于底层API,每当NVIDIA公司释放出某一个版本的驱动时,如果你要升级主机上的驱动,那么内核模块和libcuda.so.major.minor这2个文件就必须同时升级到同一个版本,这样原有的程序才能正常工作,
不同版本的驱动不能同时存在于宿主机上

2、非驱动级API:由动态库libcublas.so等用户空间级别的API组成,图中表示为CUDA Toolkit

非驱动级API的版本号是以Toolkit自身的版本号来管理, 比如cuda-10,cuda-11
不同版本的Toolkit可以同时运行在相同的宿主机上
非驱动级API算是对驱动级API的一种更高级的封装,最终还是要调用驱动级API来实现功能

为了让使用GPU的容器更具可扩展性,关于非驱动级的API被 NVIDIA 打包进了 NVIDIA Container Toolkit,因此在容器中使用GPU之前,每个机器需要先安装好NVIDIA驱动,之后配置好 NVIDIA Container Toolkit之后,就可以在容器中方便使用GPU了。

注:本文转载自blog.csdn.net的云原生笔记的文章"https://luzejia.blog.csdn.net/article/details/127024933"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top