容器

容器是一个打包了应用和服务的环境。它是一个轻量级的虚拟机,每一个容器都由一组特定的应用和必要的依赖库组成。容器作为一个软件应用的标准集装箱,它必然需要定义一组跟具体应用无关的标准接口。

一、容器的管理操作

对于容器的常见命令(包括查看、创建、启动、终止和删除等),我们按照由浅到深、由必须到可选的顺序介绍。

要查看某条指令的详细帮助信息,可以访问 http://docs.docker.com/reference/,或者通过docker help命令。此外,我们也可以通过man pages查看(例如:man docker-run)。

创建容器

创建容器有两个命令,一个是docker create,另一个是docker run。二者的区别在于前者创建的容器处于停止状态,而后者不仅创建了容器,而且启动了容器。

采用docker create创建一个停止状态的容器,具体如下:

$ docker create ubuntu:14.04
adedeb41185ad9ac096b8f1a7a3c2d3c2f0cf759643685d320ff656bd49b9d48
$ docker ps
CONTAINER ID    IMAGE         COMMAND    CREATED         STATUS       PORTS        NAMES
$ docker ps -a
CONTAINER ID    IMAGE         COMMAND    CREATED         STATUS       PORTS        NAMES
adedeb41185a  ubuntu:14.04  "/bin/bash"  27 seconds ago                            stupefied_brown

创建容器后,Docker会立刻返回容器的ID,例如adedeb…就是我们刚刚所创建容器的ID。ID可以唯一标识一个容器,每一个容器的ID都是独一无二的。docker ps命令用于查看正在运行的容器,我们没有看到任何运行的容器,docker ps –a则是查看所有容器,包含未启动的容器。可以看到,我们创建的容器已经存在。

想要让创建的容器立马进入运行态,可以使用docker run命令,该命令等同于用docker create创建容器后再使用docker start启动容器。使用docker run命令,可以创建两种类型的容器——后台型容器和交互型容器。

① 交互型容器:运行在前台,通常会指定有交互的控制台,可以给容器输入,也可以得到容器的输出。创建该容器的终端被关闭,在容器内部使用exit命令或者调用了docker stop、docker kill命令后,容器会变成停止状态。

② 后台型容器:运行在后台,创建启动之后就与终端无关。即便终端关闭了,该后台容器也依然存在,只有调用docker stop或docker kill命令时才能够使容器变成停止状态。

下面我们创建一个交互型容器,相关代码如下:

$ sudo docker run -i -t --name=inspect_shell ubuntu /bin/bash
Unable to find image 'ubuntu' locally
Pulling repository ubuntu
86ce37374f40: Download complete
511136ea3c5a: Download complete
5bc37dc2dfba: Download complete
61cb619d86bc: Download complete
3f45ca85fedc: Download complete
78e82ee876a2: Download complete
dc07507cef42: Download complete
root@761ef6d4b28f:/#

首先,告诉Docker要运行docker run命令。这个命令后面是命令行标志-i和-t,前者用于打开容器的标准输入(STDIN),后者告诉Docker为容器建立一个命令行终端。这两个标志为我们和容器提供了交互shell,是创建交互型容器的基本设置。后面的--name标志为容器指定了一个名字,这是一个可选项。当没有这个选项时,Docker会为我们取一个随机的名字。接下来,我们告诉Docker使用哪个镜像去创建容器,这里使用的是ubuntu。ubuntu镜像是一个基础镜像,我们可以使用基础镜像(例如ubuntu、fedora、debian、centos等)作为创建自己镜像的基础。这里我们只是用基础镜像来启动容器,没有添加任何东西。最后,告诉Docker要在容器里面执行命令/bin/bash。

命令本身我们理解了,那么在后台会发生些什么呢?创建容器的流程如图2-1所示,当我们运行docker run命令后,Docker在本地搜索我们指定的ubuntu镜像,如果没有找到,就会到公有仓库Docker Hub中继续搜索。如果在服务器上找到了需要的镜像,Docker就会下载这个镜像,并将其保存到本地。然后,Docker使用这个镜像创建一个新的容器并将其启动;容器的文件系统是在只读的镜像文件上增加一层可读写的文件层,这样可以保证镜像不变而只记录改变的数据,这对容器的共享和传输都非常有利。接着会配置容器的网络,Docker会为容器分配一个虚拟网络接口,并通过网桥的方式将该网络接口桥接到宿主主机上去,然后该虚拟网络接口分配一个IP地址。最后,Docker在新容器中运行指定的命令,例如我们的例子中是/bin/bash。容器创建成功后,会出现类似下面的提示符:

