Docker容器

容器简介

Docker利用容器来开发、运行应用。 容器是镜像创建的实例。它可以被启动、开始、停止、删除。每个容器都是 相互隔离的、保证安全的平台。
类似安装系统的电脑实体。简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境
对应的虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

启动容器

启动容器有两种方式:

  • 基于镜像新建一个容器并启动
  • 将在终止状态(stopped)的容器重新启动。

这里我们先操作基于镜像新建一个容器并启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
docker@default:~$ docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:6540fc08ee6e6b7b63468dc3317e3303aae178cb8a45ed3123180328bcc1d20f
Status: Downloaded newer image for hello-world:latest

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/

上面例子中我们直接基于镜像hello-world来创建容器,由于本地没有对应的镜像,先自动拉取镜像,然后运行基于拉取的镜像运行容器。我们可以使用命令docker ps -a 查看到创建的容器:

1
2
3
docker@default:~$ sudo docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b57003b3cd3f hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago sad_ride

容器常用命令

创建容器

1.使用 docker create latest xxx 可以创建容器,ubuntu:latest 表示下载最新最新版本的镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ docker create ubuntu:latest
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
124c757242f8: Pull complete
9d866f8bde2a: Pull complete
fa3f2f277e67: Pull complete
398d32b153e8: Pull complete
afde35469481: Pull complete
Digest: sha256:de774a3145f7ca4f0bd144c7d4ffb2931e06634f11529653b23eba85aef8e378
Status: Downloaded newer image for ubuntu:latest
0785954537b0d89043c8b0bab82b498039b4a9f73f79b2cec863f599759c946a

Shuqing@LAPTOP-8B5JADC8 MINGW64 /d/Program Files/Docker Toolbox
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0785954537b0 ubuntu:latest "/bin/bash" 42 seconds ago Created hardcore_blackwell
02a347bb4f4d centos "/bin/bash" 25 minutes ago Created boring_bardeen

2.创建交互型容器:运行在前台,容器中使用exit命令或者调用docker stopdocker kill命令,容器停止。

1
2
3
4
5
6
7
$ docker run -i -t --name=51zxw ubuntu /bin/bash
root@d66ca55b5bac:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@d66ca55b5bac:/# echo 51zxw
51zxw
root@d66ca55b5bac:/# exit
exit

参数说明

  • -i(input):打开容器的标准输入。
  • -t(terminal):告诉docker为容器建立一个命令行终端。
  • --name:指定容器名称,可以不填(随机),建议根据具体使用功能命名,便于管理。
  • ubuntu:告诉我们使用什么镜像来启动容器。
  • /bin/bash:告诉docker要在容器里面执行此命令。

3.创建后台型容器:创建后与终端无关,只有调用docker stop、docker kill命令才能使容器停止。

1
2
3
4
5
6
$ docker run -d  --name=51zxw_hello_backgroud ubuntu /bin/bash -c "while true; do echo hello 51zxw; sleep 2; done"
afb5ae6b7a41d8a2501d80330aa24905084c3f05200e2fb186b79a8ff9f19b74

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
afb5ae6b7a41 ubuntu "/bin/bash -c 'while…" 50 seconds ago Up 49 seconds 51zxw_hello_backgroud
  • -d:使用-d参数,使容器在后台运行。
  • -c:后的命令是循环,从而保持容器的运行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ docker logs 51zxw_hello_backgroud
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw
hello 51zxw

查看容器详细信息

