Docker超详细教程

简介

Docker的诞生,让应用的部署变得前所未有的高效,它能将应用及其依赖项打包成容器分发部署,从而保证了应用运行环境的一致性。Docker容器其实是一种比虚拟机更轻量的技术,容器中的进程直接运行在宿主机的内核,其启动速度十分快,基本可以做到秒级启动,并不像虚拟机那样对硬件进行模拟,并在之上运行一整套操作系统,所以容器相比虚拟机更为轻便。


理解Docker

Docker有三个基本概念:仓库(Repository),镜像(Image)和容器(Container)。

  • 仓库(Repository) 是一个集中存放镜像的空间。我们写的代码可以上传到Github仓库中,类似的,Docker的镜像就能上传到Docker Hub仓库,以便镜像的分发部署。Docker Hub是官方的公开服务,每个账号可以建立一个免费的私有仓库。
  • 镜像(Image) 是一个特殊的文件系统,其中存储了应用和环境的所有数据,镜像在构建之后是静态的,不可改变的。
  • 容器(Container) 是镜像的运行实体,类似于面向对象编程中的实例,一个静态的镜像可以产生多个独立动态运行的容器。我们实际使用Docker就是在容器中运行自己的应用,每个容器都有自己独立的运行空间,与宿主系统环境隔绝。

快速上手Docker

为了让读者能快速上手Docker,下面以一个实际应用进行说明,让我们从易到难,先假设目前已经构建好一个镜像,后面我们会具体讲如何构建这个镜像。读者可以跟随本文实际操作,学习效果会更佳。

一、安装Docker

本文以Ubuntu系统安装Docker CE版本为例,更详细的其他版本安装步骤可以参考Docker官网文档

  1. 卸载旧版本
1
sudo apt-get remove docker docker-engine docker.io containerd runc
  1. 安装依赖包
1
2
3
4
5
6
7
sudo apt-get update
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
  1. 添加GPG key,并设置stable版本的仓库
1
2
3
4
5
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
  1. apt-get安装
1
2
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
  1. 验证安装结果
1
sudo docker run --rm hello-world

--rm参数代表我们运行后随即删除这个容器,因为我们只需要这个容器输出一段信息而已。

执行后会输出类似这样的信息,说明已经安装成功:

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:

  1. The Docker client contacted the Docker daemon.
  2. The Docker daemon pulled the “hello-world” image from the Docker Hub.
    (amd64)
  3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
  4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

For more examples and ideas, visit:
https://docs.docker.com/get-started/

  1. 免sudo运行
    每次运行docker都要加一个sudo挺麻烦,我们将当前账号加入Docker组里面即可免sudo运行Docker:
1
2
3
4
sudo groupadd docker
sudo gpasswd -a ${USER} docker
sudo service docker restart
newgrp - docker

二、镜像操作

1、获取Docker镜像

笔者在Ubuntu 16.04镜像的基础上,制作了一个很简单的Docker镜像,里面有一个my_clock.pyPython文件,执行后就会间隔一秒钟输出一次当前系统时间。此镜像我已经上传到自己的Docker Hub公共仓库中,任何人都可以随时下载,执行以下命令即可将此镜像下载到本地:

1
docker pull chasonlee/ubuntu_demo:latest

其中chasonlee/ubuntu_demo是镜像名字,latest是镜像的标签Tag,不同的Tag代表不同的版本,执行后会显示如下信息:

1
2
3
4
5
6
7
8
9
latest: Pulling from chasonlee/ubuntu_demo
9ff7e2e5f967: Pull complete
59856638ac9f: Pull complete
6f317d6d954b: Pull complete
a9dde5e2a643: Pull complete
583e635329f1: Pull complete
d74dae086c4f: Pull complete
Digest: sha256:f4396916a5cbb3ece8e5eb74a860d956b8957965675d5dde707ed4f316407b8c
Status: Downloaded newer image for chasonlee/ubuntu_demo:latest

从信息中我们可以看出,镜像的下载是一层一层分开的,镜像是分层存储,9ff7e2e5f967是其中一层。Docker有一个优点,不同镜像之间如果基于某些相同的镜像进行定制化修改,就可以共享部分相同的层,从而节省空间的占用。

