准備
相關鏈接
安裝
dpkg -i nvidia-docker_1.0.1-1_amd64.deb
- 1
優勢
集成nvidia-docker有以下好處:
- 可復制的版本
- 易於部署
- 單獨設備的隔離
- 跨異構驅動程序運行
- 只需要安裝NVIDIA驅動程序
- 啟用“開啟和忘記”GPU應用程序
- 促進合作
nvidia-docker
描述
nvidia-docker是docker頂部的薄包裝, 作為docker命令行界面的替代品. 提供這個二進制文件, 方便用戶自動檢測和設置利用NVIDIA硬件的GPU容器. 如果您不打算使用它, 請參閱內部部分.
在內部, nvidia-docker調用docker, 依靠NVIDIA Docker插件來發現驅動程序文件和GPU設備. nvidia-docker使用的命令可以使用環境變量NV_DOCKER來覆蓋:
# Running nvidia-docker with a custom docker command NV_DOCKER='sudo docker -D' nvidia-docker <docker-options> <docker-command> <docker-args>
- 1
- 2
請注意, nvidia-docker僅修改運行的行為並創建Docker命令. 所有其他命令只是傳遞到docker命令行界面. 因此, 在構建Docker映像時, 無法執行GPU代碼.
GPU隔離
使用環境變量NV_GPU通過逗號分隔的ID列表導出GPU. ID是指定設備的索引或UUID.
設備索引類似於nvidia-docker-plugin REST接口, nvidia-smi報告的索引, 或者運行CUDA_DEVICE_ORDER = PCI_BUS_ID的CUDA代碼時, 它與默認的CUDA排序不同. 默認情況下, 導出所有GPU.
# Running nvidia-docker isolating specific GPUs by index NV_GPU='0,1' nvidia-docker <docker-options> <docker-command> <docker-args> # Running nvidia-docker isolating specific GPUs by UUID NV_GPU='GPU-836c0c09,GPU-b78a60a' nvidia-docker <docker-options> <docker-command> <docker-args>
- 1
- 2
- 3
- 4
本地運行
如果nvidia-docker-plugin安裝在主機上並在本地運行, 則不需要額外的步驟. 需要啟動使用NVIDIA GPU的容器時, nvidia-docker將通過查詢插件執行必要的操作.
遠程運行
遠程使用nvidia-docker需要在遠程主機上運行nvidia-docker-plugin.
可以使用環境變量DOCKER_HOST或NV_HOST設置遠程主機目標.
規定如下:
- 如果
NV_HOST被設置, 那么它用於聯系插件. - 如果
NV_HOST未設置, 但DOCKER_HOST已設置, 則NV_HOST默認為DOCKER_HOST位置, 使用端口3476上的http協議(更多)
NV_HOST的規范定義為:[(http|ssh)://][<ssh-user>@][<host>][:<ssh-port>]:[<http-port>]
http協議要求nvidia-docker-plugin在可達接口上進行監聽(默認情況下, nvidia-docker-plugin只偵聽本地主機). 選擇ssh的時候, 只需要有效的SSH憑據(您的ssh代理中的密碼或私鑰).
# Run CUDA on the remote host 10.0.0.1 using HTTP DOCKER_HOST='10.0.0.1:' nvidia-docker run cuda # Run CUDA on the remote host 10.0.0.1 using SSH NV_HOST='ssh://10.0.0.1:' nvidia-docker -H 10.0.0.1: run cuda # Run CUDA on the remote host 10.0.0.1 using SSH with custom user and ports DOCKER_HOST='10.0.0.1:' NV_HOST='ssh://foo@10.0.0.1:22:80' nvidia-docker run cuda
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
nvidia-docker-plugin
描述
nvidia-docker-plugin是一個Docker Engine插件, 旨在簡化在異構環境中部署GPU感知容器的過程. 它作為守護進程, 發現主機驅動程序文件和GPU設備以及源自Docker守護程序的卷安裝請求的答案.
該插件還提供了一個REST API, 可以查詢以獲取GPU信息, 也可以根據給定的卷名稱和設備編號生成Docker參數.
用法
可以使用以下參數調整插件守護程序:
Usage of nvidia-docker-plugin: -d string Path where to store the volumes (default "/var/lib/nvidia-docker/volumes") -l string Server listen address (default "localhost:3476") -s string Path to the plugin socket (default "/run/docker/plugins") -v Show the plugin version information
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
如果您正在使用二進制包, 那么可以在init配置文件中更改:/etc/default/nvidia-docker或/etc/systemd/system/nvidia-docker.service.d/override.conf, 具體取決於您的分發.
一旦插件運行, nvidia-docker將能夠連接到它並請求信息進行容器化. 如果升級NVIDIA驅動程序, 您將需要重新啟動該插件.
REST API
默認情況下, nvidia-docker-plugin在端口3476上本地提供其REST接口. 這將有效防止nvidia-docker通過http協議遠程訪問計算機(請參閱遠程部署). 可以使用-l使用選項(例如通配符地址端口1234的-l:1234)來更改此行為.
REST端點如下所述. 請注意, 如果給定的客戶端僅關心最新的API版本, 則可以省略版本前綴(即/ gpu / info當前等效於/v1.0/gpu/info)
Version 1.0
- GET
/v1.0/gpu/info,/v1.0/gpu/info/json
查詢GPU設備信息 (類似於nvidia-smi -q).
應答信息格式分別為text/plainandapplication/json.
- GET
/v1.0/gpu/status,/v1.0/gpu/status/json
查看GPU設備狀態 (類似於nvidia-smi).
應答信息格式分別為text/plainandapplication/json.- GET
/v1.0/docker/cli,/v1.0/docker/cli/json
查詢與docker運行或docker創建一起使用的命令行參數.
它接受兩個查詢字符串參數:dev用於設備(類似於NV_GPU)和vol的卷.
應答信息格式分別為text/plainandapplication/json.
如果您不想依賴nvidia-docker替代CLI(參見Internals), 這很有用. 例如:
> docker run -ti `curl -s http//localhost:3476/v1.0/docker/cli?dev=0+1\&vol=nvidia_driver` cuda
>- GET
/v1.0/mesos/cli
查詢啟動Mesos代理時使用的命令行參數.
與/v1.0/gpu/info/json類似, 但在zlib / base64(RFC 6920)中壓縮和編碼設備信息.
已知限制
- NVIDIA驅動程序安裝需要與Docker插件的卷目錄保持在同一分區上.
nvidia-docker-plugin內部需要創建一些驅動程序文件的硬鏈接. 因此, 您需要NVIDIA驅動程序(通常位於/usr下)與Docker插件卷目錄位於同一分區(默認情況下為/var). 可能的解決方法包括在不同的位置安裝NVIDIA驅動程序(請參閱 - 安裝程序的高級選項)或更改插件卷目錄(請參閱nvidia-docker-plugin -d)
不建議將nvidia-docker-plugin卷目錄放在與NVIDIA驅動程序(即/usr/lib, /usr/lib64 …)相同的目錄結構下. 這是由於NVIDIA安裝程序在執行升級之前執行沖突文件的檢查.
內部架構
NVIDIA驅動
挑戰
為了在您的機器上執行GPU應用程序, 您需要安裝NVIDIA驅動程序. NVIDIA驅動程序由多個內核模塊組成:
$ lsmod | grep nvidia
nvidia_uvm 711531 2 nvidia_modeset 742329 0 nvidia 10058469 80 nvidia_modeset,nvidia_uvm
- 1
- 2
- 3
- 4
它還提供了一組用戶級驅動程序庫, 使您的應用程序能夠與內核模塊以及GPU設備進行通信:
$ ldconfig -p | grep -E 'nvidia|cuda' libnvidia-ml.so (libc6,x86-64) => /usr/lib/nvidia-375/libnvidia-ml.so libnvidia-glcore.so.375.66 (libc6,x86-64) => /usr/lib/nvidia-375/libnvidia-glcore.so.375.66 libnvidia-compiler.so.375.66 (libc6,x86-64) => /usr/lib/nvidia-361/libnvidia-compiler.so.375.66 libcuda.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libcuda.so ...
- 1
- 2
- 3
- 4
- 5
- 6
請注意庫如何與驅動程序版本相關聯.
驅動程序安裝程序還提供了諸如nvidia-smi和nvidia-modprobe之類的實用程序二進制文件.
集成GPU應用程序的早期想法之一是將用戶級驅動程序庫安裝在容器內(例如使用驅動程序安裝程序中的選項–no-kernel-module). 然而, 用戶級驅動程序庫與內核模塊的版本相關, 所有Docker容器共享主機操作系統內核. 內核模塊的版本必須與用戶級庫的版本完全匹配(主要版本和次要版本). 嘗試運行具有不匹配環境的容器會立即在容器內產生錯誤:
$ nvidia-smi
Failed to initialize NVML: Driver/library version mismatch
- 1
- 2
這種方法使鏡像不可移植, 使鏡像分享變得不可能, 從而打敗了Docker的主要優勢. 解決方案是使鏡像與驅動程序版本無關. DockerHub上提供的Docker鏡像是通用的, 但是當創建容器時, 環境必須通過docker run的--volume參數來掛載主機上的用戶級庫, 從而指定了主機內核模塊.
NVIDIA驅動程序支持多個主機操作系統, 有多種安裝驅動程序的方法(例如runfile或deb/rpm軟件包), 安裝程序也可以自定義. 在整個發行版中, 驅動程序文件沒有便攜式位置. 要導入的文件列表也可能取決於您的驅動程序版本.
nvidia-docker
我們的方法等同於如上所示運行ldconfig -p:我們以編程方式解析ldcache文件(/etc/ld.so.cache), 以發現庫的預定義列表的位置. 有些庫可以在系統上找到多次, 其中一些庫不能被選擇. 例如, OpenGL庫可以由多個供應商提供. 我們有一個函數, 能夠拉黑這些已知由多重來源提供的庫.
由於這些庫可以分散在主機文件系統中, 因此我們創建了一個由已發現庫的硬鏈接組成的Docker 命名卷 , 如果硬連接無效, 則有一個復制回退路徑. 這個卷可以通過nvidia-docker-plugin守護進程來進行管理, 該守護進程實現了volume plugins的Docker API.
$ docker volume inspect nvidia_driver_375.66 [ { "Driver": "nvidia-docker", "Labels": null, "Mountpoint": "/var/lib/nvidia-docker/volumes/nvidia_driver/375.66", "Name": "nvidia_driver_375.66", "Options": {}, "Scope": "local" } ]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
nvidia-docker包裝器將自動將卷參數添加到命令行, 然后將控制權傳遞給docker, 您只需要運行nvidia-docker-plugin守護程序即可.
替代選擇
如果不想使用nvidia-docker包裝器, 可以手動添加命令行參數:
$ docker run --volume-driver=nvidia-docker --volume=nvidia_driver_375.66:/usr/local/nvidia:ro
- 1
請參閱該wiki的下一部分, 了解如何發現和導入設備文件.
為避免使用–volume-driver(因為每個命令行只能使用一次), 您可以手動創建命名卷:
$ docker volume create --name=nvidia_driver_375.66 -d nvidia-docker
- 1
上述兩個解決方案仍然需要使用nvidia-docker-plugin, 但是由於Docker正式支持volume plugins, 因此這個問題應該更少.
如果您不想使用volume plugins, 則必須使用ldconfig -p或解析ldcache手動查找驅動程序文件. 如果您的部署環境完全相同, 您可以簡單地硬編碼用例的文件路徑. 為了驗證, 您可以查看由nvidia-docker-plugin創建的卷:
我們不建議基於通過查找找到庫的解決方案, 因為您可能從較舊的驅動程序安裝中選擇流浪庫.
我們建議使用驅動程序版本對該卷的名稱進行后綴, 這樣可以防止錯誤驅動程序/庫版本不匹配, 如果您更新驅動程序但忘記重新創建一個新的卷.
GPU隔離
挑戰
GPU在/dev中顯示為獨立的設備文件, 以及其他設備:
$ ls -l /dev/nvidia* crw-rw-rw- 1 root root 195, 0 Jul 10 10:03 /dev/nvidia0 crw-rw-rw- 1 root root 195, 1 Jul 10 10:03 /dev/nvidia1 crw-rw-rw- 1 root root 195, 2 Jul 10 10:03 /dev/nvidia2 crw-rw-rw- 1 root root 195, 3 Jul 10 10:03 /dev/nvidia3 crw-rw-rw- 1 root root 195, 255 Jul 10 10:03 /dev/nvidiactl crw-rw-rw- 1 root root 246, 0 Jul 10 10:03 /dev/nvidia-uvm crw-rw-rw- 1 root root 246, 1 Jul 10 10:03 /dev/nvidia-uvm-tools
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
Docker允許用戶在啟動容器(docker run)時通過參數--device來放行對特定設備的訪問(使用cgroup). 在多GPU機器上, 常見的用例是並行啟動多個作業, 每個作業都使用可用GPU的子集. 最基本的解決方案是使用環境變量CUDA_VISIBLE_DEVICES, 但這並不能保證正確的隔離. 通過在Docker中使用設備白名單, 您可以限制容器可以訪問的GPU. 例如, 容器A被授予訪問/dev/nvidia0, 而容器B被授予對/dev/nvidia1的訪問權限. 設備/dev/nvidia-uvm和/dev/nvidiactl不對應於GPU, 並且對於所有容器都可以訪問它們.
第一個挑戰是將設備文件(或換句話說, 次要設備數量)映射到PCI總線排序(由nvidia-smi報告). 當您的機器上有不同型號的GPU並且您想要將容器特別分配給一個GPU時, 這一點非常重要. nvidia-smi報告的GPU編號並不總是匹配設備文件的次要號碼:
$ nvidia-smi -q GPU 0000:05:00.0 Minor Number: 3 GPU 0000:06:00.0 Minor Number: 2
- 1
- 2
- 3
- 4
- 5
- 6
第二個挑戰與nvidia_uvm內核模塊相關,它在引導時不會自動加載,因此/dev/nvidia-uvm不會被創建,並且容器可能沒有足夠的權限來加載內核模塊本身。 在啟動任何CUDA容器之前,必須手動加載內核模塊。
nvidia-docker
使用NVML庫中的函數nvmlDeviceGetCount枚舉GPU,並使用函數nvmlDeviceGetMinorNumber獲取相應的設備。 如果設備次要號碼為N,則設備文件只是/dev/nvidiaN。 使用環境變量NV_GPU控制隔離,通過傳遞GPU的索引來隔離,例如:
$ NV_GPU=0,1 nvidia-docker run -ti nvidia/cuda nvidia-smi
- 1
nvidia-docker包裝器將找到相應的設備文件,並將--device參數添加到命令行,然后將控制權傳遞給docker。
要手動加載nvidia_uvm並創建/dev/nvidia-uvm,我們在啟動nvidia-docker-plugin守護程序時,在主機上使用命令nvidia-modprobe -u -c = 0。
替代選擇
如果你不想使用nvidia-docker
$ docker run --device=/dev/nvidiactl --device=/dev/nvidia-uvm --device=/dev/nvidia0
- 1
這需要與用於安裝包含用戶級驅動程序庫的卷的命令行參數結合使用。 可以使用來自NVML的nvmlDeviceGetCount或CUDA API的cudaGetDeviceCount列出可用的GPU。 我們建議使用NVML,因為它還提供nvmlDeviceGetMinorNumber來查找要裝載的設備文件。 如果要使用NVML或nvidia-smi收集使用率指標,則必須在設備文件和孤立的GPU之間進行正確的映射。 如果您仍然想使用CUDA API,請確保取消設置環境變量CUDA_VISIBLE_DEVICES,否則系統上的某些GPU可能不會被列出。
要加載nvidia_uvm,您還應該使用nvidia-modprobe -u -c = 0(如果可用)。 如果不是,您需要手動執行mknod。
鏡像檢查
挑戰
安裝用戶級驅動程序庫和設備文件會破壞容器的環境,只有當容器運行GPU應用程序時才應該執行此操作。 這里的挑戰是確定給定的圖像是否將使用GPU。 我們還應該防止基於與主機NVIDIA驅動程序版本不兼容的Docker映像啟動容器,您可以在此wiki頁面上找到更多詳細信息。
nvidia-docker
沒有通用的解決方案來檢測是否有任何鏡像將使用GPU代碼。在nvidia-docker中,我們假設基於我們的nvidia / cuda映像(DockerHub上可用)的任何映像都將是GPU應用程序,因此它們需要驅動程序卷和設備文件。
更具體地說,當使用nvidia-docker運行時,我們檢查在命令行中指定的鏡像。在這個鏡像中,我們查找標簽com.nvidia.volumes.needed的存在和值。 我們提供的nvidia / cuda圖像開始時都包含這個標簽。執行FROM nvidia / cuda的所有Docker文件將自動繼承此元數據,從而可以與nvidia-docker無縫工作。
為了檢測鏡像與主機驅動程序不兼容,我們依賴於第二個元數據,即com.nvidia.cuda.version標簽。此標簽存在於每個CUDA基本鏡像中,並具有相應的版本號。該版本與驅動程序支持的最大CUDA版本進行比較,nvidia-docker為此使用CUDA API函數cudaDriverGetVersion。如果驅動程序對於運行此版本的CUDA來說太舊了,則在啟動容器之前會出現錯誤:
$ nvidia-docker run --rm nvidia/cuda nvidia-docker | 2016/04/21 21:41:35 Error: unsupported CUDA version: driver 7.0 < image 7.5
- 1
- 2
替代選擇
在這種情況下,nvidia-docker不會簡單地將參數注入docker命令行。 因此,重現這種行為更為復雜。 您將需要在工作流程或容器編排解決方案的上游檢查圖像。 查看圖像內的標簽很簡單:
If you build your own custom CUDA images, we suggest you to reuse the same labels for compatibility reasons
--------------------- 作者:思庄 來源:CSDN 原文:https://blog.csdn.net/QiangLi_strong/article/details/81022591?utm_source=copy 版權聲明:本文為博主原創文章,轉載請附上博文鏈接!