root@761ef6d4b28f:/#

图2-1 docker run命令的内部流程

@前面的是我们在容器的登录用户root,后面的761ef6d4b28f是容器的主机名。可以使用ctrl+D或者exit命令退出该容器。容器停止并不代表容器销毁,其实容器还在,只是不再是运行态,可以通过docker ps –a命令查看到已存在的容器。

接下来,我们创建一个后台型容器。在实际的应用中,大多数容器都是后台型容器,因为服务器程序不可能因为创建容器的终端退出而退出。创建后台型容器需要使用-d参数,其创建命令如下:

$ sudo docker run --name daemon_while -d ubuntu /bin/sh -c    "while true; do echo hello world; sleep 1; done"
f40f1463221f6fdcd5ae26d223df10273b0a4831d8bf1db16d461f583ac0cfb6

你可能注意到了,上面的命令没有像前面的容器那样关联到一个shell,而是返回了一个容器ID后直接返回到了宿主主机的命令提示符。我们可以通过运行docker ps命令,查看新建的容器是否正在运行:

$ sudo docker ps
CONTAINER ID  IMAGE         COMMAND               CREATED        STATUS        PORTS  NAMES
f40f1463221f  ubuntu:latest /bin/sh -c 'while tr  2 minutes ago  Up 2 minutes         daemon_while
761ef6d4b28f  ubuntu:latest /bin/bash             49 minutes ago Up 49 minutes        inspect_shell

可以看到,有两个容器在运行,交互型的容器inspect_shell和后台型容器daemon_while。

查看容器

我们经常使用docker ps命令来查看正在运行的容器。

$ sudo docker ps
CONTAINER ID   IMAGE          COMMAND               CREATED            STATUS           PORTS
NAMES
f40f1463221f   ubuntu:latest  /bin/sh -c 'while tr  16 minutes ago     Up 16 minutes
daemon_while
761ef6d4b28f   ubuntu:latest  /bin/bash             About an hour ago  Up About an hour
inspect_shell
  • CONTAINER ID:唯一标识容器的ID。它是一个64位的十六进制数,对某个容器的操作可以通过它来标识操作目标。在不会混淆的前提下,可以采用ID的前几位来标识该容器,而在显示的时候一般会显示12位。
  • IMAGE:创建容器时使用的镜像。
  • COMMAND:容器最后运行的命令。
  • CREATED:创建容器的时间。
  • STATUS:容器的状态。如果容器是运行状态,则类似UP 49 minutes的形式,其中49分钟是容器已经运行的时间;如果容器是停止状态,则是类似Exited(0)的形式,其中数字0是容器退出的错误码,0为正常退出,其他数字则表示容器内部出现错误。
  • PORTS:对外开放的端口。
  • NAMES:容器名。和容器ID一样都可以唯一标识一个容器,所以同一台宿主主机上不允许有同名的容器存在,否则会提示冲突。

使用docker ps命令,只会列出当前正在运行的容器。当要查看所有的容器时,可以使用-a选项,它会告诉Docker列出所有容器,包括运行的和停止的容器。示例代码如下:

$ sudo docker ps -a
CONTAINER ID   IMAGE          COMMAND               CREATED           STATUS                PORTS
NAMES
dbc5bafd5805   ubuntu:latest  echo hello            7 seconds ago     Exited (0) 6 seconds ago
hopeful_bartik
f40f1463221f   ubuntu:latest  /bin/sh -c 'while tr  16 minutes ago    Up 16 minutes
daemon_while
761ef6d4b28f   ubuntu:latest  /bin/bash             About an hour ago Up About an hour
inspect_shell

当要查看最新创建的容器时,还可以使用-l选项,该选项告诉Docker只列出最后创建的容器:

$ sudo docker ps -l
CONTAINER ID   IMAGE          COMMAND      CREATED        STATUS           PORTS       NAMES
dbc5bafd5805   ubuntu:latest  echo hello   7 seconds ago  Exited (0) 6 seconds ago

此外,还可以使用-n=x选项,此时会列出最后创建的x个容器:

$ sudo docker ps –n=2
CONTAINER ID  IMAGE          COMMAND              CREATED         STATUS                   PORTS
NAMES
dbc5bafd5805  ubuntu:latest  echo hello           7 seconds ago   Exited (0) 6 seconds ago
hopeful_bartik
f40f1463221f  ubuntu:latest  /bin/sh -c 'while tr 16 minutes ago  Up 16 minutes

这里列出了最近创建的两个容器的运行情况。

启动容器

通过docker run命令创建的容器会直接进入到运行状态,而通过docker create命令创建的容器则会进入到停止状态,想要运行该容器,则可以通过docker start命令来启动它。当容器运行完自己的任务后,容器会退出,进入到停止状态,如果需要再次启动该容器,可以再次用docker start命令来启动。

例如,可以通过docker start来启动之前已经停止了的inspect_shell容器:

$ sudo docker start inspect_shell

也可以使用该容器的ID来启动:

$ sudo docker start 761ef6d4b28f

容器在运行过程中,总是不可避免地会出现各种问题,严重的会导致容器因为异常而退出。而有时我们需要根据错误码来判断容器是否需要重启。默认情况下,容器是不重启的,为了让容器在退出后能够自动重启,需要用到--restart参数。--restart标志会检查容器的退出码,并据此来决定是否需要重启容器。

我们可以用下面的命令创建容器:

$ sudo docker run --restart=always --name docker_restart -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"

在这个例子中,--restart标志被设置成always。不管容器的返回码是什么,Docker都会尝试重启容器。另外,我们也可以将其设置成on-failure,这样的话,当容器的返回值是非0时,Docker才会重启容器。on-failure标志还接受一个可选的重启次数,如下所示:

--restart=on-failure:5

表示当收到一个非0的返回码时,最多尝试重启容器5次。

终止容器

退出容器的方式有很多种。当容器发生严重的错误时,容器会因为异常而退出并带有错误码,这时可以通过错误码来判定容器内部发生的错误。而在正常情况下,交互型容器可以在shell中输入exit,或者是使用ctrl+d组合键来使其退出。另外,交互型容器和后台型容器都可以采用docker stop命令来停止:

$ sudo docker stop daemon_while

上述介绍的都是通过容器名来停止该容器。此外,我们还可以通过容器ID来停止容器:

$ sudo docker stop f40f1463221f

docker stop命令给容器中的进程发送SIGTERM信号,默认行为是会导致容器退出。当然,容器内程序可以捕获该信号并自行处理,例如可以选择忽略。如果要强行停止一个容器,则需要使用docker kill命令,它会给容器的进程发送SIGKILL信号,该信号将会使容器必然退出。

删除容器

当一个容器停止时,容器并没有消失,只是进入了停止状态,必要的话还可以重新运行。如果确定不再需要这个容器时,可以使用docker rm命令删除它:

$ sudo docker rm hopeful_bartik
hopeful_bartik

要注意一点,不可以删除一个运行中的容器,此时必须先用docker stop或docker kill命令停止它才能删除。示例如下:

$ docker ps
CONTAINER ID  IMAGE            COMMAND        CREATED          STATUS        PORTS  NAMES
dfc72feb607b  ubuntu:14.04     "/bin/sh"      13 seconds ago   Up 12 seconds        modest_mestorf
micall@micall-ThinkPad:~$ docker rm modest_mestorf
Error response from daemon: You cannot remove a running container. Stop the container before attempting removal or use –f
FATA[0000] Error: failed to remove one or more containers

此时会输出错误,提示你不能够删除一个正在运行的容器,必须先停止才能够删除。当然,你也可以使用-f选项强制删除它:

$ docker rm -f modest_mestorf
modest_mestorf
micall@micall-ThinkPad:~$ docker ps
CONTAINER ID        IMAGE            COMMAND      CREATED     STATUS       PORTS        NAMES

Docker并没有提供一次性删除所有容器的命令,但是可以用下面的命令来实现这个目的:

docker rm `docker ps -a -q`

这个命令会用docker ps列出当前的所有容器,-a标志列出所有容器,-q标志只列出容器的ID,不包括容器的其他信息。然后将这个列表传给docker rm命令,依次删除容器。

二、容器内信息获取和命令执行

依附容器

