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
如上所述,通过 --device 来指定挂载的GPU设备,通过 -v 来将宿主机上的 nvidia gpu 的命令行工具和相关的依赖库挂载到容器。这样,在容器中就可以看到和使用宿主机上的GPU设备了。 这样使用,对于GPU的可用性(哪些GPU是空闲的等)需要人为的判断,效率很低。为了提高Nvidia GPU在 docker 中的易用性, Nvidia 通过对原生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或者自己来启动容器进程。
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逻辑。
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更高一层的封装,通常是一些成熟的高效函数库,
开发者也可以自己封装一些函数库便于使用;
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 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 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": []
}
}
}
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 将原来 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了。
浏览器对象模型(BOM)以window对象对象为委托,表示浏览器窗口以及页面可见区域。同时,window对象还是ECMAScript中global对象,因而所有全局变量和函数都是它的属性,且所有原生的构造函数函数及其他函数也都是存在于它的命名空间下。本章讨论了下列BOM的组成部分。 1.在使用框架时,每个框架都有自己的window对象以及所有原生构造函数及其他函数的副本。每个框架都...
原文地址:http://www.kernelchina.org/node/277对于协处理器CP0的访问,需要使用特别的指令。这些指令属于“特权级指令”,只有在内核态(Kernel Mode)下才能执行。如果在用户态下,会引起一个异常(Exception)。对CP0的主要操作有以下的指令:mfc0 rt, rd 将CP0中的rd寄存器内容传输到rt通用寄存器;mtc0 rt,
一、图的表示1.1 邻接矩阵一个一维数组存储顶点。一个二维数组存储边。稠密图首选邻接矩阵。如果顶点太多了,比如说有100000个顶点,要开辟mpt[100000][100000]这么大的数组,空间超出限制,则考虑用邻接表。同时,如果图比较稀疏,也可考虑用邻接表。下面演示邻接矩阵的存储过程。#include <bits/stdc++.h>using namespace std;int mpt[105][105]; int n,m; //n个点,m条边 # define IN
关于Anaconda的使用https://www.php.cn/python-tutorials-392026.html
当时遇到这个错误只知道是编译错误,不知道为什么,也定不了问题所在,网上说的一堆也试了,都没用日志的错误说的也不清晰,有很多时候我都是Rebuild或清理工程就解决了,这次是因为集成极光分享,集成到一半又删了,没删干净,所以出现了这个问题,处理方法是把下图的文件夹删掉,重新编译,立马定位到代码块找不到极光的包,删除该代码就好了,因为上次集成极光编译是没问题的,删了极光后还有缓存,An...
tftp服务器软件 内容精选换一换需在所有云服务器上安装Data Provider软件,SAP技术支持人员通过该软件收集云服务器所在的平台信息,以便在SAP系统故障、性能下降时进行定位和分析。SAP NetWeaver所在的服务器上,在创建服务器的时候需要为其指定名为DataproviderAccess的Agency,同时也需要安装Data Provider软件。syst需在所有云服务器上安装Da...
1,org.springframework.remoting.RemoteAccessException: Cannot access Hessian service at [http://61.152.162.173/remote/remoteService]; 出现这个异常一般是因为服务端操作出现异常引起的2,com.caucho.hessian.io.Hess...
最近写脚本的时候碰到了这方面的问题,到网上搜了半天也没找到好一点的方案或总结。今天我把自己的摸索写一下。 首先是Sed里使用变量的问题网上有人总结了四种方案:1. eval sed 's/$a/$b/' filename2. sed "s/$a/$b/" filename3. .sed 's/'$a'/'$b'/'
中山大学C++视频下载地址
中山大学南方学院是经教育部批准设立,于2006年由中山大学与广东珠江投资集团合作创办的独立学院,是一所多学科全日制应用型本科高等学校。学校位于素有“北回归线上的明珠”和“都市桃园”之誉的广州市从化区,校园占地面积1000亩。经过11年的建设和发展,现已拥有完备的教学生活和文化体育设施,校园布局有致,秀丽宁静,是陶冶情操、读书治学的胜境。学校图书馆面积2.91万平方米,藏书200万册,共享中山大学图...
中文名马啸职业教师学位/学历博士专业方向信息论与编码、空间通信、无线通信(5G通信)等职务中山大学数据科学与计算机学院副院长职称教授马啸人物经历编辑语音1997年,硕士,通信与电子系统,西安电子科技大学1991年,学士,应用数学,哈尔滨船舶工程学院工作经历:2004.7—,中山大学信息科学与技术学院电子与通信工程系,教授,博士生导师2002.9—2004.12,香港城市大学...
在实际开发环境中,经常需要同时运行32位与64位的Eclipse与JDK,为了保持它们的兼容性,需要进行如下设置。1. 同时安装JDK 32bit与JDK 64bit如果需要在64位的Windows上同时安装JDK 32bit与JDK 64bit,则需要进行如下两个步骤: 1. 先安装32位版本,在安装目录下拷贝出JDK与JRE,存放到另外的地址如D:/JDK32,或者直接安装JDK压缩包。 2