跳转至

Docker命令行接口

在前一篇文章当中,我们运行了最简单的hello-world程序。在本文当中,我将介绍常用的Docker命令。需要注意的是,为了避免重复的讨论,我们将会在一个命令当中使用尽可能多的参数。实际生产环境当中,这些参数可能无需用到。

创建容器

首先,让我们再创建一个容器。

Text Only
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
docker run -dit \
    --name=test \
    --label color=blue \
    -v <HOST-PATH>:<CONTAINER-PATH> \
    -v <VOLUME-NAME>:<CONTAINER-PATH>:ro \
    --mount type=bind,source=<HOST-PATH>,target=<CONTAINER-PATH> \
    --mount type=volume,source=<VOLUME-NAME>,target=<CONTAINER-PATH>,readonly \
    -p 127.0.0.1:81:80/tcp \
    --cpuset="0-1" \
    -m 4096m \
    -e AUTHOR="Zhiyuan Chen" \
    --net="bridge"
    10.1-cudnn7-devel-ubuntu18.04:latest

不要担心,正如我们之前说的,本文撰写过程当中使用了尽可能多的常用参数,以免重复讨论。实际应用当中的Docker命令要比这小许多。接下来,让我们一个一个解释参数的意思。

首先,从 -dit 开始。

-d 让容器后台运行,只在开始运行后返回一个容器ID

-i 让容器的标准输入保持常开

-t 让docker为容器分配一个虚拟终端(pseudo-tty),并绑定到容器的标准输入上

通常情况下,我们都会使用 -dit 选项。当然,开发阶段如果需要对容器进行一些调整的话,我们可能会省略 -d 而直接使用 -it。

–name 指定这个容器的名字。

–label 指定这个容器的标签。我们通常会根据容器类型或者其他来给容器设置标签,方便日后查找。标签看似简单实则很深。无论是一个容器、一个镜像还是一个数据卷,甚至是一个守护进程都可以被打上标签。想象一下,当你有数万个容器运行的时候,没有正确的分组一定会让你疯掉的。我们会视情况单开一章进行讨论。

-v 和 –mount 都表示挂载。由于一些历史原因,这两个东西代表的功能完全相同,但语法略有差异。在本例当中,我们分别通过 -v 和 –mount 挂在了一个本地文件和一个数据卷到容器当中,其中数据卷均被设置成只读。可以看到,相较而言 -v 要更简洁一些,也是我更推荐大家使用的。有关数据卷的更多内容,我们将会在其他章节讨论。

-p 将容器的80端口绑定到主机127.0.0.1地址的81端口。

–cpuset 指定了容器只使用前两个处理器内核。需要注意的是,和其他程序一样,Docker看到的也是逻辑内核。

-m 或者 –memory 设置了这个容器能使用的最大的内存大小,结尾一般是m或者g。一个容器允许设置的最小内存是4m。有关内存的设置其实有不少,比如 –memory-swap、–memory-reservation 等等。我们会视情况单开一章进行讨论。

-e 指定环境变量。

–net 指定网络类型,本选项在绝大多数情况下无需设置,默认为”bridge”。我们也会视情况单开一章进行讨论。

最后的最后,我们运行了一个预装CUDA 10.1、cuDNN 7的ubuntu 18.04镜像。如果你不打算在你的容器里运行显卡的话,我强烈建议你把这一行替换成alpine:lates。Ubuntu实在是太大了,如果没有特殊需要的话,还是alpine这种小家伙更适合容器一些。我们会在随后单开一章进行讨论。

此时,由于我们之前指定了 -d,什么都不会发生,除了一个返回的容器ID。

查看容器列表

Text Only
1
docker ps -a -f since=hello-world -n 5

-a 或者 –all 显示所有容器,默认只显示运行当中的容器。

-f 或者 –filter 根据指定条件筛选容器。这个内容有点儿多,我们会看情况单开一章进行讨论,或者在日后补充。

-n 或者 –lat 只显示最近创建的五个容器。考虑到这个教程的进度,你应该只能看见一个,所以加与不加也没什么区别。

此外还有一些其他参数,比如 –format 修改展示格式、-s 显示文件大小、-q 只显示容器ID等等,此处不再赘述。

进入容器

综合考虑到我们创建一个容器之后总要做些什么,那么我们首先需要进入容器。

进入容器有很多很多方法,考虑到要紧跟时代的潮流,我们将只讨论目前进入容器的方法–exec。

Text Only
1
docker exec -it test /bin/bash

需要注意的是,如果你之前选择了alpine的话,由于alpine并没有内置bash这种高端的东西(他真的真的很小),你应该把最后一段替换成 /bin/sh。

此外,或许会有些人告诉你最后一段只需要 bash 就好,但我们提倡 不要这么做 !!不要在无所谓的东西上省略,就跟变量名长点儿并没有什么关系,但重点是能让人理解这个变量里存的是什么。

接下来,在容器里稍微玩玩,毕竟,这个容器马上就要被杀掉了。

检视容器情况

Text Only
1
docker stats

监视容器运行消耗了多少资源。这个没什么好说的,当然也不怎么常用,一笔带过吧。

检查点

这是一个实验性功能,请不要在生产环境当中使用! 使用本命令之前需先打开Docker的实验性功能,我们会看情况单开一章进行讨论。

Text Only
1
docker checkpoint create --checkpoint-dir <CHECKPOINT_DIR> --leave-running test CHECKPOINT

启停容器

Text Only
1
2
3
4
docker stop test -t 10
docker start test --checkpoint-dir <CHECKPOINT_DIR>
docker restart test -t 10
docker rm -f -v

在十秒钟之后关闭容器,加载检查点启动容器,在十秒钟之后重启容器,然后彻底删掉容器及其所挂载的数据卷(需要注意的是,如果这个数据卷仍挂载在其他容器上,那他并不会被删除)。


结语

本章我也拖了很久很久。开局到现在连着挖了几个坑都没时间填,事情虽然不是很多但现在真心没有动力去做。在下一篇文章当中我们会讨论Dockerfile,希望不会让你们等太久。