依附操作attach通常用在由docker start或者docker restart启动的交互型容器中。由于docker start启动的交互型容器并没有具体终端可以依附,而容器本身是可以接收用户交互的,这时就需要通过attach命令来将终端依附到容器上。具体示例如下:

$ docker run -i -t ubuntu:14.04 /bin/sh
$ docker ps
CONTAINER ID     IMAGE          COMMAND         CREATED           STATUS         PORTS      NAMES
$ docker run -i -t --name ubuntu ubuntu:14.04 /bin/sh
# ls
bin  boot  dev etc  home  lib lib64  media  mnt  opt proc  root  run  sbin  srv  sys  tmp  usr  var
# ^C
#
$ docker ps
CONTAINER ID     IMAGE          COMMAND         CREATED           STATUS         PORTS      NAMES
$ docker start ubuntu
ubuntu
$ docker ps
CONTAINER ID     IMAGE          COMMAND         CREATED           STATUS         PORTS      NAMES
d5521fff6cdb     ubuntu:14.04   "/bin/sh"       45 seconds ago    Up 5 seconds              ubuntu

$ docker attach ubuntu
# ls
bin  boot  dev etc  home  lib lib64  media  mnt  opt proc  root  run  sbin  srv  sys  tmp  usr  var
#

需要注意的是,当使用attach命令依附容器后,需要多按一次回车才会出现容器的shell交互界面。

在上面,我们特别强调的是将终端依附到交互型容器中,那么对于后台型容器,使用attach命令会发生什么呢?我们通过实例来探索这个问题的答案。我们发现,后台型容器是无法依附终端的,因为它本身就不接受用户交互输入。

查看容器日志

对于交互型容器,由于本身就存在交互终端或者可以通过attach依附终端,所以查看容器的配置信息或者调试程序比较方便。但对于后台型容器,它不存在交互终端,要获取其信息,势必需要其他的方法,Docker给我们提供了logs、inspect等方法。docker logs命令用于查看容器的日志,它将输出到标准输出的数据作为日志输出到运行docker logs命令的终端上。

首先,创建一个不断输出一些内容的后台型容器:

$ sudo docker run -d --name deamon_logs ubuntu /bin/bash -c 'for((i=0;1;i++));do echo $i;sleep 1;done;'
956c4bb8db65aa24c2e7b865f829c1c19d2b201c9c7fc86a77d199b2589bdc54

deamon_logs是一个包含循环输出自然数的应用程序的容器,我们可以使用logs来查看其输出:

$ sudo docker logs -f  deamon_logs
0
1
2
3
...

可以看到,该容器的程序循环向标准输出数字0、1、2 ...。默认情况下,logs输出的是从容器启动到调用执行logs命令时的所有输出,之后的日志不再输出,并立即返回主机的控制台。如果要实时查看日志,可以使用-f标志。由于这里使用了-f标志,可以看到,日志从开始一直输出到当前时刻,并且还在不断更新,此时可以使用ctrl+C快捷键退出监视日志。

如果前面已经有很多日志,但是我们不想关心,只想要查看日志的最后部分,可以通过--tail参数。

使用--tail标志可以精确控制logs输出的日志行数。例如,查看最后5行日志:

$ sudo docker logs -f --tail=5 daemon_logs
723
724
725
726
727
...

可以看到,首先输出日志的最后5行。由于使用了-f标志,之后的日志也会不断更新出来。

为了方便调试程序,我们还可以通过-t标志查看日志产生的时刻,相关代码如下:

$ sudo docker logs -f --tail=5 -t daemon_logs
2014-12-27T08:16:00.873690621Z 755
2014-12-27T08:16:01.875306639Z 756
2014-12-27T08:16:02.880058459Z 757
2014-12-27T08:16:03.884377275Z 758
2014-12-27T08:16:04.885695676Z 759

...

查看容器进程

使用docker top命令,可以查看容器中正在运行的进程。

首先,创建一个后台型容器(交互型容器也行,但是要到其他控制台运行docker top):

$ sudo docker run -d --name="deamon_top" ubuntu /bin/bash -c 'while true;do sleep 1; done'
d9a46de654821f15269d7427d93b3126dd3217492e7c2eb3c7ae09a18fdf8bc2

运行docker top命令,查看容器中的进程:

$ sudo docker top deamon_top
UID              PID            PPID       C       STIME
TTY              TIME           CMD
root             11699          1158       0
16:38            ?              00:00:00   /bin/bash -c while true;do sleep
1; done
root             11778          11699      0
16:39            ?              00:00:00   sleep 1

