Docker容器

容器简介

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

 

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

启动容器

启动容器有两种方式:

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

新建启动容器

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

1
2
3
4
5
#创建后台运行容器
docker run -itd --name "lf-client-api" ubuntu /bin/bash

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

将容器保存为镜像

查看容器id

1
docker ps

保存的格式:

1
docker commit [选项] [容器ID或容器名]  [仓库名:标签]

例子:

1
2
3
4
5
6
7
8
9
10
11
mac@sutune0223 ~ % docker commit -a 'sutune' -m 'add appium' 22fea2c5fd87 lf_client:v1.3
sha256:1e9d954d091d54531fb15f73b6d9e5471f870948430ff2b18cc42a57a7fe4aa1
mac@sutune0223 ~ % docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
lf_client v1.3 1e9d954d091d 52 seconds ago 2.15GB
lf_client v1.2 c98b067ceebf 20 hours ago 1.57GB
lf_client v1.1 f92400514ad5 23 hours ago 1.24GB
lf_client v1 237cee06c7b8 23 hours ago 878MB
appium/appium latest c31dd6970796 4 months ago 1.56GB
centos centos7 eeb6ee3f44bd 5 months ago 204MB
centos latest 5d0da3dc9764 5 months ago 231MB

参数说明

  • -a 提交作者
  • -m 提交修改点

启动已经存在的容器

首先我们使用命令docker ps -a查询全部容器

1
2
3
4
5
6
docker@default:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e90cf586d3ce nginx "nginx -g 'daemon of…" 25 minutes ago Up 25 minutes 0.0.0.0:80->80/tcp webserver
cdc042ee37cb nginx "nginx -g 'daemon of…" 22 hours ago Exited (0) 22 hours ago quirky_ritchie
300cbb2050a5 ubuntu "/bin/bash" 22 hours ago Exited (127) 22 hours ago sutune
docker@default:~$

然后我们启动容器名称为sutune的容器,从状态来看该容器暂时已经停止运行。使用命令docker start 容器id 即可启动已经存在的容器。

1
2
3
4
5
6
7
docker@default:~$ docker start 300cbb2050a5  
300cbb2050a5
docker@default:~$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e90cf586d3ce nginx "nginx -g 'daemon of…" 27 minutes ago Up 27 minutes 0.0.0.0:80->80/tcp webserver
cdc042ee37cb nginx "nginx -g 'daemon of…" 22 hours ago Exited (0) 22 hours ago quirky_ritchie
300cbb2050a5 ubuntu "/bin/bash" 22 hours ago Up 3 seconds sutune

容器常用命令

创建容器

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

创建交互型容器

运行在前台,容器中使用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要在容器里面执行此命令。

创建后台型容器

创建后与终端无关,只有调用docker stopdocker kill命令才能使容器停止。这里以我们创建nginx服务为例子。

1
2
3
4
5
docker@default:~$ docker run -d  --name webserver -p 80:80 nginx
aab982ead42420ccef44ef071902cfb9b404645960b2be83272eee09bec5d3e8
docker@default:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
aab982ead424 nginx "nginx -g 'daemon of…" 5 seconds ago Up 4 seconds 0.0.0.0:80->80/tcp webserver

参数说明

  • -d (deamon):后台守护模式运行
  • -p (port):映射端口,这里我们指定映射端口为80。

启动容器之后在浏览器输入对应的地址http://ip地址或localhost:80即可访问nginx主页。

  • 如果是在 Linux 本机运行的 Docker,或者如果使用的是 Docker for Mac、Docker
    for Windows,那么可以直接访问:http://localhost;
  • 如果使用的是 Docker Toolbox(记得不要填宿主机的ip而是toolbox客户端显示虚拟机ip),或者是在虚拟机、云服务器上安装的 Docker,则需要将 localhost 换为虚拟机地址或者实际云服务器地址。

image

还可以直接输入镜像ID 来启动容器。

1
docker run -it  -d --name huawei-nova4  b73c14a14a11  /bin/bash

进入容器

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即可

如果我们想修改上面nginx服务的默认页面,我们可以进入到webserver容器进行修改。

1
2
3
4
docker@default:~$ docker exec -it webserver  /bin/bash
root@63d4136cbd69:/# echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
root@63d4136cbd69:/# exit
exit

执行之后刷新页面,我们可以看到nginx首页变成了我们自定义的页面内容。

image

查看容器列表

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 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 $(docker ps -a -q)

删除容器

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

3.删除全部容器

1
docker rm $(docker ps -a -q)

查看容器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

查看容器详细信息

使用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网络的转发原理,docker中的网络是通过NAT转发至宿主主机处理的,遂查询宿主主机防火墙NAT转发情况:

1
2
firewall-cmd --query-masquerade
no

通过以上情况可见在此宿主主机中防火墙的NAT转发并未开启,通过以下命令开启,并重启防火墙:

1
2
firewall-cmd --zone=public --add-masquerade --permanent
firewall-cmd --reload

方法2

把docker0网卡添加到trusted域

1
2
firewall-cmd --permanent --zone=trusted --change-interface=docker0
firewall-cmd --reload

然后关闭所有容器

1
docker stop $(docker ps -aq)

重启docker服务

1
systemctl restart docker.service

参考资料