使用docker inspect 可以查看容器的详细配置信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
docker@default:~$ docker inspect hello-world
[
{
"Id": "sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e",
"RepoTags": [
"hello-world:latest"
],
"RepoDigests": [
"hello-world@sha256:6540fc08ee6e6b7b63468dc3317e3303aae178cb8a45ed3123180328bcc1d20f"
],
"Parent": "",
"Comment": "",
"Created": "2019-01-01T01:29:27.650294696Z",
"Container": "8e2caa5a514bb6d8b4f2a2553e9067498d261a0fd83a96aeaaf303943dff6ff9",
"ContainerConfig": {
"Hostname": "8e2caa5a514b",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"/hello\"]"
],
"ArgsEscaped": true,
"Image": "sha256:a6d1aaad8ca65655449a26146699fe9d61240071f6992975be7e720f1cd42440",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "18.06.1-ce",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/hello"
],
"ArgsEscaped": true,
"Image": "sha256:a6d1aaad8ca65655449a26146699fe9d61240071f6992975be7e720f1cd42440",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 1840,
"VirtualSize": 1840,
"GraphDriver": {
"Data": null,
"Name": "aufs"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:af0b15c8625bb1938f1d7b17081031f649fd14e6b233688eea3c5483994a66a3"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]

查看容器列表

1.使用 docker container ls -all 来查看所有的容器,如果查看正在运行的就不需要加参数 --all

1
2
3
4
5
6
$ docker container ls --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
92d1b548ad88 hello-world "/hello" 16 hours ago Exited (0) 16 hours ago blissful_hypatia
17d0e0e51df1 hello-world "/hello" 45 hours ago Exited (0) 45 hours ago priceless_khorana
d84baeb7c5f6 hello-world "/hello" 45 hours ago Exited (0) 45 hours ago dreamy_swanson
5e644f959f0b ubuntu-upstart:latest "/sbin/init" 45 hours ago Exited (255) 17 hours ago 0.0.0.0:32768->22/tcp ubuntu-upstart

2.使用 docker ps -a 查看,如果需要查看正在运行的容器就不用加-a参数

启动已经存在的容器

使用命令 docker start CONTAINER ID 来启动已经存在的容器

1
2
$ docker start 5e644f959f0b
5e644f959f0b

启动完成后可以使用 docker ps 或者 docker container ls查看正在运行的容器

1
2
3
4
5
6
7
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5e644f959f0b ubuntu-upstart:latest "/sbin/init" 46 hours ago Up 23 seconds 0.0.0.0:32770->22/tcp ubuntu-upstart

$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5e644f959f0b ubuntu-upstart:latest "/sbin/init" 46 hours ago Up 3 minutes 0.0.0.0:32770->22/tcp ubuntu-upstart

进入容器

docker exec是需要容器处于运行中且进程也处于运行中才能执行的操作。命令执行后会进入容器的默认工作目录

1
docker exec -it container_id  /bin/bash

  • -i :即使没有附加也保持STDIN 打开
  • -t :分配一个伪终端

比如我们进入到运行ngnix容器内部后,查看目录结构发现和一个独立的操作系统文件目录结构一样。

1
2
3
4


root@63d4136cbd69:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var

如果需要退出容器,则执行exit即可

重启容器

使用 docker restart 来重启正在运行的容器。

1
2
$ docker restart 5e644f959f0b
5e644f959f0b

容器自动重启

  • Docker提供了restart policy机制,可以在容器退出或者Docker重启时控制容器能够自启动。这种Restart policy可以保证相关容器按照正确顺序启动。虽然也可以通过进程监控的方式(如systemd)来完成这种动作,但Docker还是建议尽量避免使用进程监控的方式来 “自启动” 容器。

  • Docker的 Restart policydockerd命令的--live-restore启动标志还有区别:--live-restore标志可以在Docker升级的时候保证容器继续运行,但是网络以及用户终端输入会被中断。
    那到底什么是restart policy呢?我们来看看实际的情况吧。

restart policy

restart policy在使用docker run启动容器时通过--restart标志指定,这个标志有多个value可选,不同的value有不同的行为,如下表所列:
值|描述
—|—
no|不自动重启容器. (默认value)
on-failure| 容器发生error而退出(容器退出状态不为0)重启容器
unless-stopped| 在容器已经stop掉或Docker stoped/restarted的时候才重启容器
always |在容器已经stop掉或Docker stoped/restarted的时候才重启容器

restart policy细节

  1. 容器只有在成功启动后restart policy才能生效。这里的”成功启动”是指容器处于up至少10秒且已经处于docker监管。这是避免没有成功启动的容器陷入restart的死循环。
  2. 如果手动(manually)的stop(与前面的explicitly stopped有何区别)一个容器,容器设置的restart policy将会被忽略,除Docker daemon重启或者容器手动重启。这是避免了另外一种死循环。
  3. estart policies只能用于容器,对于swarm servicesrestart policies有不通过的配置。

停止容器运行

使用 docker stop 来停止正在运行的容器

1
2
3
4
5
6
7
Shuqing@LAPTOP-8B5JADC8 MINGW64 /d/Program Files/Docker Toolbox
$ docker stop 5e644f959f0b
5e644f959f0b

Shuqing@LAPTOP-8B5JADC8 MINGW64 /d/Program Files/Docker Toolbox
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

删除容器

1.使用 docker rm 删除已经停止的容器

1
2
$ docker rm 92d1b548ad88
92d1b548ad88

2.使用 docker rm -f 删除正在运行的容器

1
2
$ docker rm -f 5e644f959f0b
5e644f959f0b

Tips:可以删除多个容器 docker rm container1 container2

查看容器log

1
2
3
4
5
6
7
8

sudo docker logs -f -t CONTAINER_ID #查看容器日志

sudo docker logs -f -t --since="2018-02-08" --tail=100 CONTAINER_ID


#查看某个事件段的log
sudo docker logs -t --since="2018-02-08T13:23:37" --until "2018-02-09T12:23:37" CONTAINER_ID

参考资料