在上一节讲了如何安装docker以及一些配置的更改,本节将会初步介绍docker容器的使用。
1、运行我们的第一个容器
现在, 让我们尝试启动第一个Docker容器。 我们可以使用docker run命令创建容器。docker run命令提供了Docker容
器的创建到启动的功能。
[05:37 shexuan@hulab ~]$ docker run --name bob_the_container -i -t ubuntu /bin/bash
Unable to find image 'ubuntu:latest' locally
Trying to pull repository docker.io/library/ubuntu ...
latest: Pulling from docker.io/library/ubuntu
473ede7ed136: Pull complete
c46b5fa4d940: Pull complete
93ae3df89c92: Pull complete
6b1eed27cade: Pull complete
Digest: sha256:29934af957c53004d7fb6340139880d23fb1952505a15d69a03af0d1418878cb
Status: Downloaded newer image for docker.io/ubuntu:latest
root@9edcf79a4252:/#
上面命令启动运行了一个容器,并指定了多个参数:
-
run
docker run
用来启动一个容器; -
--name
为我们运行的容器指定一个名字,不指定的话则系统会生成一个名称; -
-i
-i
标志保证容器中STDIN是开启的, 尽管我们并没有附着到容器中。 持久的标准输入是交互式shell的“半边天”; -
-t
-t
标志则是另外“半边天”, 它告诉Docker为要创建的容器分配一个伪tty终端; -
/bin/bash
为运行的容器执行的第一个命令,这个命令启动了一个Bash shell。
在很多Docker命令中, 都可以用容器的名称来替代容器ID, 后面我们将会看到。 容器名称有助于分辨容器, 当构建容器和应用程序之间的逻辑连接时, 容器的名称也有助于从逻辑上理解连接关系。 具体的名称(如web、 db) 比容器ID和随机容器名好记多了。 我推荐大家都使用容器名
称, 以更加方便地管理容器。容器的命名必须是唯一的。 如果试图创建两个名称相同的容器, 则命令将会失败。 如果要使用的容器名称已经存在, 可以先用docker rm命令删除已有的同名容器后, 再来创建新的容器。
最后,输入exit
可以退出当前容器。
若想在退出容器后自动删除容器,还可以加上--rm
参数。
如果由于某种错误而导致容器停止运行,还可以通过
--restart
标志,让Docker自动重新启动该容器。--restart
标志会检查容器的退出代码, 并据此来决定是否要重启容器。 默认的行为是Docker不会重启容器。
$ docker run --restart=always --name daemon_dave -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
在本例中, --restart
标志被设置为always
。 无论容器的退出代码是什么, Docker都会自动重启该容器。 除了always
, 还可以将这个标志设为on-failure
, 这样, 只有当容器的退出代码为非0值的时候, 才会自动重启。 另外, on-failure
还接受一个可选的重启次数参数。
# 当容器退出代码为非0时, Docker会尝试自动重启该容器, 最多重启5次。
$ docker run --restart=on-failure:5 --name daemon_dave -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
2、重新启动已经停止的容器
在上面输入exit
后bob_the_container容器已经停止了, 接下来我们能对它做些什么呢? 如果愿意, 我们可以用start
命令重新启动一个已经停止的容器。
[21:03 shexuan@hulab ~]$ docker start bob_the_container
bob_the_container
# 也可以通过ID来指定容器
[21:09 shexuan@hulab ~]$ docker start 22e568aab98b
22e568aab98b
Docker容器重新启动的时候, 会沿用docker run
命令时指定的参数来运行, 因此我们的容器重新启动后会运行一个交互式会话shell。 此外,也可以用docker attach
命令, 重新附着到该容器的会话上。
# 先启动停止了的容器
[21:26 shexuan@hulab ~]$ docker start bob_the_container
bob_the_container
# 使用attach命令重新附着到该容器的会话上
[21:26 shexuan@hulab ~]$ docker attach bob_the_container
root@22e568aab98b:/#
3、创建守护式容器
除了这些交互式运行的容器(interactive container) , 也可以创建长期运行的容器。 守护式容器(daemonized container) 没有交互式会话, 非常适合运行应用程序和服务。
使用-d
参数, Docker会将容器放到后台运行:
[21:33 shexuan@hulab ~]$ docker run --name daemon_dave -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"
42b18316632c701e2ce266e49313cc274963b0bbb2241353da0f11526d403317
上面的命令创建了一个后台运行的容器,我们还在容器里运行了一个while 循环,该循环会一直打印hello world,知道该容器或进程停止运行。
使用docker ps
我们可以看到一个正在运行的容器:
[21:33 shexuan@hulab ~]$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
42b18316632c ubuntu "/bin/sh -c 'while..." 4 minutes ago Up 4 minutes daemon_dave
使用docker logs
可以查看该容器的内部运行情况,或称日志:
[21:40 shexuan@hulab ~]$ docker logs daemon_dave
hello world
hello world
hello world
...
# 加上-f 参数来监控最新日志,这个参数类似于tail -f 命令的作用
[21:40 shexuan@hulab ~]$ docker logs -f daemon_dave
hello world
hello world
hello world
...
# 还可以使用--tail 参数来指定获取日志最后指定行数
[21:45 shexuan@hulab ~]$ docker logs --tail 3 daemon_dave
hello world
hello world
hello world
# 最后你还可以组合使用--tail和-f命令来获取容器的最新日志而不必读取整个日志文件
[21:52 shexuan@hulab ~]$ docker logs --tail 3 -ft daemon_dave
2018-11-06T02:53:01.314952000Z hello world
2018-11-06T02:53:02.316191000Z hello world
2018-11-06T02:53:03.317513000Z hello world
2018-11-06T02:53:04.318959000Z hello world
# -t参数会输出时间戳使得看起来更方便
在上面我们简要介绍了如何使用docker logs
来查看守护式容器的内部运行情况,获取其日志文件:
-
-f
-f
参数类似于tail -f
,会不断刷新输出最新日志; -
--tail
输出日志的最后几行; -
--tail number -f
输出最后指定行数日志并不断刷新输出最新日志; -
-t
给日志加上时间戳。
最后,可以使用docker stop
停止运行守护式容器:
[22:04 shexuan@hulab ~]$ docker stop daemon_dave
daemon_dave
docker stop
和docker kill
都可以停止运行守护式容器,但是略有区别:
docker stop
,支持“优雅退出”。先发送SIGTERM信号,在一段时间之后(10s)再发送SIGKILL信号。Docker内部的应用程序可以接收SIGTERM信号,然后做一些“退出前工作”,比如保存状态、处理当前请求等;docker kill
,发送SIGKILL信号,应用程序直接退出。
更多docker日志配置可查看更改docker的日志引擎为 journald。
4、查看容器内部进程及统计信息
除了容器的日志, 也可以查看容器内部运行的进程。 要做到这一点, 要使用docker top
命令:
[22:31 shexuan@hulab ~]$ docker top daemon_dave
UID PID PPID C STIME TTY TIME CMD
root 10317 10299 0 22:31 ? 00:00:00 /bin/sh -c while true; do echo hello world; sleep 1; done
root 10466 10317 0 22:31 ? 00:00:00 sleep 1
该命令执行后, 可以看到容器内的所有进程(主要还是我们的while循环) 、 运行进程的用户及进程ID。
除了查看进程信息外,还可以通过docker stats
来查看一个或多个容器的统计信息:
[22:37 shexuan@hulab ~]$ docker stats daemon_dave
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
daemon_dave 0.13% 952 KiB / 251.6 GiB 0.00% 648 B / 648 B 0 B / 0 B 2
我们能看到一个守护式容器的列表, 以及它们的CPU、 内存、 网络I/O及存储I/O的性能和指标。 这对快速监控一台主机上的一组容器非常有用。
5、在容器中创建新的进程
通过docker exec
命令可以在容器内部额外启动新进程。 可以在容器内运行的进程有两种类型: 后台任务和交互式任务。 后台任务在容器内运行且没有交互需求, 而交互式任务则保持在前台运行。
[22:55 shexuan@hulab ~]$ docker exec -d daemon_dave touch /etc/new_config_file
这里的-d标志表明需要运行一个后台进程, -d标志之后, 指定的是要在内部执行这个命令的容器的名字以及要执行的命令。 上面例子中的命令会在daemon_dave容器内创建了一个空文件, 文件名为/etc/new_config_file。 通过docker exec后台命令, 可以在正在运行的容器中进行维护、 监控及管理任务。
我们也可以在daemon_dave容器中新打开一个shell的交互式任务:
[22:55 shexuan@hulab ~]$ docker exec -t -i daemon_dave /bin/bash
root@42b18316632c:/#
和启动容器时候一样,这里的-i -t
为我们执行的进程创建了TTY并捕捉STDIN。最后的/bin/bash
为一个新创建的shell。
run
,attach
,exec
的区别:
docker run
通常是在新创建的容器中所使用的命令。 它适用于在没有其他容器运行的情况下,您想要创建一个容器,并且要启动它,然后在其上运行一个进程;docker exec
适用于在现有容器中运行命令的情况。如果您已经拥有了一个正在运行的容器,并希望更改该容器或从中获取某些内容,那么使用“docker exec”命令就非常合适了;docker attach
也是相当于继续运行已有的容器,但是并不会另外启动一个进程,而是以初始docker run
启动命令的会话上。
6、深入了解容器信息
除了通过docker ps
命令获取容器的信息, 还可以使用docker inspect
来获得更多的容器信息。
[00:49 shexuan@hulab ~]$ docker inspect daemon_dave
[
{
"Id": "42b18316632c701e2ce266e49313cc274963b0bbb2241353da0f11526d403317",
"Created": "2018-11-06T02:33:42.333222931Z",
"Path": "/bin/sh",
"Args": [
"-c",
"while\ntrue; do echo hello world; sleep 1; done"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 10317,
"ExitCode": 0,
"Error": "",
"StartedAt": "2018-11-06T03:31:21.144011748Z",
"FinishedAt": "2018-11-06T03:05:00.01247215Z"
},
"Image": "sha256:ea4c82dcd15a33e3e9c4c37050def20476856a08e59526fbe533cc4e98387e39",
...
]
docker inspect
命令会对容器进行详细的检查, 然后返回其配置信息, 包括名称、命令、网络配置、基础镜像以及很多有用的数据。
也可以用-f
或者--format
标志来选定查看结果:
[00:53 shexuan@hulab ~]$ docker inspect --format='{{ .State.Running }}' daemon_dave
false
docker inspect
支持同时指定多个容器, 并显示每个容器的输出结果。
7、删除容器
如果容器已经不再使用(已停止使用), 可以使用docker rm
命令来删除它们。如果想删除正在运行的容器,可以加上-f
参数。
[00:58 shexuan@hulab ~]$ docker rm daemon_dave
daemon_dave
目前, 还没有办法一次删除所有容器,但是可以通过下面的小技巧来一次性删除所有容器:
[01:02 shexuan@hulab ~]$ docker rm `sudo docker ps -a -q`
9f0b544d3573
22e568aab98b
上面的docker ps命令会列出现有的全部容器, -a标志代表列出所有容器, 而-q标志则表示只需要返回容器的ID而不会返回容器的其他信息。这样我们就得到了容器ID的列表, 并传给了docker rm命令, 从而达到删除所有容器的目的。
参考:
《第一本docker书》