2、查看本地镜像

执行以下命令可以查看当前所有本地镜像:

1
docker images

执行后就能看到我们刚刚pull回来的镜像和一个之前的hello-world镜像:

1
2
3
REPOSITORY                	TAG                     IMAGE ID            CREATED             	SIZE
chasonlee/ubuntu_demo latest 59693b89568e 2 minutes ago 158MB
hello-world latest fce289e99eb9 4 months ago 1.84kB

可能读者会疑惑为什么有hello-world镜像,因为当我们执行docker run --rm hello-world的时候,在本地找不到hello-world镜像,就会自动到Docker Hub上找到相应镜像下载回来,再根据此镜像来新建并启动容器。

另外,我们也可以查看中间层镜像

1
docker images -a

如果不同镜像之间有复用的中间层,这里就会看见一些没有镜像名和标签的镜像,很多镜像依赖这些中间层,所以中间层镜像是不能随意删除的。

3、删除镜像

当我们想删除一些不需要的镜像时,比如hello-world镜像,可以执行:

1
docker rmi hello-world

如果此时有基于此镜像的容器,则需要先删除相应的容器才能删除此镜像,如果想强制删除镜像,加上-f参数即可:

1
docker rmi -f <image name>

在使用docker images查看本地镜像时(不加-a参数时),我们也可能会发现一些没有镜像名和标签的镜像:

1
2
3
4
REPOSITORY                	TAG                     IMAGE ID            CREATED             	SIZE
chasonlee/ubuntu_demo latest 59693b89568e 2 minutes ago 158MB
hello-world latest fce289e99eb9 4 months ago 1.84kB
<none> <none> 3517732c5437 7 weeks ago 2.74GB

不同于上面提到的中间层镜像,我们称这种镜像为虚悬镜像(dangling image),有几种情况会产生虚悬镜像,比如上述强制删除一个已经运行容器的镜像,或者使用docker pull命令更新镜像时,镜像的名称和标签会转移到新镜像中,旧的镜像就会变成虚悬镜像,另外,在使用docker build构建镜像的时候,如果构建失败也会产生虚悬镜像。一般来说虚悬镜像已经没有实际用处,可以随意删除,一条命令就能清除所有虚悬镜像:

1
docker image prune

4、导出镜像

上文中我们用docker pull命令将镜像从Docker Hub下载到本地,如果目标环境不能访问外网时无法下载,我们就可以直接导出镜像文件:

1
docker save -o ubuntu_demo.tar chasonlee/ubuntu_demo
  • -o参数后面接着输出文件名。
  • chasonlee/ubuntu_demo是需要导出的镜像名。

注意:这里只是导出一个静态的镜像,根据当前镜像启动的容器环境并不能直接导出,如果需要迁移当前容器的环境,还需要先使用commit命令自行制作一个镜像再导出,详情可跳转到理解commit章节阅读。

假如镜像文件很大,可以直接压缩导出镜像:

1
docker save chasonlee/ubuntu_demo:latest | gzip > ubuntu_demo.tar.gz

5、导入镜像

然后拷贝此镜像文件到目标环境中,并导入镜像:

1
docker load -i ubuntu_demo.tar

或者直接导入压缩后的镜像:

1
gunzip -c ubuntu_demo.tar.gz | docker load

导入后可以即可通过docker images查看镜像。

6、修改镜像名称及标签

如果我们想把镜像名称改为ubuntu_chason:1.0,则执行:

1
docker tag chasonlee/ubuntu_demo:latest ubuntu_chason:1.0

三、容器操作

1、新建并启动容器

前面我们有讲过,镜像是静态的,容器才是实际运行的实体,Docker可以基于某个镜像新建容器。可以这么理解,用一个镜像来初始化新建的容器。容器运行之后的所有变化都不会反过来影响镜像,容器在运行终止后,里面新产生的数据将会随之丢弃。

为了方便,我们通常会新建容器并让其后台持续运行:

1
docker run -dit --name my_ubuntu chasonlee/ubuntu_demo:latest
  • -dit有三个参数,其顺序没有影响,-t能让Docker分配一个伪终端,并绑定到容器的输入上,-i能让容器的标准输入保持打开状态,-d则可以让容器在后台保持运行。
  • --name my_ubuntu可以为容器命名,方便自己管理。
  • chasonlee/ubuntu_chason:latest是初始化容器的镜像名加标签Tag。

