在過去的幾年里,使用容器來大規(guī)模部署數(shù)據(jù)中心應用程序的數(shù)量急劇增加。原因很簡單:容器封裝了應用程序的依賴項,以提供可重復和可靠的應用程序和服務執(zhí)行,而無需整個虛擬機的開銷。如果您曾經(jīng)花了一天的時間為一個科學或 深度學習 應用程序提供一個包含大量軟件包的服務器,或者已經(jīng)花費數(shù)周的時間來確保您的應用程序可以在多個 linux 環(huán)境中構(gòu)建和部署,那么 Docker 容器非常值得您花費時間。
圖 1 : Docker 容器封裝了應用程序的依賴項,以提供可重復和可靠的執(zhí)行。 NVIDIA Docker 插件支持在任何 Linux GPU 服務器上部署 GPU – 加速應用程序,并支持 NVIDIA Docker 。
在 NVIDIA ,我們以各種方式使用容器,包括開發(fā)、測試、基準測試,當然還有生產(chǎn)中的容器,作為通過 NVIDIA DGX-1 的云管理軟件部署深度學習框架的機制。 Docker 改變了我們管理工作流程的方式。使用 Docker ,我們可以在工作站上開發(fā)和原型化 GPU 應用程序,然后在任何支持 GPU 容器的地方發(fā)布和運行這些應用程序。
在本文中,我們將介紹 Docker 容器;解釋 NVIDIA Docker 插件的好處;通過構(gòu)建和部署一個簡單的 CUDA 應用程序的示例;最后演示如何使用 NVIDIA Docker 運行當今最流行的深度學習應用程序和框架,包括 DIGITS 、 Caffe 和 TensorFlow 。
上周在 DockerCon 2016 年 上, Felix 和 Jonathan 做了一個演講“使用 Docker 實現(xiàn) GPU – 加速應用”。這是幻燈片。
[slideshare id=63346193&doc=146387dockercon16-160622172714]
Docker 簡介
Docker 容器是一種將 Linux 應用程序與其所有庫、數(shù)據(jù)文件和環(huán)境變量捆綁在一起的機制,以便在運行的任何 Linux 系統(tǒng)上以及在同一主機上的實例之間,執(zhí)行環(huán)境始終是相同的。 Docker 容器僅為用戶模式,因此來自容器的所有內(nèi)核調(diào)用都由主機系統(tǒng)內(nèi)核處理。 在它的網(wǎng)站上 , Docker 這樣描述容器:
Docker 容器將一個軟件包在一個完整的文件系統(tǒng)中,該文件系統(tǒng)包含運行所需的一切:代碼、運行時、系統(tǒng)工具、系統(tǒng)庫——任何可以安裝在服務器上的東西。這保證了軟件無論其環(huán)境如何,都將始終運行相同的程序。
區(qū)分容器和基于 hypervisor 的虛擬機( vm )很重要。 vm 允許操作系統(tǒng)的多個副本,甚至多個不同的操作系統(tǒng)共享一臺機器。每個虛擬機可以承載和運行多個應用程序。相比之下,容器被設計成虛擬化單個應用程序,并且部署在主機上的所有容器共享一個操作系統(tǒng)內(nèi)核,如圖 2 所示。通常,容器運行速度更快,以裸機性能運行應用程序,并且更易于管理,因為進行操作系統(tǒng)內(nèi)核調(diào)用沒有額外的開銷。
圖 2 :雖然 vm 封裝了整個操作系統(tǒng)和任何應用程序,但容器封裝了單個應用程序及其依賴項,以便進行可移植部署,但在容器之間共享相同的主機操作系統(tǒng)。
Docker 提供了硬件和軟件封裝,允許多個容器同時在同一個系統(tǒng)上運行,每個容器都有自己的資源集( CPU 、內(nèi)存等)和它們自己的專用依賴集(庫版本、環(huán)境變量等)。 Docker 還提供了可移植的 Linux 部署: Docker 容器可以在任何內(nèi)核為 3 。 10 或更高版本的 Linux 系統(tǒng)上運行。自 2014 年以來,所有主要的 Linux 發(fā)行版都支持 Docker 。封裝和可移植部署對于創(chuàng)建和測試應用程序的開發(fā)人員以及在數(shù)據(jù)中心運行應用程序的操作人員都很有價值。
Docker 提供了許多更重要的功能。
Docker 強大的命令行工具“ Docker build ”,使用“ Dockerfile ”中提供的描述,從源代碼和二進制文件創(chuàng)建 Docker 映像。
Docker 的組件架構(gòu)允許一個容器映像用作其他容器的基礎。
Docker 提供容器的自動版本控制和標簽,優(yōu)化了組裝和部署。 Docker 映像由版本化的層組合而成,因此只需要下載服務器上缺少的層。
Docker Hub 是一項服務,它可以方便地公開或私下共享 Docker 圖像。
容器可以限制在一個系統(tǒng)上有限的一組資源(例如一個 CPU 內(nèi)核和 1GB 內(nèi)存)。
Docker 提供了一個 分層文件系統(tǒng) ,它可以節(jié)省磁盤空間,并構(gòu)成可擴展容器的基礎。
為什么是 Docker ?
Docker 容器與平臺無關(guān),但也與硬件無關(guān)。當使用特殊的硬件,如 NVIDIA GPUs 時,這就產(chǎn)生了一個問題,這些硬件需要內(nèi)核模塊和用戶級庫來操作。因此, Docker 本機不支持容器中的 NVIDIA GPUs 。
解決這個問題的早期解決方案之一是在容器中完全安裝 NVIDIA 驅(qū)動程序,并在啟動時映射到與 NVIDIA GPUs (例如 /dev/nvidia0 )對應的字符設備中。此解決方案很脆弱,因為主機驅(qū)動程序的版本必須與容器中安裝的驅(qū)動程序版本完全匹配。這一要求大大降低了這些早期容器的可移植性,破壞了 Docker 更重要的特性之一。
為了使 Docker 映像能夠利用 NVIDIA GPUs 實現(xiàn)可移植性,我們開發(fā)了 nvidia-docker ,這是一個托管在 Github 上的開源項目,它提供了基于 GPU 的可移植容器所需的兩個關(guān)鍵組件:
與驅(qū)動程序無關(guān)的 CUDA 圖像;以及
Docker 命令行包裝器,在啟動時將驅(qū)動程序和 GPUs (字符設備)的用戶模式組件裝入容器。
nvidia-docker 本質(zhì)上是圍繞 docker 命令的包裝器,它透明地為容器提供了在 GPU 上執(zhí)行代碼所需的組件。只有在使用 nvidia-docker run 來執(zhí)行使用 GPUs 的容器時才是絕對必要的。但為了簡單起見,在本文中,我們將其用于所有 Docker 命令。
安裝 Docker 和 NVIDIA Docker
在我們開始構(gòu)建集裝箱化的 GPU 應用程序之前,讓我們先確保您已經(jīng)安裝了必備軟件并能正常工作。您需要:
您系統(tǒng)的最新 NVIDIA drivers 。
碼頭工人。您可以按照 此處為安裝說明 操作。
` NVIDIA -docker `您可以按照 此處為安裝說明 操作。
為了幫助安裝,我們創(chuàng)建了一個 執(zhí)行 docker 和 NVIDIA -docker 安裝的可靠角色 。 Ansible 是一個自動化機器配置管理和應用程序部署的工具。
要測試您是否準備就緒,請運行以下命令。您應該會看到與所示內(nèi)容類似的輸出。
要測試您是否準備就緒,請運行以下命令。您應該會看到與所示內(nèi)容類似的輸出。
ryan@titanx:~$ nvidia-docker run --rm hello-world Using default tag: latest latest: Pulling from library/hello-world a9d36faac0fe: Pull complete Digest: sha256:e52be8ffeeb1f374f440893189cd32f44cb166650e7ab185fa7735b7dc48d619 Status: Downloaded newer image for hello-world:latest Hello from Docker. This message shows that your installation appears to be working correctly. [... simplified output ...]
現(xiàn)在一切都正常了,讓我們開始在容器中構(gòu)建一個簡單的 GPU 應用程序。
構(gòu)建集裝箱化 GPU 應用程序
為了突出 Docker 和我們的插件的特性,我將在容器中從 CUDA 工具箱示例構(gòu)建 deviceQuery 應用程序。此三步方法可以應用于任何 CUDA 示例,也可以應用于您最喜歡的應用程序,只需稍作修改。
在容器中設置和探索開發(fā)環(huán)境。
在容器中構(gòu)建應用程序。
在多個環(huán)境中部署容器。
發(fā)展環(huán)境
相當于安裝 CUDA 開發(fā)庫的 Docker 命令如下:
nvidia-docker pull nvidia/cuda
這個命令從 DockerHub 獲取最新版本的nvidia/cuda
映像, DockerHub 是一個用于容器映像的云存儲服務。可以使用docker run
在這個容器中執(zhí)行命令。下面是在我們剛剛提取的容器中對nvcc --version
的調(diào)用。
ryan@titanx:~$ nvidia-docker run --rm -ti nvidia/cuda nvcc --version nvcc: NVIDIA (R) Cuda compiler driver Copyright (c) 2005-2015 NVIDIA Corporation Built on Tue_Aug_11_14:27:32_CDT_2015 Cuda compilation tools, release 7.5, V7.5.17
如果需要 CUDA 6 .5 或 7.0 ,可以指定 圖像的標記 。 Ubuntu 和 CentOS 可用的 CUDA 圖像列表可以在 NVIDIA -docker 維基 上找到。下面是一個使用 CUDA 7 。 0 的類似示例。
ryan@titanx:~$ nvidia-docker run --rm -ti nvidia/cuda:7.0 nvcc --version Unable to find image 'nvidia/cuda:7.0' locally 7.0: Pulling from nvidia/cuda 6c953ac5d795: Already exists [ … simplified layers -- ubuntu base image … ] 68bad08eb200: Pull complete [ … simplified layers -- cuda 7.0 toolkit … ] Status: Downloaded newer image for nvidia/cuda:7.0 nvcc: NVIDIA (R) Cuda compiler driver Copyright (c) 2005-2015 NVIDIA Corporation Built on Mon_Feb_16_22:59:02_CST_2015 Cuda compilation tools, release 7.0, V7.0.27
由于系統(tǒng)上本地只有 nvidia/cuda:7.5 映像,所以上面的 docker run 命令將 pull 和 run 操作合并在一起。您會注意到, nvidia/cuda:7.0 圖像的拉動比 7 。 5 圖像的拉動要快。這是因為兩個容器映像共享相同的基礎 ubuntu14 。 04 映像,該映像已經(jīng)存在于主機上。 Docker 緩存并重用圖像層,因此只下載 CUDA 7 。 0 工具包所需的新層。這一點很重要: Docker 鏡像是逐層構(gòu)建的,可以與多個鏡像共享,節(jié)省主機上的磁盤空間(以及部署時間)。 Docker 映像的這種可擴展性是一個強大的特性,我們將在本文后面討論。(了解更多 Docker 的分層文件系統(tǒng) )。
最后,您可以通過運行一個執(zhí)行 bash shell 的容器來探索開發(fā)映像。
nvidia-docker run --rm -ti nvidia/cuda:7.5 bash
在這個沙盒環(huán)境中盡情玩耍吧。您可以通過 apt 安裝軟件包或檢查 /usr/local/cuda 中的 CUDA 庫,但請注意,退出( ctrl + d 或 exit 命令)時,對正在運行的容器所做的任何更改都將丟失。
這種非持久性實際上是 Docker 的一個特性。 Docker 容器的每個實例都從映像定義的相同初始狀態(tài)開始。在下一節(jié)中,我們將研究一種擴展和向圖像添加新內(nèi)容的機制。
構(gòu)建應用程序
讓我們在容器中構(gòu)建 deviceQuery 應用程序,方法是用應用程序的層擴展 CUDA 映像。一種用于定義層的機制是 Dockerfile 。 Dockerfile 就像一個藍圖,文件中的每一條指令都會給圖像添加一個新的層。讓我們看看 deviceQuery 應用程序的 Dockerfile 。
# FROM defines the base image FROM nvidia/cuda:7.5 # RUN executes a shell command # You can chain multiple commands together with && # A \ is used to split long lines to help with readability # This particular instruction installs the source files # for deviceQuery by installing the CUDA samples via apt RUN apt-get update && apt-get install -y --no-install-recommends \ cuda-samples-$CUDA_PKG_VERSION && \ rm -rf /var/lib/apt/lists/* # set the working directory WORKDIR /usr/local/cuda/samples/1_Utilities/deviceQuery RUN make # CMD defines the default command to be run in the container # CMD is overridden by supplying a command + arguments to # `docker run`, e.g. `nvcc --version` or `bash` CMD ./deviceQuery
有關(guān)可用Dockerfile
指令的完整列表,請參閱碼頭工人。
在只有 Dockerfile 的文件夾中運行以下docker build
命令,從 Dockerfile 藍圖構(gòu)建應用程序的容器映像。
nvidia-docker build -t device-query .
這個命令生成一個名為 device-query 的 docker 容器映像,它繼承了 CUDA 7 。 5 開發(fā)映像的所有層。
運行集裝箱化 CUDA 應用程序
我們現(xiàn)在準備在 GPU 上執(zhí)行 device-query 容器。默認情況下, nvidia-docker 將主機上的所有 GPUs 映射到容器中。
ryan@titanx:~$ nvidia-docker run --rm -ti device-query ./deviceQuery Starting... CUDA Device Query (Runtime API) version (CUDART static linking) Detected 2 CUDA Capable device(s) Device 0: "GeForce GTX TITAN X" CUDA Driver Version / Runtime Version 8.0 / 7.5 CUDA Capability Major/Minor version number: 5.2 Total amount of global memory: 12287 MBytes (12883345408 bytes) (24) Multiprocessors, (128) CUDA Cores/MP: 3072 CUDA Cores [... simplified output …] Device 1: "GeForce GTX TITAN X" CUDA Driver Version / Runtime Version 8.0 / 7.5 CUDA Capability Major/Minor version number: 5.2 Total amount of global memory: 12288 MBytes (12884705280 bytes) (24) Multiprocessors, (128) CUDA Cores/MP: 3072 CUDA Cores [... simplified output …] > Peer access from GeForce GTX TITAN X (GPU0) -> GeForce GTX TITAN X (GPU1) : Yes > Peer access from GeForce GTX TITAN X (GPU1) -> GeForce GTX TITAN X (GPU0) : Yes deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 8.0, CUDA Runtime Version = 7.5, NumDevs = 2, Device0 = GeForce GTX TITAN X, Device1 = GeForce GTX TITAN X Result = PASS
nvidia-docker
還通過NV_GPU
環(huán)境變量提供資源隔離功能。下面的示例在 GPU 1 上運行device-query
容器。
ryan@titanx:~$ NV_GPU=1 nvidia-docker run --rm -ti device-query ./deviceQuery Starting... CUDA Device Query (Runtime API) version (CUDART static linking) Detected 1 CUDA Capable device(s) Device 0: "GeForce GTX TITAN X" CUDA Driver Version / Runtime Version 8.0 / 7.5 CUDA Capability Major/Minor version number: 5.2 Total amount of global memory: 12288 MBytes (12884705280 bytes) (24) Multiprocessors, (128) CUDA Cores/MP: 3072 CUDA Cores [... simplified output …] deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 8.0, CUDA Runtime Version = 7.5, NumDevs = 1, Device0 = GeForce GTX TITAN X Result = PASS
因為我們只將 GPU 1 映射到容器中, deviceQuery 應用程序只能看到并報告一個 GPU 。資源隔離允許您指定允許您的容器化應用程序使用哪個 GPUs 。為獲得最佳性能,請確保在選擇 GPUs 的子集時考慮到 PCI 樹的拓撲結(jié)構(gòu)。
集裝箱 GPU
在我們目前的例子中,我們在一個有兩個 GPUs NVIDIA X Titan 的工作站上構(gòu)建并運行 device-query 。現(xiàn)在,讓我們在 DGX-1 服務器上部署該容器。部署容器是將容器映像從構(gòu)建位置移動到運行位置的過程。部署容器的多種方法之一是 碼頭樞紐 ,這是一種云服務,用于承載容器映像,類似于 Github 托管 git 存儲庫的方式。我們用來構(gòu)建 device-query 的 nvidia/cuda 映像由 Docker Hub 托管。
在將 device-query 推送到 DockerHub 之前,我們需要用 DockerHub 用戶名/帳戶對其進行標記。
ryan@titanx:~$ nvidia-docker tag device-query ryanolson/device-query
現(xiàn)在將標記的圖像推送到 Docker Hub 很簡單。
ryan@titanx:~/docker/blog-post$ nvidia-docker push ryanolson/device-query The push refers to a repository [docker.io/ryanolson/device-query] 35f4e4c58e9f: Pushed 170db279f3a6: Pushed 3f6d94182a7e: Mounted from nvidia/cuda [ … simplifed multiple ‘from nvidia/cuda’ layers … ]
對于使用 Docker Hub 或其他容器托管存儲庫的替代方法,請查看 docker save 和 docker load 命令。
我們推送到 Docker Hub 的 device-query 映像現(xiàn)在可供世界上任何支持 Docker 的服務器使用。為了在我實驗室的 DGX-1 上部署 device-query ,我只需拉取并運行映像。這個例子使用了 CUDA 8 。 0 候選版本,現(xiàn)在您可以通過加入 NVIDIA 加速計算開發(fā)人員計劃 來訪問它。
lab@dgx-1-07:~$ nvidia-docker run --rm -ti ryanolson/device-query Using default tag: latest latest: Pulling from ryanolson/device-query 6c953ac5d795: Already exists [ … simplified multiple ‘a(chǎn)lready exists’ layers … ] 1cc994928295: Pull complete a9e6b6393938: Pull complete Digest: sha256:0b42703a0785cf5243151b8cba7cc181a6c20a3c945a718ce712476541fe4d70 Status: Downloaded newer image for ryanolson/device-query:latest ./deviceQuery Starting... CUDA Device Query (Runtime API) version (CUDART static linking) Detected 8 CUDA Capable device(s) Device 0: "Tesla P100-SXM2-16GB" CUDA Driver Version / Runtime Version 8.0 / 7.5 CUDA Capability Major/Minor version number: 6.0 Total amount of global memory: 16281 MBytes (17071669248 bytes) (56) Multiprocessors, (64) CUDA Cores/MP: 3584 CUDA Cores [... simplified output … ] Device 7: "Tesla P100-SXM2-16GB" CUDA Driver Version / Runtime Version 8.0 / 7.5 CUDA Capability Major/Minor version number: 6.0 Total amount of global memory: 16281 MBytes (17071669248 bytes) (56) Multiprocessors, (64) CUDA Cores/MP: 3584 CUDA Cores [ … simplified output … ] deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 8.0, CUDA Runtime Version = 7.5, NumDevs = 8, Device0 = Tesla P100-SXM2-16GB, Device1 = Tesla P100-SXM2-16GB, Device2 = Tesla P100-SXM2-16GB, Device3 = Tesla P100-SXM2-16GB, Device4 = Tesla P100-SXM2-16GB, Device5 = Tesla P100-SXM2-16GB, Device6 = Tesla P100-SXM2-16GB, Device7 = Tesla P100-SXM2-16GB Result = PASS
Docker for Deep Learning 和 HPC
既然您已經(jīng)了解了構(gòu)建和運行一個簡單的 CUDA 應用程序是多么容易,那么運行更復雜的應用程序(如 DIGITS 或 Caffe )有多困難?如果我告訴你這就像一個命令那么簡單呢?
nvidia-docker run --name digits --rm -ti -p 8000:34448 nvidia/digits
這個命令啟動 nvidia/digits 容器,并將運行 DIGITS web 服務的容器中的 34448 端口映射到主機上的端口 8000 。
如果您在閱讀本文的同一臺機器上運行該命令,那么現(xiàn)在嘗試打開 http://localhost:8000 。如果在遠程計算機上執(zhí)行 nvidia-docker 命令,則需要訪問該計算機上的端口 8000 。如果可以直接訪問遠程服務器,只需將 localhost 替換為遠程服務器的主機名或 IP 地址。
只需一個命令,就可以啟動并運行 NVIDIA 的數(shù)字平臺,并且可以從瀏覽器訪問,如圖 3 所示。
圖 3 這個屏幕截圖顯示了一個本地 web 瀏覽器連接到遠程主機上的容器中運行的數(shù)字,使用 ssh 隧道進行轉(zhuǎn)發(fā)本地主機: 8000 到運行容器的遠程主機上的端口 8000 。(點擊查看更大的屏幕截圖。)
這就是為什么我們喜歡 NVIDIA 的 Docker 。作為 DIGITS 等開源軟件的開發(fā)人員,我們希望像您這樣的用戶能夠以最小的努力使用我們最新的軟件。
而且我們并不是唯一的一家:谷歌和微軟分別使用我們的 CUDA 圖片作為 TensorFlow 和 CNTK 的基礎圖片。 Google 提供 TensorFlow 的預構(gòu)建 Docker 映像 通過他們的公共容器存儲庫,而微軟 為 CNTK 提供 Dockerfile 則可以自己構(gòu)建。
讓我們看看啟動一個更復雜的應用程序有多容易,比如 TensorFlow ,它需要 NumPy 、 Bazel 和無數(shù)其他依賴項。是的,只是一條線!您甚至不需要下載和構(gòu)建 TensorFlow ,您可以直接使用 Docker Hub 上提供的圖像。
nvidia-docker run --rm -ti tensorflow/tensorflow:r0.9-devel-gpu
運行此命令后,您可以通過運行其包含的 MNIST 訓練腳本來測試 TensorFlow :
nvidia-docker run --rm -ti tensorflow/tensorflow:r0.9-devel-gpu root@ab5f46ba17d2:~# python -m tensorflow.models.image.mnist.convolutional [tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcublas.so locally [tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcudnn.so locally [tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcufft.so locally [tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcuda.so locally [tensorflow/stream_executor/dso_loader.cc:108] successfully opened CUDA library libcurand.so locally Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes. Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes. Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes. Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes. [...]
今天就開始使用 NVIDIA Docker
在這篇文章中,我們通過擴展 nvidia/cuda 映像并在多個不同的平臺上部署我們的新容器,介紹了在容器中構(gòu)建 GPU 應用程序的基本知識。當您將您的 GPU 應用程序容器化時,請使用下面的注釋與我們聯(lián)系,以便我們可以將您的項目添加到 使用 nvidia-docker 的項目列表 。
關(guān)于作者
Ryan Olson 是 NVIDIA 全球現(xiàn)場組織的解決方案架構(gòu)師。他的主要職責包括支持深度學習和高性能計算應用程序。
Jonathan Calmels 是 NVIDIA 的系統(tǒng)軟件工程師。他的工作主要集中在 GPU 數(shù)據(jù)中心軟件和用于深度學習的超大規(guī)模解決方案。喬納森擁有計算機科學與工程碩士學位。
Felix Abecasis 是 NVIDIA 的系統(tǒng)軟件工程師,致力于使 GPU 應用程序更易于在數(shù)據(jù)中心部署和管理。 GPU 專注于機器學習支持框架。他擁有法國學校 EPITA 的計算機科學碩士學位。
Phil Rogers 是 NVIDIA 計算服務器產(chǎn)品的首席軟件架構(gòu)師。 Phil 現(xiàn)在主要關(guān)注的是 DGX-1 的系統(tǒng)軟件,以及 GPU ——加速容器,用于將應用程序傳送到該服務器。
審核編輯:郭婷
-
NVIDIA
+關(guān)注
關(guān)注
14文章
4986瀏覽量
103066 -
gpu
+關(guān)注
關(guān)注
28文章
4740瀏覽量
128951
發(fā)布評論請先 登錄
相關(guān)推薦
評論