Docker 容器(Container)的管理

 2017年01月29日    4616     声明


容器(Container)是Docker的核心组件之一,它是用于运行镜像的一个沙箱环境,是一个从镜像创建的应用运行实例,镜像打包、构建完成后最终都会运行于容器中。容器具有良好的隔离性,容器之间是相互隔离、互不可见。本文将介绍Docker容器的创建与管理,并以容器的生命周期为主线介绍容器的创建、管理、停止,到最终删除。

  1. 检查Docker状态
  2. 创建、运行Docker容器
  3. 容器的一些操作
  4. 停止容器
  5. 删除容器

1. 检查Docker状态

首先,检查下Docker是否存在,运行状态是否正常:

$ sudo docker info
Containers: 1
 Running: 1
 Paused: 0
 Stopped: 0
Images: 1
Server Version: 1.13.0
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins: 
 Volume: local
 Network: bridge host ipvlan macvlan null overlay
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 03e5862ec0d8d3b3f750e19fca3ee367e13c090e
runc version: 2f7393a47307a16f8cee44a37b262e8b81021e3e
init version: 949e6fa
Security Options:
 seccomp
  Profile: default
Kernel Version: 4.9.4-moby
Operating System: Alpine Linux v3.5
OSType: linux
Architecture: x86_64
CPUs: 2
Total Memory: 1.952 GiB
Name: moby
ID: JUX2:WLWM:UFGS:PWPS:INCJ:ETK4:RIAW:DXGO:5MZS:3UCW:XO7E:NFLV
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): true
 File Descriptors: 23
 Goroutines: 32
 System Time: 2017-01-27T00:46:27.630232318Z
 EventsListeners: 1
No Proxy: *.local, 169.254/16
Registry: https://index.docker.io/v1/
Experimental: true
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

在这里,我们通过docker info命令来检查Docker状态信息。其返回信息包括:所有容器数量及各运行状态的容器数量、镜像数量、存储驱动等。

注:Docker命令格式为docker COMMAND,可以通过docker helpdocker --helpdocker查看Docker的使用帮助页;还可以通过docker COMMAND --helpdocker help COMMAND查看每个COMMAND的帮助信息。


2. 创建、运行Docker容器

2.1 docker run创建并运行容器

运行一个Docker容器使用docker run命令,该命令提供了Docker容器的创建和启动功能。

运行一个Ubuntu容器:

$ sudo docker run -i -t ubuntu /bin/bash
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
8aec416115fd: Pull complete 
695f074e24e3: Pull complete 
946d6c48c2a7: Pull complete 
bc7277e579f0: Pull complete 
2508cbcde94b: Pull complete 
Digest: sha256:71cd81252a3563a03ad8daee81047b62ab5d892ebbfbf71cf53415f29c130950
Status: Downloaded newer image for ubuntu:latest

docker run命令格式如下:

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

在这个命令中,我们执行了docker run命令,并指定了-i-t两个参数。其中,-i是保证容器STDIN是开启状态;-t是告诉Docker为创建的容器分配一个伪TTY终端。这样我们就创建了一个能在命令行下与之交互的容器。

然后,我们告诉Docker使用什么镜像来创建容器。在本例中,我们使用了ubuntu镜像。ubuntu镜像是Docker官方提供的一个基础(base)镜像,存储于Docker Hub Registry上。基础镜像又称为常备镜像,类似的镜像还有centosdebianfedore等,我们可以以这些镜像为基础的操作系统,并在此之上构建自己的镜像。在本例中,我们只以基础镜像启动了一个容器,并没有对容器增加其它东西。

最后,告诉Docker要在容器中执行什么命令及命令的参数。在本例中,我们运行了/bin/bash。容器创建完毕之后,就会执行/bin/bash命令,这时我们就可以看到类似如下界面:

root@af2099536638:/# 

docker run命令的执行过程下:

  • 首先检查本地是否ubuntu镜像
  • 如果没有,连接Docker Hub Registry查看是否有名为ubuntu:latest镜像的镜像,该镜像指向latest LTS
  • 找到镜像,将镜像下载到本地
  • Docker在文件系统内部使用这个镜像创建一个新容器,这个容器会有自已的网络、IP地址以及一个与本地宿主机通讯的桥接网络接口
  • 容器创建完成后,执行所要执行的命令

注:docker run命令的所有运行参数,可以通过docker run --helpdocker help run查看。


2.2 容器的交互

在前面,我创建了一个交互式容器。创建完成后,就已经以root用户登录到了新创建的容器中,容器的ID是af2099536638

创建容器时,我们使用了基础镜像ubuntu,因此所创建的容器也是一个具有完整功能的Ubuntu系统,而容器的ID就是所创建容器的主机名:

root@af2099536638:/# hostname
af2099536638

检查/etc/hosts文件:

root@af2099536638:/# cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.3	af2099536638

Docker为该主机的添加了一条主机配置项。

像普通主机一样,我们也可以在容器中安装软件:

root@af2099536638:~# apt-get update & apt-get install vim

在容器中工作结束后,可以通过exit命令退出并返回宿主机:

root@af2099536638:~# exit
exit

退出后,/bin/bash程序结束,容器也会随之停止。这时,可以通过docker ps查看容器列表:

$ sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                         NAMES
af2099536638        ubuntu              "/bin/bash"              4 hours ago         Exited (0) 5 minutes ago                                 thirsty_shaw

docker ps命令只能看到正在运行中的容器,查看所有容器需要增加-a参数。通过docker ps命令,还可以看到很多容器信息,如:容器ID、创建容器的镜像、创建时间、运行/退出状态(如果退出状态是0,则表示容器是正常退出,如上例)等。

注意:docker ps命令,除-a参数外,常用的还有-l参数,用于列出最后一个运行的容器(无论容器是否运行)。更多参数请使用docker help psdocker ps --help查看。


2.2 docker create创建但不运行容器

docker run命令会创建并运行容器,如果仅想创建但不运行容器,可以使用docker create命令:

$ sudo docker create ubuntu 
7d31bae2b5fa86675de61ad3473bf05c95ce28c26b915a434991efa966042b07

使用docker create创建不运行容器,可以方便我们进行一些精细化的控制。如上所示,创建成功后会返回所创建容器的UUID,该UUID是一个长UUID,可以使用该ID做为容器标识,进行后续操作。


2.3 命名容器

创建容器时,如果不指定名称,Docker会为容器指定一个随机名称,如,在前面示例中容器名为thirsty_shaw。如果需要为容器指定一个名称,可以在创建容器时添加--name参数。

如,创建并命名容器:

$sudo docker run -i -t --name itbilu_ubuntu ubuntu /bin/bash
root@0f5a0e713219:/# 

这样我们就创建了一个名为itbilu_ubuntu的容器。容器的短UUID、长UUID、名称都可以做为容器的标识使用,但名称会比随机生成的名称或容器ID要好记,和易于管理。大多数docker命令都可以使用名称代替ID,更推荐使用容器名称来代替ID使用,以更方便的进行管理。

容器命名必须唯一,如果名称重复时会创建失败。这时,可以傅和docker rm命令先将容器移除再重新创建。


2.4 创建守护式容器

与容器存在交互式会话的容器,称之为交互式容器(interactive container)。除交互式容器容器外,还可以创建没有交互会话的、长期运行的守护式容器(daemonized container)。实际上,我们使用容器在后台运行程序或服务,大多时候创建的都是守护式容器。

如,创建一个守护式容器:

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

在这个示例中,我们创建了一个名为daemon_ubuntu的容器。创建容器时,我们使用了-d参数,这个参数会告诉Docker在后台运行容器。这个容器创建成功后,不会进入shell会话,而是会返回容器的UUID。

在这个容器中,我们还使用了一个while循环,这个循环会每秒打印一次hello world

通过docker ps命令,可以看到这个容器:

$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
04e31cefe605        ubuntu              "/bin/sh -c 'while..."   14 hours ago        Up 5 minutes                            daemon_ubuntu


容器的自动重启

容器可能会由于某些错误而异常退出,默认情况下容器停止后不会自动重启。在运行容器时,可以设置--restart参数,容器退出时,--restart参数会检查容器的退出代码,并依此决定是否重启容器。该参数默认值为no,即:不会自动重启。可选值有:

  • always - 无论容器的退出代码是什么总是在退出后自动重启
  • no-failure[:NUM] - 退出代码非0时才自动重启。该参数还接受一个可选的NUM参数,表示尝试重启的次数

如,创建一个总是在退出后自动重启的守护式容器:

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

如,创建一个守护式容器,异常退出后尝试自动重启5次:

$ sudo docker run --restart=no-failure:5 --name daemon_ubuntu -d ubuntu /bin/sh -c "while true; do echo hello world; sleep 1; done"


3. 容器的一些操作

3.1 容器的启动

容器停止后,可以通过docker startdocker restart重新启动容器。

如,启动容器itbilu_ubuntu

$ sudo docker start itbilu_ubuntu
itbilu_ubuntu

启动后就可以通过docker ps而不用加-a参数看到刚启动的容器。


3.2 附着到容器

通过docker run命令并添加-i-t启动了一个交互式的shell。但容器退出后,再通过docker start命令启动时后,容器会在后台运行。这时,可以通过docker attach命令重新附着到容器的会话上:

$ sudo docker attach itbilu_ubuntu
root@0f5a0e713219:/# 

命令输入完成,并回车确认,即可进行会话界面。需要注意的是docker attach只有容器处理运行状态的容器才会附着成功。而退出容器shell后,容器会再次停止。


3.3 容器日志查看

2.4节中,我们创建一个在后台运行的守护式容器。在这个容器中,每秒会输出一次hello worldSTDOUT。为了获取容器的日志信息,可以使用docker logs命令。

docker logs命令格式如下:

docker logs [OPTIONS] CONTAINER

如,查看容器daemon_ubuntu的日志信息:

$ sudo docker logs daemon_ubuntu
hello world
hello world
hello world
…