执行后就会打印一行此容器的ID,说明容器已经成功在后台运行。

另外,我们也可以在让容器一次性运行一条命令:

1
docker run --rm chasonlee/ubuntu_demo:latest echo "hello world"
  • --rm我们之前解释过,是为了容器停止后直接删除,避免留下一个已经停止的容器。

这条命令看起来和我们在本地直接运行echo "hello world"并没有什么区别,我们只是在容器中执行了echo指令,输出结果,容器就停止了。

或者我们也可以直接运行容器的bash终端:

1
docker run -it --rm chasonlee/ubuntu_demo:latest bash

执行本命令就会看到容器的伪终端,此时我们就继续在容器中执行命令,要注意的是,当我们执行exit退出容器时,容器就会停止,--rm参数会在容器停止后直接删除容器。

2、查看容器

执行以下命令可以查看所有容器及其状态:

1
docker ps -a

执行后会输出以下类似信息:

1
2
CONTAINER ID	IMAGE				COMMAND		CREATED		STATUS		PORTS	NAMES
d346805da373 chasonlee/ubuntu_demo:latest "/bin/bash" 2 minutes ago Up 2 minutes my_ubuntu

可见my_ubuntu就是我们新建好的容器,Up 2 minutes代表容器正在后台运行,已经运行2分钟。

3、进入容器

执行以下命令即可进入容器中的bash:

1
docker exec -it my_ubuntu bash
  • -it和前面一样代表打开标准输入和分配伪终端。
  • my_ubuntu是要进入容器的名字,我们如果换成容器IDd346805da373也是一样的,但使用名字肯定更方便直观。
  • 最后的参数代表我们需要容器执行的命令,我们需要交互式的Shell,所以这里输入bash,如果我们只需要执行容器里面的一个命令,可以将bash替换成想执行的命令即可。

执行后即可进入容器中:

或者执行docker attach my_ubuntu也可以进入容器,但不推荐使用,原因后面会讲。

容器里面是独立的系统环境,我已经配置默认采用Python3,并在workspace中存放my_clock.py文件,执行:

1
python my_clock.py

程序会每隔一秒在界面中打印系统时间:

我还在容器中安装了htop工具,用于查看CPU、内存使用情况,执行htop即可查看:

简单的程序可以如上直接在容器中运行,虽然我们在运行容器时加入了-d参数能保持程序一直运行,但我们无法在重新进入容器时看到程序以前输出的结果。如果需要长时间保持程序的运行,笔者还是推荐在容器中使用tmux,tmux教程在这里

4、退出容器

退出容器很简单,直接执行:

1
exit

即可回到系统bash中,现在再用docker ps -a查看容器状态,依旧是Up运行状态:

1
2
CONTAINER ID	IMAGE		COMMAND		CREATED			STATUS		PORTS	NAMES
d346805da373 59693b89568e "/bin/bash" 10 minutes ago Up 10 minutes my_ubuntu

这是因为我们进入容器时使用的是docker exec命令,如果我们使用的是docker attach命令,退出容器后,容器将会停止运行:

1
2
CONTAINER ID	IMAGE		COMMAND		CREATED		STATUS                     PORTS	NAMES
d346805da373 59693b89568e "/bin/bash" 10 minutes ago Exited (1) 4 seconds ago my_ubuntu

5、启动停止容器

容器停止时,可以启动容器:

1
docker start my_ubuntu

容器正在运行时,也可以停止容器:

1
docker stop my_ubuntu

6、删除容器

当容器已经停止时,可以直接删除容器:

1
docker rm my_ubuntu

当容器还在运行,可以强制删除容器:

1
docker rm -f my_ubuntu

如果当前有很多已经停止的容器,一个命令即可清空所有已停止容器:

1
docker container prune

7、导出容器快照(不推荐)

类似镜像的导出,我们同样可以导出容器快照:

1
docker export my_ubuntu > my_ubuntu.tar

容器快照会丢弃所有的历史记录和元数据信息,仅保存容器当时的快照状态。

