docker容器訪問GPU資源的使用指南
概述
nvidia-docker 和 nvidia-container-runtime 是用于在 NVIDIA GPU 上運(yùn)行 Docker 容器的兩個(gè)相關(guān)工具。它們的作用是提供 Docker 容器與 GPU 加速硬件的集成支持,使容器中的應(yīng)用程序能夠充分利用 GPU 資源。
nvidia-docker
為了提高 Nvidia GPU 在 docker 中的易用性, Nvidia 通過對(duì)原生 docker 的封裝提供了 nvidia-docker 工具
nvidia-docker 是一個(gè) Docker 插件,用于在 Docker 容器中啟用 NVIDIA GPU 支持。
該工具提供了一個(gè)命令行界面,允許在運(yùn)行容器時(shí)通過簡(jiǎn)單的命令來指定容器是否應(yīng)該訪問主機(jī)上的 NVIDIA GPU 資源。
當(dāng)在容器中運(yùn)行需要 GPU 加速的應(yīng)用程序時(shí),可以使用 nvidia-docker 來確保容器能夠訪問 GPU。
# 示例命令 nvidia-docker run -it --rm nvidia/cuda:11.0-base nvidia-smi
上述命令使用 nvidia-docker 在容器中運(yùn)行 NVIDIA 的 CUDA 基礎(chǔ)鏡像,并在容器中執(zhí)行 nvidia-smi 命令以查看 GPU 信息
nvidia-container-runtime
nvidia-container-runtime 是 NVIDIA 的容器運(yùn)行時(shí),它與 Docker 和其他容器運(yùn)行時(shí)(如 containerd)集成,以便容器可以透明地訪問 NVIDIA GPU 資源。
與 nvidia-docker 不同,nvidia-container-runtime 不是 Docker 插件,而是一種更通用的容器運(yùn)行時(shí),可與多個(gè)容器管理工具集成。
nvidia-docker
和 nvidia-container-runtime
都是用于使 Docker 容器能夠訪問 NVIDIA GPU 資源的工具??梢愿鶕?jù)自己的需求選擇其中一個(gè)來配置容器以利用 GPU 加速。
需要注意的是,最新的 NVIDIA Docker 支持通常建議使用 nvidia-container-runtime
,因?yàn)樗峁┝烁`活和通用的 GPU 支持,而不僅僅是為 Docker 定制的解決方案。
# 示例命令 docker run --runtime=nvidia -it --rm nvidia/cuda:11.0-base nvidia-smi
上述命令使用 Docker 運(yùn)行容器,通過 --runtime=nvidia
參數(shù)指定使用 nvidia-container-runtime
運(yùn)行時(shí),并在容器中執(zhí)行 nvidia-smi
命令。
原生 docker 通過設(shè)備掛載和磁盤掛載的方式支持訪問 GPU 資源
docker 本身并不原生支持 GPU,但使用 docker 的現(xiàn)有功能可以對(duì) GPU 的使用進(jìn)行支持
# 示例命令 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 設(shè)備,通過 -v 來將宿主機(jī)上的 nvidia gpu 的命令行工具和相關(guān)的依賴庫掛載到容器。這樣,在容器中就可以看到和使用宿主機(jī)上的 GPU 設(shè)備了。
注意:這種方式對(duì)于 GPU 的可用性(哪些 GPU 是空閑的等)需要人為的判斷,效率很低
nvidia-docker 詳解
結(jié)構(gòu)圖及各組件說明
nvidia-docker 對(duì)于使用 GPU 資源的 docker 容器支持的層次關(guān)系:
Nvidia-docker的原理圖以及各個(gè)部分的作用解析:
**libnvidia-container:**提供了一個(gè)庫和簡(jiǎn)單的 CLI 工具,以實(shí)現(xiàn)在容器當(dāng)中支持使用 GPU 設(shè)備的目標(biāo)。
nvidia-container-toolkit:
是一個(gè)實(shí)現(xiàn)了 runC 的 prestart hook 接口的腳本,該腳本在 runC 創(chuàng)建一個(gè)容器之后,啟動(dòng)該容器之前調(diào)用,其主要作用就是修改與容器相關(guān)聯(lián)的 config.json,注入一些在容器中使用 NVIDIA GPU 設(shè)備所需要的一些信息(比如:需要掛載哪些 GPU 設(shè)備到容器當(dāng)中)。
nvidia-container-runtime:
主要用于將容器 runC spec 作為輸入,然后將 nvidia-container-toolkit 腳本作為一個(gè) prestart hook 加入到 runC spec 中,再用修改后的 runC spec 調(diào) runc 的 Exec 接口運(yùn)行容器。
所以在容器啟動(dòng)之前會(huì)調(diào)用 pre-start hook(nvidia-container-toolkit),這個(gè) hook 會(huì)通過 nvidia-container-cli 文件,來調(diào)用libnvidia-container 庫,最終映射掛載宿主機(jī)上的 GPU 設(shè)備、nvid 驅(qū)動(dòng)的 so 文件、可執(zhí)行文件到容器內(nèi)部。
nvidia-container-runtime 才是真正的核心部分,它在原有的 docker 容器運(yùn)行時(shí) runc 的基礎(chǔ)上增加一個(gè) prestart hook,用于調(diào)用 libnvidia-container 庫
RunC:
RunC 是一個(gè)輕量級(jí)的工具,它是用來運(yùn)行容器的,只用來做這一件事。
可以認(rèn)為它就是個(gè)命令行小工具,可以不用通過 docker 引擎,直接運(yùn)行容器。也是 docker 默認(rèn)的容器運(yùn)行方式。
事實(shí)上,runC 是標(biāo)準(zhǔn)化的產(chǎn)物,它根據(jù) OCI 標(biāo)準(zhǔn)來創(chuàng)建和運(yùn)行容器。而 OCI(Open Container Initiative)組織,旨在圍繞容器格式和運(yùn)行時(shí)制定一個(gè)開放的工業(yè)化標(biāo)準(zhǔn)。
直接使用 RunC 的命令行即可以完成創(chuàng)建一個(gè)容器,并提供了簡(jiǎn)單的交互能力。
容器創(chuàng)建過程
創(chuàng)建一個(gè)正常容器(不支持 GPU)的流程:
docker --> dockerd --> containerd–> containerd-shim -->runc --> container-process
docker 客戶端將創(chuàng)建容器的請(qǐng)求發(fā)送給 dockerd,當(dāng) dockerd 收到請(qǐng)求任務(wù)之后將請(qǐng)求發(fā)送給 containerd,containerd 經(jīng)過查看校驗(yàn)啟動(dòng) containerd-shim 或者自己來啟動(dòng)容器進(jìn)程。
創(chuàng)建一個(gè)支持 GPU 的容器的流程:
docker–> dockerd --> containerd --> containerd-shim–> nvidia-container-runtime --> nvidia-container-runtime-hook --> libnvidia-container --> runc – > container-process
基本流程和不支持 GPU 的容器差不多,只是把 docker 默認(rèn)的運(yùn)行時(shí)替換成了 NVIDIA 封裝的 nvidia-container-runtime
這樣當(dāng) nvidia-container-runtime 創(chuàng)建容器時(shí),先執(zhí)行 nvidia-container-runtime-hook,這個(gè) hook 去檢查容器是否需要使用GPU(通過環(huán)境變 NVIDIA_VISIBLE_DEVICES 來判斷)。如果需要?jiǎng)t調(diào)用 libnvidia-container 來暴露 GPU 給容器使用。否則走默認(rèn)的 runc 邏輯。
NVIDIA Docker 整體工作架構(gòu)
軟硬件基礎(chǔ)
- 硬件,服務(wù)器上安裝了英偉達(dá) GPU
- 宿主機(jī),安裝了操作系統(tǒng)和 Cuda Driver,以及 Docker 引擎
- 容器,包含容器 OS 用戶空間,Cuda Toolkit,以及用戶應(yīng)用程序
注意:
- 宿主機(jī)上需要安裝 cuda driver,容器內(nèi)需要安裝 cuda toolkit。容器內(nèi)無需安裝 cuda driver
- NVIDIA 提供了一些官方鏡像,其中已經(jīng)安裝好了 cuda toolkit,但還是需要在宿主機(jī)安裝 cuda driver。
API 結(jié)構(gòu)
NVIDIA 提供了三層 API:
- CUDA Driver API:
GPU 設(shè)備的抽象層,通過提供一系列接口來操作 GPU 設(shè)備,性能最好,但編程難度高,一般不會(huì)使用該方式開發(fā)應(yīng)用程序
- CUDA Runtime API:
對(duì) CUDA Driver API 進(jìn)行了一定的封裝,調(diào)用該類 API 可簡(jiǎn)化編程過程,降低開發(fā)難度
- CUDA Libraries:
是對(duì) CUDA Runtime API 更高一層的封裝,通常是一些成熟的高效函數(shù)庫,開發(fā)者也可以自己封裝一些函數(shù)庫便于使用
CUDA 結(jié)構(gòu)圖如下:
CUDA 調(diào)用關(guān)系:
應(yīng)用程序可調(diào)用 CUDA Libraries 或者 CUDA Runtime API 來實(shí)現(xiàn)功能,當(dāng)調(diào)用 CUDA Libraries 時(shí),CUDA Libraries 會(huì)調(diào)用相應(yīng)的 CUDA Runtime API,CUDA Runtime API 再調(diào)用 CUDA Driver API,CUDA Driver API 再操作 GPU 設(shè)備。
CUDA 的容器化
目標(biāo):讓應(yīng)用程序可以在容器內(nèi)調(diào)用 CUDA API 來操作 GPU
因此需要實(shí)現(xiàn):
- 在容器內(nèi)應(yīng)用程序可調(diào)用 CUDA Runtime API 和 CUDA Libraries
- 在容器內(nèi)能使用 CUDA Driver 相關(guān)庫。因?yàn)?CUDA Runtime API 其實(shí)就是 CUDA Driver API 的封裝,底層還是要調(diào)用到 CUDA Driver API
- 在容器內(nèi)可操作 GPU 設(shè)備
因此容器中訪問 GPU 資源過程為:
- 要在容器內(nèi)操作 GPU 設(shè)備,需要將 GPU 設(shè)備掛載到容器里
- Docker 可通過 --device 掛載需要操作的設(shè)備,或者直接使用特權(quán)模式(不推薦)。
- NVIDIA Docker 是通過注入一個(gè) prestart 的 hook 到容器中,在容器自定義命令啟動(dòng)前就將GPU設(shè)備掛載到容器中。
- 至于要掛載哪些GPU,可通過 NVIDIA_VISIBLE_DEVICES 環(huán)境變量控制。
- 掛載 GPU 設(shè)備到容器后,還要在容器內(nèi)可調(diào)用 CUDA API
- CUDA Runtime API 和 CUDA Libraries 通常跟應(yīng)用程序一起打包到鏡像里
- CUDA Driver API 是在宿主機(jī)里,需要將其掛載到容器里才能被使用。
- NVIDIA Docker 掛載 CUDA Driver 庫文件到容器的方式和掛載 GPU 設(shè)備一樣,都是在 runtime hook 里實(shí)現(xiàn)的。
注意:
該方案也有一些問題,即容器內(nèi)的 CUDA Runtime 同宿主機(jī)的 CUDA driver 可能存在版本不兼容的問題。
CUDA Libraries 和 CUDA Runtime API 是和應(yīng)用程序一起打包到鏡像中的,而 Driver 庫是在創(chuàng)建容器時(shí)從宿主機(jī)掛載到容器中的,需要保證 CUDA Driver 的版本不低于 CUDA Runtime 版本。
NVIDIA Docker 2.0(nvidia-container-runtime)
實(shí)現(xiàn)機(jī)制
- nvidia-docker2.0 是一個(gè)簡(jiǎn)單的包,它主要通過修改 docker 的配置文件 /etc/docker/daemon.json,將默認(rèn)的 Runtime 修改為 nvidia-container-runtime,可實(shí)現(xiàn)將 GPU 設(shè)備,CUDA Driver 庫掛載到容器中。
cat /etc/docker/daemon.json { "default-runtime": "nvidia", "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [] } } }
Debug日志
修改 nvidia runc 的默認(rèn)配置文件 /etc/nvidia-container-runtime/config.toml ,打開 hook 的 debug 日志選項(xiàng),可以看到宿主機(jī)掛載 nvidia 驅(qū)動(dòng)、設(shè)備到容器內(nèi)部的詳細(xì)過程。
以上就是docker容器訪問GPU資源的使用指南的詳細(xì)內(nèi)容,更多關(guān)于docker訪問GPU資源的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用dockercompose搭建springboot-mysql-nginx應(yīng)用
這篇文章主要介紹了使用dockercompose搭建springboot-mysql-nginx應(yīng)用,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-03-03使用Docker搭建Vsftpd 的 FTP 服務(wù)的詳細(xì)過程
FTP 基礎(chǔ)FTP 需要兩個(gè)端口,一個(gè)是數(shù)據(jù)端口,一個(gè)是控制端口,這篇文章主要介紹了使用Docker搭建Vsftpd的FTP服務(wù),需要的朋友可以參考下2022-08-08快速使用docker-compose部署clickhouse的教程
ClickHouse 的工作速度比傳統(tǒng)方法快 100-1000 倍。它適用于大數(shù)據(jù)、業(yè)務(wù)分析和時(shí)間序列數(shù)據(jù)。在這個(gè)小教程中,我將向您展示如何以最少的設(shè)置安裝 ClickHouse,感興趣的朋友一起看看吧2021-11-11解決Docker中的error during connect異常情況
這篇文章主要介紹了解決Docker中的error during connect異常情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11