可以看到,这里有两个进程,一个是while循环的进程,另一个是while循环内部运行的sleep进程。

查看容器信息

docker inspect用于查看容器的配置信息,包含容器名、环境变量、运行命令、主机配置、网络配置和数据卷配置等:

$ sudo docker inspect daemon_dave
[{
    "ID": " c2c4e57c12c4c142271c031333823af95d64b20b5d607970c334784430bcbd0f ",
    "Created": "2014-05-10T11:49:01.902029966Z",
    "Path": "/bin/sh",
    "Args": [
        "-c",
        "while true; do echo hello world; sleep 1; done"
    ],
    "Config": {
        "Hostname": "c2c4e57c12c4",
    ...

使用-f或者--format格式化标志,可以查看指定部分的信息。

查询容器的运行状态:

$ sudo docker inspect --format='{{ .State.Running }}' daemon_dave
false

查询容器的IP地址:

$ sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}'
daemon_dave

同时还可查看多个信息,例如查看容器名和运行状态:

$ sudo docker inspect --format '{{.Name}} {{.State.Running}}' \
daemon_dave bob_the_container
/daemon_dave false
/bob_the_container false

容器内执行命令

在容器启动的时候,通常需要指定其需要执行的程序,然而有时候我们需要在容器运行之后中途启动另一个程序。从Docker 1.3开始,我们可以用docker exec命令在容器中运行新的任务,它可以创建两种任务:后台型任务和交互型任务。后台型任务没有用户交互终端,交互型任务具有和用户交互的输入输出终端。

让我们看一个后台型任务的例子:

$ sudo docker exec -d daemon_dave touch /etc/new_config_file

这里-d标志表示要运行一个后台型任务。接着需要指定要运行命令的容器名和要运行的命令。在这个例子里,touch命令会在daemon_dave容器中创建一个new_config_file文件。通过docker exec创建的后台任务,我们可以执行维护、监视、管理等复杂而有意义的任务。

使用docker exec命令创建交互型任务时,需要加上-t -i标志,示例如下:

$ sudo docker exec -t -i daemon_dave /bin/bash

-t和-i标志的用法与我们创建交互型容器时一样,会创建一个交互终端,并捕捉进程的标准输入和输出。通过该交互终端,我们可以在容器内运行命令和查看信息等。

三、容器的导入和导出

Docker的流行与它对容器的易分享和易移植密不可分。用户不仅可以把容器提交到公共服务器上,还可以将容器导出到本地文件系统中。同样,我们也可以将导出的容器重新导入到Docker运行环境中。Docker的导入和导出分别由import命令和export命令完成。

下面我们说明一下容器的导出。首先,创建一个容器:

$ sudo docker run -i -t --name=inspect_import ubuntu /bin/bash
root@3d2371934e2d:/#

然后按需要修改容器,安装需要的软件,配置系统环境。当我们完成这一切后,就可以把容器保存到本地,使用docker export命令导出容器:

$ sudo docker export inspect_import > my_container.tar
$ ls
my_container.tar

docker export 命令会把容器的文件系统以tar包的格式导出到标准输出,我们将其重定位到目标文件name.tar。将容器保存到本地文件也算是其持久化方式的一种。将容器保存到本地之后,我们就可以通过网络等方法将tar包分享给他人。

反过来,我们可以使用docker import命令导入一个本地的tar包作为镜像:

$ cat my_container.tar | sudo docker import - imported:container
6c16d0ec9f8ef1a1f6ef47ce92b77692dd8c5d12e669b045366bbaf71d7182b1
$ sudo docker images
REPOSITORY        TAG               IMAGE ID            CREATED             VIRTUAL SIZE
imported          container         6c16d0ec9f8e        35 seconds ago      192.5 MB
ubuntu            latest            9bd07e480c5b        3 weeks ago         192.7 MB

ocker import会把打包的容器导入为一个镜像。

import表示从标准输入读取容器内容,我们把name.tar的内容传给了标准输入,res和tag分别代表生成的镜像和标记。

除了导入本地文件系统的tar包成为一个镜像外,我们还可以使用一个url来导入网络上的容器:

docker import url res:tag

接着就可以通过docker run命令使用导入的镜像创建我们需要的容器了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值