8、导入容器快照(不推荐)

有了容器快照文件,即可将容器快照导入新的镜像中:

1
docker import my_ubuntu.tar my_ubuntu:1.0
  • my_ubuntu.tar是容器快照。
  • my_ubuntu:1.0是新镜像名和标签TAG,若不写TAG,默认为latest
    注意,是导入到镜像中,而不是直接新建一个容器。

9、挂载目录

当我们需要访问宿主机的数据时,就需要把宿主机目录挂载到容器中,在新建容器时使用docker run -v参数即可挂载目录,例如:

1
docker run -dit --name my_ubuntu -v /hdd:/workspace/hdd chasonlee/ubuntu_demo:latest
  • -v代表挂载目录,宿主机目录和容器目录用:分开,如果需要挂载多个目录,继续多写几个-v及其对应目录即可。
  • /hdd是宿主机目录,必须是绝对路径。
  • /workspace/hdd是容器里面映射的目录,必须是绝对路径,如果目录不存在会自动创建。

至此阶段,相信读者已经掌握了docker的基本使用方法,接下来将会介绍如何制作自定义的镜像。


镜像制作

Docker Hub中,除了笔者举例的镜像,我们还可以搜索到其他很多高质量的镜像,例如Ubuntu官方镜像TensorFlow官方镜像等等。有了这些镜像,我们就没有必要重复造轮子,若这些镜像无法完全满足需求,我们只需要基于这些镜像做一些定制化的修改即可。

一、理解commit

镜像的制作,有一种最简单快速的方式是docker commit,只需在某个镜像基础上,启动容器,并在容器中安装自己需要的环境,即可将此容器commit到一个新的镜像中。

基本语法:

1
docker commit [可选项] 容器 [镜像[:标签]]
  • 可选项包括:
    -a (–author string): 镜像制作者信息,如"chason.me"
    -c (–change list): 使用Dockerfile指令来创建镜像
    -m (–message string): 提交时的说明信息
    -p (–pause): 在commit时,将容器暂停,默认为True
  • 容器可以写容器名或容器ID
  • 镜像[:标签]代表你要新建的镜像和标签名

假如我们已经在容器my_ubuntu中安装好一切需要的环境,退出容器后,执行:

1
docker commit -a "chason.me" -m "new environment" my_ubuntu chason_env:latest

即可创建一个名为chason_env:latest镜像,导出此镜像即可将环境迁移至其他机器使用。

需要提醒的是,docker commit虽然很方便,但并不推荐使用,因为在容器中的每一次操作我们都可能产生很多临时文件,造成镜像越来越臃肿,而且每次操作无法回溯,我们很难知道这个镜像到底执行过什么命令,导致镜像难以维护。

那是否存在一种方法,能让镜像的修改操作透明、同时又能解决臃肿问题呢?当然有,答案就是Dockerfile

二、学习Dockerfile

Dockerfile是一个文本文件,包含了镜像构建的所有命令,通过修改Dockerfile中的命令,就能定制化自己想要的镜像。Dockerfile里面每一个指令都会构建一层镜像,层层叠加最终得到定制化镜像。

1、基本指令

让我们重新回到原来的例子,chasonlee/ubuntu_demo镜像是如何构建的呢?

首先我们在本地新建一个文件夹,专门存放Dockerfile和其他所需文件,并在里面新建my_clock.py程序以及Dockerfile文件:

1
2
3
mkdir my_docker
cd my_docker
vim my_clock.py

在Python文件中输入持续打印当前时间的代码:

1
2
3
4
5
# coding: utf-8
import time
while True:
print (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
time.sleep(1)

保存代码后,在同样的目录下新建Dockerfile文件:

1
vim Dockerfile

输入以下Dockerfile指令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM ubuntu:16.04
ENV WORK_DIR=/workspace
WORKDIR ${WORK_DIR}
COPY . ${WORK_DIR}
RUN apt update \
&& apt install -y python3 \
&& apt install -y htop \
&& apt install -y tzdata \
&& apt-get clean \
&& apt-get autoclean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
&& ln -s /usr/bin/python3 /usr/bin/python \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&& echo 'Asia/Shanghai' >/etc/timezone \
  • FROM指令代表基于哪个镜像进行修改,第一条指令必须是FROM指令,若我们不想基于任何镜像,可以写FROM scratch即可完全从零开始构建镜像。
  • ENV指令可以创建环境变量,比如WORK_DIR工作目录环境变量,后面就能通过${WORK_DIR}调用环境变量的值。
  • COPY指令可以将宿主机中的文件在构建镜像时复制到镜像存储中。
  • WORKDIR指令可以指定工作目录,在刚进入容器时,系统会自动转到工作目录,默认的工作目录是根目录/
  • RUN指令就是用来执行命令的指令,由于一条指令就会创建一层镜像,而镜像层数是有限制的,一般是127层,当我们需要执行多条命令时,一般都用&&连接多条命令,从而节省镜像层数。

现在我们逐条命令讲解以上Dockerfile的内容:

  1. 首先是基于ubuntu:16.04镜像开始构建
  2. 设置环境变量WORK_DIR为/workspace
  3. 设置工作目录为WORK_DIR
  4. 复制宿主机当前目录所有文件到镜像WORK_DIR目录中,包含Dockerfilemy_clock.py
  5. 更新apt列表
  6. 安装Python3,-y代表默认同意安装,这样就不需要手动输入y确认安装。
  7. 安装htop工具
  8. 安装tzdata时间工具
  9. 清除临时软件包
  10. 清除临时软件包
  11. 清除临时文件
  12. 将python软连接到python3
  13. 将系统默认时区设置为亚洲上海
  14. 将系统默认时区设置为亚洲上海

从Dockerfile可见,整个镜像的构建过程都是透明的、清晰的,为了避免镜像过于臃肿,需要时刻记得清除无用的数据,否则镜像的大小容易失去控制。

定制自己的镜像就是写一份Dockerfile,把想要的程序或工具的安装命令直接写入Dockerfile即可,比如想用tmux的读者,在Dockerfile里面插入apt install -y tmux即可。

2、拓展指令

ADD指令

ADD指令和COPY类似,但包含更多功能,比如可以从一个网址下载文件到目标目录中(下载后文件默认权限是600),另外一个常用的功能是自动解压,支持gzip、bzip2和xz压缩格式,比如ADD file.tar /会将压缩包解压到目标路径中。

由于ADD指令语义不够清晰,除了需要自动解压的情况,我们一般都不推荐使用ADD指令。

CMD指令

运行格式:CMD ["可执行文件", "参数1", "参数2"...]

CMD指令可以用来指定容器默认的运行命令,比如之前我们提到可以这样直接执行容器的bash指令:

1
docker run -it --rm chasonlee/ubuntu_demo:latest bash

其实后面的bash不写也行,因为ubuntu:16.04镜像中已经用CMD指令设置好默认命令为bash

若我们在Dockerfile中加入CMD ["python","my_clock.py"],重新构建镜像后,运行容器时后面不加任何命令,就会默认执行python my_clock.py

1
docker run -it --rm chasonlee/ubuntu_demo:latest

执行后就会每隔一秒钟输出一次系统时间。若我们在后面加入其它命令,就会替换默认的命令。

敬请期待…

  • ENTRYPOINT
  • ARG
  • VOLUME
  • EXPOSE
  • USER
  • HEALTHCHECK
  • ONBUILD

三、构建镜像

完成Dockerfile之后,便可在Dockerfile的目录中直接构建镜像:

1
docker build -t ubuntu_demo:latest .
  • ubuntu_demo:latest是构建的镜像名和标签,如需上传到Docker Hub,可以修改为<user name>/<image name>:<tag>形式。
  • .最后一个参数指向Dockerfile所在的目录,这里是当前目录。

执行后就会开始根据Dockerfile的内容构建镜像,需要等待一段时间,联网下载的部分命令耗时会比较长,读者如果需要安装TensorFlow之类安装包较大的库时,建议先下载好本地whl文件,用COPY命令复制到镜像中,用RUN命令安装并把whl文件删除。

如果构建失败,请查看Dockerfile中的命令是否有问题。如果成功,恭喜你已经掌握了基本的镜像构建方法!

执行docker images即可查看刚刚构建成功的镜像。


Docker Hub使用

首先请到Docker Hub官网注册一个账号,每个账号都有一个免费的私有仓库,无限个公有仓库,私有仓库只有你自己能看到,如有需要可以购买更多私有仓库。

一、登陆登出Docker Hub

如果需要上传镜像到自己的Docker Hub,需要先在bash中登陆:

1
docker login

之后输入自己的账号密码即可。

若需要登陆其他平台的仓库,在后面加上网址即可:

1
docker login <url>

需要登出时可执行:

1
docker logout

若需要登陆其他账号,可以加入-u参数,-p可以输入密码:

1
docker login -u 用户名 -p 密码

二、上传镜像

与下载镜像pull相反,上传镜像用push命令:

1
docker push <user name>/ubuntu_demo:latest
  • <user name>是自己的用户名,如果构建镜像时,镜像名称前面忘记加用户名,请用docker tag命令修改。

镜像上传需要一定时间,取决于镜像大小和网速。上传成功后镜像默认存在私有仓库中,在SettingMake public即可转为公开的仓库。


nvidia-docker

Docker支持CUDA环境的隔绝,这是深度学习算法框架使用者的福音,因为TensorFlow的不同版本可能需要不同CUDA版本,这导致无法用virtualenv在同一台机安装多个版本跨度较大的TensorFlow,有了Docker,这种问题就能迎刃而解。

基于前面的内容,读者可能会发现,在之前启动的Docker容器里面并不能执行nvidia-smi命令,无法使用GPU版本的TensorFlow或PyTorch。不用着急,现在我们开始学习如何配置一个带NVIDIA的Docker,只需在安装Docker的基础之上,继续安装nvidia-docker2即可,具体可参考nvidia-docker说明,主要包含以下几个步骤:

一、卸载旧版nvidia-docker

If you have nvidia-docker 1.0 installed: we need to remove it and all existing GPU containers

1
2
docker volume ls -q -f driver=nvidia-docker | xargs -r -I{} -n1 docker ps -q -a -f volume={} | xargs -r docker rm -f
sudo apt-get purge -y nvidia-docker

二、添加包源

Add the package repositories

1
2
3
4
5
6
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | \
sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \
sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update

三、安装nvidia-docker2

Install nvidia-docker2 and reload the Docker daemon configuration

1
2
sudo apt-get install -y nvidia-docker2
sudo pkill -SIGHUP dockerd

四、测试nvidia-docker

安装完成后,我们可以在启动容器的命令前面加上nvidia-即可启动支持GPU的Docker

首先,我们需要先下载一个自带CUDA的镜像,读者可以在DockerHub里面自行寻找,或尝试这个:

1
docker pull nvidia/cuda:10.0-base-ubuntu16.04

镜像拉回本地后,即可使用nvidia-docker命令创建容器:

1
nvidia-docker run -dit --name my_ubuntu_gpu nvidia/cuda:10.0-base-ubuntu16.04

等同于加--runtime=nvidia,这种新的用法只有nvidia-docker v2支持:

1
docker run --runtime=nvidia -dit --name my_ubuntu_gpu nvidia/cuda:10.0-base-ubuntu16.04

为了加以区分,容器名后面加上了_gpu,进入容器的方法不变:

1
docker exec -it my_ubuntu_gpu bash

现在进入容器后即可执行nvidia-smi查看GPU状态。

注意:nvidia-docker只是能让Docker支持GPU而已,Docker镜像需要同时带有CUDA才能使用GPU,如上面的nvidia/cuda:10.0-base-ubuntu16.04镜像,我们可以基于此定制自己的镜像。另外,也可以基于不带CUDA的镜像,先下载好CUDA安装包,然后在Dockerfile里面写好安装的命令,在构建镜像的过程中安装好CUDA(安装cuDNN也是同样的思路)。


结束语

我们从镜像到容器、从运行到构建、从CPU到GPU,一步步学完了Docker的基本使用方法。笔者在本文以实例的方式讲述Docker的使用,是希望读者能以边读边实践方式进行学习,没人可以一次记住所有的命令,熟练的前提是反复不断地练习。另外,本文介绍的内容并非Docker的全部,更多内容有待读者自行探索Docker官网文档,未来我也会持续更新。

您的支持将鼓励我继续创作!