在上例中,会看到容器的所有日志信息。查看日志时,还可以添加-f参数,该参数类似tail -f命令,会看到实时看到日志输出。

$ sudo docker logs -f daemon_ubuntu
hello world
hello world
hello world
…

为了显示更为友好,还可以通过--tail参数指定最后显示的日志行数。如,查看最后5行日志:

$ sudo docker logs -f --tail 5 daemon_ubuntu
hello world
hello world
hello world
hello world
hello world
……

注:请使用docker help logsdocker logs --help查看日志的详细参数


3.4 容器内进程查看

对容器进行管理时,有时会需要查看容器内正在运行的进程。容器内进程查看可以使用docker top命令。

如,查看容器daemon_ubuntu内的进程:

$ sudo docker top daemon_ubuntu
PID                 USER                TIME                COMMAND
16411               root                0:03                /bin/sh -c while true; do echo hello world; sleep 1; done

在这个容器中,我们只运行了一个用于打印日志的/bin/sh进行。通过docker top命令,可以看到进行的PID、进程用户等。


3.5 容器内运行进程

不仅可以查看容器内正在运行的进程,通过docker exec命令还可以启动新进程。在容器内启动的进程分为两类:后台任务和交互式任务。后台任务运行于容器内部没有交互需要。而交互式任务则会保持在前台,如果需要在容器内打开shell,则很适用创建交互式任务。

docker exec命令格式如下:

docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

如果要创建后台任务,则需要在执行docker exec命令时指定-d参数。

如,在容器daemon_ubuntu内创建一个空的配置文件:

$ sudo docker exec -d daemon_ubuntu touch /etc/a_config_file

创建交互式任务,与运行交互式容器时一样,需要添加-t-i参数。如:

$ sudo docker exec -t -i daemon_ubuntu /bin/bash
root@04e31cefe605:/# 

创建交互式任务并退出后,并不会导致守护式容器的停止。

注意:docker exec命令在Docker 1.3+版本才可用。docker exec使用说明及详细参数请使用docker help execdocker exec --help查看。


3.6 容器状态查看

在查看容器内进程时,我们使用了docker top命令。除此之外,还可以使用docker stats来查看容器的详细使用统计信息,该命令可以同时查看一个或多个容器的统计信息。

如,查看容器daemon_ubuntu的使用统计:

$ sudo docker stats daemon_ubuntu
CONTAINER           CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
daemon_ubuntu       0.08%               616 KiB / 1.952 GiB   0.03%               15 kB / 1.35 kB     0 B / 0 B           2

docker statsdocker top统计内容有所不同,统计内容包括:CPU、内存、网络I/O、存储I/O使用情况等。统计形式也有所不同,docker stats是实时统计。

docker stats可以同时统计多个容器的使用情况,指定多个需要统计的容器ID或名称即可,也可以通过-a参数对所有容器进行统计:

$ sudo docker stats daemon_ubuntu itbilu_ubuntu

注意:docker stats命令在Docker 1.5+版本才可用。docker stats使用说明及详细参数请使用docker help statsdocker stats --help查看。


3.7 容器详细信息

通过docker ps命令,我们可以看到容器的一些基本信息。除此之外,docker还提供了一个docker inspect命令,该命令会返回容器的详细配置信息。包括:名称、命令、运行状态、网络配置等。

其语法格式如下:

docker inspect [OPTIONS] NAME|ID [NAME|ID...]

如,查看容器daemon_ubuntu的详细信息:

$ sudo docker inspect daemon_ubuntu
[
  {
    "Id": "04e31cefe605bd3636a4d3908fd0083421b1c6d321e4f07beabfead4b633a528",
    "Created": "2017-01-27T12:54:11.923454273Z",
    "Path": "/bin/sh",
    "Args": [
      "-c",
      "while true; do echo hello world; sleep 1; done"
    ],
    "State": {
      "Status": "running",
…

docker inspect命令有一个很有用的参数-f--format,这个参数支持完整的GO语言模板,可以对输出结果进行格式化、筛选等。

如,查看容器daemon_ubuntu的运行状态:

$ sudo docker inspect -f '{{.State.Running}}' daemon_ubuntu
true

如,查看容器daemon_ubuntu的IP地址:

$ sudo docker inspect -f '{{.NetworkSettings.IPAddress}}' daemon_ubuntu
172.17.0.2


4. 停止容器

停止守护式容器时,需要手工调用docker stop命令。停止容器时,

如,停止容器daemon_ubuntu

$ sudo docker stop daemon_ubuntu

也可以使用容器ID:

$ sudo docker stop 04e31cefe605

停止容器时,docker stop命令会向容器进程发送SIGTERM信号,收到该信号进程完成处理后结束。如果想快速停止可以使用docker kill,该命令会向容器进程发送SIGKILL信号。


5. 删除容器

容器不再使用后,可以使用docker rm命令将其删除。

如,删除容器daemon_ubuntu

$ sudo docker rm daemon_ubuntu

如果容器正在运行中,会删除失败。这时,可以先使用docker stop命令停止容器后再删除。或者使用-f参数强制删除:

$ sudo docker rm -f daemon_ubuntu