前言

啊,一转眼好久都没更新了,这一大段时间都在搞生活中的”其他”的东西,至于技术上的东西没有搞多少,算是体验了一把另一种境界的生活吧。其实我觉得还是一个人的生活好一点,我这么说的原因可能是因为我不适应两个人的生活,但也无妨。总之两个人相处起来真的很麻烦很难不排斥对方(除非是那种天作之合的,那种当我没说),就算现在不会以后某一天也肯定会。但如果要我说说两个人相处的优点是什么的话,那就是能减少很多负面情绪(有个小孩子陪在身边的感觉真的特别解压,整个人都感觉轻松了许多),还有就是能做一个人做不到的事情。罢了,感觉还是技术上的东西好一点,至少它不会因为我许久不复习不碰它而厌烦我,不因为我的某些不足而嫌弃我。

帮助命令

1
2
3
docker version		#显示 docker 的版本信息
docker info #显示 docker 的系统信息,包括镜像和容器的数量
docker 命令 --help #帮助命令

镜像命令

docker images 查看所有本地的主机上的镜像

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 5 months ago 13.3kB
#解释
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的id
CREATED 镜像的创建时间
SIZE 镜像的大小
#参数
-a,--all #列出所有镜像
-q,--quiet #只显示镜像的id

docker search 搜索镜像

1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]# docker search php
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
php While designed for web development, the PHP … 6470 [OK]
phpmyadmin/phpmyadmin A web interface for MySQL and MariaDB. 1153 [OK]
composer Composer is a dependency manager written in … 841 [OK]
adminer Database management in a single PHP file. 690 [OK] 0
#参数
--filter=STARS=5000 #只显示收藏为大于5000的结果
[root@localhost ~]# docker search php --filter=STARS=5000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
php While designed for web development, the PHP … 6470 [OK]

docker pull 下载镜像

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
# docker pull mysql 默认下载最新版(defualt-tag:laste)
[root@localhost ~]# docker pull mysql
Using default tag: latest
latest: Pulling from library/mysql
72a69066d2fe: Pull complete #分层下载--docker image 的核心联合文件系统
93619dbc5b36: Pull complete
99da31dd6142: Pulling fs layer
99da31dd6142: Pull complete
626033c43d70: Pull complete
37d5d7efb64e: Pull complete
ac563158d721: Pull complete
d2ba16033dad: Pull complete
688ba7d5c01a: Pull complete
00e060b6d11d: Pull complete
1c04857f594f: Pull complete
4d7cfa90e6ea: Pull complete
e0431212d27d: Pull complete
Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest #真实地址
#等价于 docker pull docker.io/library/mysql:latest

# 可选参数:指定版本--docker pull 镜像名(:tag)
[root@localhost ~]# docker pull mysql:5.7
5.7: Pulling from library/mysql
72a69066d2fe: Already exists
93619dbc5b36: Already exists
99da31dd6142: Already exists
626033c43d70: Already exists
37d5d7efb64e: Already exists
ac563158d721: Already exists
d2ba16033dad: Already exists
0ceb82207cd7: Pull complete
37f2405cae96: Pull complete
e2482e017e53: Pull complete
70deed891d42: Pull complete
Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7

docker rmi (-f) 删除镜像

-f:全部删除,默认为只删除一部分

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
#根据镜像id删除镜像
[root@localhost ~]# docker rmi -f 3218b38490ce
Untagged: mysql:latest
Untagged: mysql@sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709
Deleted: sha256:3218b38490cec8d31976a40b92e09d61377359eab878db49f025e5d464367f3b
Deleted: sha256:aa81ca46575069829fe1b3c654d9e8feb43b4373932159fe2cad1ac13524a2f5
Deleted: sha256:0558823b9fbe967ea6d7174999be3cc9250b3423036370dc1a6888168cbd224d
Deleted: sha256:a46013db1d31231a0e1bac7eeda5ad4786dea0b1773927b45f92ea352a6d7ff9
Deleted: sha256:af161a47bb22852e9e3caf39f1dcd590b64bb8fae54315f9c2e7dc35b025e4e3
Deleted: sha256:feff1495e6982a7e91edc59b96ea74fd80e03674d92c7ec8a502b417268822ff
Deleted: sha256:8805862fcb6ef9deb32d4218e9e6377f35fb351a8be7abafdf1da358b2b287ba
Deleted: sha256:872d2f24c4c64a6795e86958fde075a273c35c82815f0a5025cce41edfef50c7
Deleted: sha256:6fdb3143b79e1be7181d32748dd9d4a845056dfe16ee4c827410e0edef5ad3da
Deleted: sha256:b0527c827c82a8f8f37f706fcb86c420819bb7d707a8de7b664b9ca491c96838
Deleted: sha256:75147f61f29796d6528486d8b1f9fb5d122709ea35620f8ffcea0e0ad2ab0cd0
Deleted: sha256:2938c71ddf01643685879bf182b626f0a53b1356138ef73c40496182e84548aa
Deleted: sha256:ad6b69b549193f81b039a1d478bc896f6e460c77c1849a4374ab95f9a3d2cea2

#删除多个镜像 docker rmi -f 镜像id 镜像id 镜像id
...


#批量删除所有镜像 docker rmi -f $(docker images -qa)
[root@localhost ~]# docker rmi -f $(docker images -qa)
Untagged: hello-world:latest
Untagged: hello-world@sha256:4c5f3db4f8a54eb1e017c385f683a2de6e06f75be442dc32698c9bbe6c861edd
Deleted: sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412
[root@localhost ~]# docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
[root@localhost ~]#

docker commit 提交镜像到本地

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
docker commit -m="镜像的描述信息" -a="作者" 容器id 目的镜像名:[tag] #提交一个镜像成为一个新的副本

[root@localhost ~]# docker commit -m="nb app" -a="Jason" cc0bb tomcat:1.0
sha256:fa9ad8946199fe8ab03fca50f960061b5dcba0d4152370b8e707e855ecf61245

[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat 1.0 fa9ad8946199 3 seconds ago 684MB
nginx latest 605c77e624dd 2 months ago 141MB
tomcat latest fb5657adc892 2 months ago 680MB
mysql latest 3218b38490ce 2 months ago 516MB
hello-world latest feb5d9fea6a5 5 months ago 13.3kB
centos latest 5d0da3dc9764 6 months ago 231MB
portainer/portainer latest 580c0e4e98b0 12 months ago 79.1MB
elasticsearch 7.6.2 f29a1ee41030 23 months ago 791MB

#总结:docker commit 就像 Vmware 的快照,如果想保存当前容器的状态,就可以通过 commit 来提交,获得一个镜像

容器命令

说明:有了镜像才可以创建容器。下面先下载一个 centos 镜像来学习

1
docker pull centos

新建容器并启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
docker run [可选参数] image

#参数说明
--name="Name" 容器名字,用来区分容器
-d 以后台方式运行
-it 使用交互方式运行,进入容器
-p 指定容器的端口
-p 主机端口:容器端口 (常用)
-p 容器端口
容器端口
-P 随机指定端口

#测试
[root@localhost ~]# docker run --name="test01" -it centos /bin/bash
[root@31921b954d38 /]# ls
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr

[root@localhost ~]# exit #退出容器返回主机

[root@localhost ~]# docker ps [可选参数]
#列出正在运行的容器
-q #只显示容器id
-a #列出正在运行的容器+带出历史运行过的容器

退出容器

1
2
exit	#直接停止容器并退出
Ctrl + P + Q #容器不停止退出

删除容器

1
2
3
docker rm 容器id					#删除指定的容器
docker rm -f $(docker ps -aq) #递归删除所有容器(-f 强制删除)
docker ps -a -q | xargs docker rm #删除所有的容器

容器的基本操作

1
2
3
4
docker start   容器id	  #启动容器
docker restart 容器id #重启容器
docker stop 容器id #停止当前容器
docker kill 容器id #强制停止当前容器

docker后台运行

1
2
3
4
5
6
#docker run -d 镜像名
[root@localhost ~]# docker run -d centos
3350e4152a789818cc2f6dba0741f303135e256cc24c5fad8604eb4558b726df

#常见问题:docker 容器后台运行必须要有一个前台进程,如果没有进程,docker 就会自动停止
#比如 nginx 容器启动后,发现自己没有提供服务,就会立刻停止

查看日志

1
2
3
4
docker logs -tf --tail [number] 容器id

-tf #持续显示日志的全部内容,-t 为显示时间戳,-f为实时显示不停止
--tail number #要显示的日志条数

查看容器中的进程信息

1
2
3
4
#命令 docker top 容器id
[root@localhost ~]# docker top 511362a61c03
UID PID PPID C STIME TTY TIME CMD
root 85849 85830 58 08:10 ? 00:00:18 /bin/sh -c while true;do echo Hello_world;done;

查看容器的元数据

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#命令 docker inspect 容器id

#测试
[root@localhost ~]# docker inspect 511362a61c03
[
{
"Id": "511362a61c0393da14276bfffa7ce0270734af12395a6aa98074b3e2500f1edf" ,
"Created": "2022-03-15T00:10:34.455001435Z",
"Path": "/bin/sh",
"Args": [
"-c",
"while true;do echo Hello_world;done;"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 85849,
"ExitCode": 0,
"Error": "",
"StartedAt": "2022-03-15T00:10:34.866041026Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d484 7e53fadb6",
"ResolvConfPath": "/var/lib/docker/containers/511362a61c0393da14276bfffa 7ce0270734af12395a6aa98074b3e2500f1edf/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/511362a61c0393da14276bfffa7c e0270734af12395a6aa98074b3e2500f1edf/hostname",
"HostsPath": "/var/lib/docker/containers/511362a61c0393da14276bfffa7ce02 70734af12395a6aa98074b3e2500f1edf/hosts",
"LogPath": "/var/lib/docker/containers/511362a61c0393da14276bfffa7ce0270 734af12395a6aa98074b3e2500f1edf/511362a61c0393da14276bfffa7ce0270734af12395a6aa9 8074b3e2500f1edf-json.log",
"Name": "/friendly_hypatia",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/b91e003fef1b39b90cbd8b49b3 e9c8fe25e09c1c86e7a2fb3d3fc835c40fffe3-init/diff:/var/lib/docker/overlay2/32e67f df068d0a2e8264bac2319675a164e08b0e6292d94282e2c1111b1f6095/diff",
"MergedDir": "/var/lib/docker/overlay2/b91e003fef1b39b90cbd8b49b 3e9c8fe25e09c1c86e7a2fb3d3fc835c40fffe3/merged",
"UpperDir": "/var/lib/docker/overlay2/b91e003fef1b39b90cbd8b49b3 e9c8fe25e09c1c86e7a2fb3d3fc835c40fffe3/diff",
"WorkDir": "/var/lib/docker/overlay2/b91e003fef1b39b90cbd8b49b3e 9c8fe25e09c1c86e7a2fb3d3fc835c40fffe3/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "511362a61c03",
"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:/b in"
],
"Cmd": [
"/bin/sh",
"-c",
"while true;do echo Hello_world;done;"
],
"Image": "centos",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20210915",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "cd180f14c3b182ff9a20d4d653f839d170610508922c326dd92d23 62e53816f5",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/cd180f14c3b1",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "f91f6a390585f578df48a07fbaad1d94bdb6059808951adb6e409 15b8ffc74a1",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "6405814fc6a02a10fed38f97ca443d9a64bebb29a3016d bec3a91f5837e9f173",
"EndpointID": "f91f6a390585f578df48a07fbaad1d94bdb6059808951 adb6e40915b8ffc74a1",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]

进入当前正在运行的容器

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
#方式一
docker exec -it 容器id shell

[root@localhost ~]# docker exec -it 511362a61c03 /bin/bash
[root@511362a61c03 /]#
[root@511362a61c03 /]#
[root@511362a61c03 /]#
[root@511362a61c03 /]# ls
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr
[root@511362a61c03 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 57 00:10 ? 00:10:33 /bin/sh -c while true;do echo
root 7 0 0 00:28 pts/0 00:00:00 /bin/bash
root 23 7 0 00:28 pts/0 00:00:00 ps -ef

#方式二
docker attach 容器id
[root@localhost ~]# docker attach 511docker attach 511
Hello_world
Hello_world
Hello_world
Hello_world
Hello_world
Hello_world
Hello_world
Hello_world
Hello_world
Hello_world
Hello_world
Hello_world
Hello_world
Hello_world
Hello_world

#方式一和方式二的区别在于:
- exec 是进入容器后开启一个新的终端
- attch 是进入容器正在执行的终端

从容器内拷贝文件到主机上(手动)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#命令 docker cp 容器id:文件的绝对路径 目的主机路径

#新建一个容器并进入容器内部终端,在容器内 创建一个 flag.txt 并写入内容
[root@localhost ~]# docker run -it centos /bin/bash
[root@ec9c9ac4e5a9 /]# cd /root
[root@ec9c9ac4e5a9 ~]# echo "flag{1now22151523}" > flag.txt
[root@ec9c9ac4e5a9 ~]# ls

#关闭容器(即使关闭容器也不影响容器内的数据)
[root@ec9c9ac4e5a9 ~]docker attach ec9
[root@ec9c9ac4e5a9 ~]# exit
exit

#拷贝容器内的文件到主机
[root@localhost ~]# docker cp ec9:/root/flag.txt /tmp
[root@localhost ~]# cd /tmp
[root@localhost tmp]# ls
flag.txt
[root@localhost tmp]# cat flag.txt
flag{1now22151523}

练习一:docker 部署 nginx 服务器

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
#1.docker pull nginx 下载镜像
#2.以后台的方式启动镜像,并把镜像命名为 practice ,把容器内的 80 端口映射到宿主机的 1122 端口
docker run -d --name practice01 -p 1122:80 nginx
ea51820740eeee14e7a731e444b64f63b2f98e63d87c129bea60282110b21646
#3.curl localhost:1122 测试宿主机的 1122 端口是否映射成功
[root@localhost ~]# curl localhost:1122
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
#4.进入容器
[root@localhost ~]# docker exec -it practice01 /bin/bash
问题思考:如何将容器内的文件映射到宿主机上,主机修改文件内容后容器内的文件也跟着修改?

端口暴露的概念

image-20220315101707715

练习二:docker 部署tomcat

1
2
3
#1. docker run -it --rm tomcat 
- 解释:--rm为用完该镜像就删除,通常用于测试。直接执行 docker run 的时候 docker 会发现没有该镜像,然后自动去官网下载
剩下的省略............

练习三:docker 部署 es + Kibana

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
es有哪些特点?
- es 暴露的端口多
- 耗内存
- es 的目录要放到安全的目录,挂载

#1.启动 es
[root@localhost ~]# docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

#2.docker stats 查询cpu状态(实时更新的查询,所以也特别耗内存)
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
7423867f6320 elasticsearch 1.02% 380.3MiB / 972.3MiB 39.12% 656B / 0B 3.25GB / 299MB 42

#3.通过 curl 查看 es 是否成功了
[root@localhost ~]# curl localhost:9200
{
"name" : "7423867f6320",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "W6N9ydeOQlSHD6IauMkkew",
"version" : {
"number" : "7.6.2",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "ef48eb35cf30adf4db14086e8aabd07ef6fb113f",
"build_date" : "2020-03-26T06:34:37.794943Z",
"build_snapshot" : false,
"lucene_version" : "8.4.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}

docker 可视化

  • portainer

docker 的一个图形化管理工具,提供一个后台面板给我们管理

1
[root@localhost ~]# docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

image-20220315143934404

docker 镜像理解

镜像是什么?

镜像是一个轻量级、可独立执行的软件包,我们可以将镜像比作是一个里面装着各种生活用品的行李箱,里面包含了某个软件所需的所有内容。

docker 镜像加载原理

UnionFS(联合文件系统)

UnionFS(联合文件系统)是一种分层、高性能、轻量级的文件系统,它支持你对文件系统的修改作为一次提交来一层层叠加。镜像可以通过分层来进行继承,基于基础镜像,我们还可以制作不同的镜像

特性:一次加载多个文件,外面看到的却是一个整体的文件。

docker 镜像加载原理

docker 镜像实际上是由一层层的 unionFS 文件组成

bootfs(boot file system),里面主要包括 bootloader 和 kernel 内核,当我们刚启动 Linux 时会加载 bootfs 文件系统,docker 镜像最底层的就是 bootfs 。这一层是所有 Linux/Unix 通用的。当加载完 boot 后内存的使用权就交给 kernel 内核了,此时系统会卸载 bootfs。

rootfs(root file system) ,在 bootfs 之上,包含的就是典型的 /dev,/proc 等标准文件。不同的操作系统发行版有不同的 rootfs。

image-20220315150841266

总之,bootfs 是公用的,docker在下载系统时一般只需要下载不同系统的 rootfs 就行,只下载 rootfs 所占用的空间是非常小的,而且每个镜像就只包含一些基本命令、程序,所以 docker 镜像的一个文件相比传统的一个镜像文件要小得多。

docker 镜像分层理解

当我们去下载一个镜像的时候会发现镜像是分层下载的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost ~]# docker pull mysql
Using default tag: latest
latest: Pulling from library/mysql
72a69066d2fe: Pull complete
93619dbc5b36: Pull complete
99da31dd6142: Pull complete
626033c43d70: Pull complete
37d5d7efb64e: Pull complete
ac563158d721: Pull complete
d2ba16033dad: Pull complete
688ba7d5c01a: Pull complete
00e060b6d11d: Pull complete
1c04857f594f: Pull complete
4d7cfa90e6ea: Pull complete
e0431212d27d: Pull complete
Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709
Status: Downloaded newer image for mysql:latest

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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
[root@localhost ~]# docker inspect mysql
[
{
"Id": "sha256:3218b38490cec8d31976a40b92e09d61377359eab878db49f025e5d464 367f3b",
"RepoTags": [
"mysql:latest"
],
"RepoDigests": [
"mysql@sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738 bd5b8e7709"
],
"Parent": "",
"Comment": "",
"Created": "2021-12-21T02:56:09.173474776Z",
"Container": "aa68c4a47b8cb77d182249805229f0903d2f843badfe4aa4d700b06900 7dce6b",
"ContainerConfig": {
"Hostname": "aa68c4a47b8c",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3306/tcp": {},
"33060/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/b in",
"GOSU_VERSION=1.12",
"MYSQL_MAJOR=8.0",
"MYSQL_VERSION=8.0.27-1debian10"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"mysqld\"]"
],
"Image": "sha256:7bab64cb803b262704c0ad1fd393a352e9016324d31f9715096 329e267451aca",
"Volumes": {
"/var/lib/mysql": {}
},
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"DockerVersion": "20.10.7",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3306/tcp": {},
"33060/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/b in",
"GOSU_VERSION=1.12",
"MYSQL_MAJOR=8.0",
"MYSQL_VERSION=8.0.27-1debian10"
],
"Cmd": [
"mysqld"
],
"Image": "sha256:7bab64cb803b262704c0ad1fd393a352e9016324d31f9715096 329e267451aca",
"Volumes": {
"/var/lib/mysql": {}
},
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": null
},
"Architecture": "amd64",
"Os": "linux",
"Size": 515592044,
"VirtualSize": 515592044,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/a68b252dc1e8ee89182afd849b 3eed6b669af02a534526396cd08b7f74f3b900/diff:/var/lib/docker/overlay2/16c4da956db 9c9817885087e56fe102edc80940403a27ffa5c86ab96704e6b4b/diff:/var/lib/docker/overl ay2/f285fa03db52ffaab132d24861d4a5e74d32132499833b726189369dfa60691c/diff:/var/l ib/docker/overlay2/8173ebea8bb17a45893116c121a7f87c6c87fd1383866acdb8a4ae97aa4b6 792/diff:/var/lib/docker/overlay2/5f1ca592d6b9179b133ea3df1663c7239ba6d2e7be2052 0f29533629b8df9674/diff:/var/lib/docker/overlay2/0a03f210e6eab970880180e4836d8a6 45de4c0ce0897715a8f029d99719b33c0/diff:/var/lib/docker/overlay2/a3c434fc7bfdb0b7 c4d5279f63ec5e82ac2825b6134d92e72d300944b871e1ab/diff:/var/lib/docker/overlay2/c 6bdf76066b2b023dcde4e89a7cef578791bf831fcebb3e50b08debb2451f6d4/diff:/var/lib/do cker/overlay2/35fbbfeee282e858e8d9a513c1bcbc7cd0e55b2a475ac7966670e0ca2d87219f/d iff:/var/lib/docker/overlay2/e8ccbd231913197590a5245a5b25e6c9c375b3c95ec1a863246 1cfb9af8bd237/diff:/var/lib/docker/overlay2/a2699db39e47de82db4c02bed5e1a301bdad e9cd8020aee92b7020be4cdfd8ae/diff",
"MergedDir": "/var/lib/docker/overlay2/7916bf3d6d8b3f6def442092f ff5762841e802e18161beb84eaa7bf1a45153dd/merged",
"UpperDir": "/var/lib/docker/overlay2/7916bf3d6d8b3f6def442092ff f5762841e802e18161beb84eaa7bf1a45153dd/diff",
"WorkDir": "/var/lib/docker/overlay2/7916bf3d6d8b3f6def442092fff 5762841e802e18161beb84eaa7bf1a45153dd/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [ #这里显示的就是该镜像的分层结构
"sha256:ad6b69b549193f81b039a1d478bc896f6e460c77c1849a4374ab95f9 a3d2cea2",
"sha256:fba7b131c5c350d828ebea6ce6d52cdc751219c6287c4a7f13a51435 b35eac06",
"sha256:0798f2528e8383f031ebd3c6d351f7d9f7731b3fd12007e5f2fdcdc4 e1efc31a",
"sha256:a0c2a050fee24f87fde784c197a8b3eb66a3881b96ea261165ac1a01 807ffb80",
"sha256:d7a777f6c3a4ded4667f61398eb1f9b380db07bf48876f64d93bf30f b1393f96",
"sha256:0d17fee8db40d61d9ca0d85bff8b32ef04bbd09d77e02cc67c454c8f 84edb3d8",
"sha256:aad27784b7621a3e58bd03e5d798e505fb80b081a5070d7c822e4160 6b90a5c0",
"sha256:1d1f48e448f9b8abb9a2aad1e76d4746b69957882d1ddb9c11115302 d45fcbbd",
"sha256:c654c2afcbba8c359565df63f6ecee333c9cc6abaeaa39838b05b446 5a82758b",
"sha256:118fee5d988ac2057ab66d87bbebd1f18b865fb02a03ba0e23762af5 b55b0bd5",
"sha256:fc8a043a3c7556d9abb4fad3aefa3ab6a5e1c02abda5f924f036c696 687d094e",
"sha256:d67a9f3f65691979bc9e2b5ee0afcd4549c994f13e1a384ecf3e11f8 3d82d3f2"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]

理解:

​ 所有的 docker 始于一个基础镜像,当进行添加或者修改时,就会在其上面新增一个镜像层

image-20220315154517388

在添加额外镜像层的时候,镜像始终保持是当前所有镜像的组合。举个例子:每个镜像层包含三个文件,而镜像包含了两个镜像层的6个文件

image-20220315155603470

特点

docker 镜像都是只读的,当一个新的容器新建并启动时,一个新的可写的镜像曾呗加载到镜像层的顶部。

这就是我们所说的容器层,容器之下的都叫镜像层

容器数据卷

什么是容器数据卷?

假如我开了个 docker 数据都存储在这个 docker 里面,我不小心删除了这个 docker 后,数据就丢失了

如果我的 MySQL 只是搭建在 docker 里面,容易被别人删库跑路

总之,为了数据的持久化同步操作,就有了容器数据卷这个东西

容器数据卷的利用

方式一:使用命令 -v 参数挂载目录

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
#docker run -it -v 宿主机目录:容器内的目录 镜像名

[root@localhost home]# docker run -it -v /home/test:/home centos #将宿主机的 /home/test目录与容器内的 /home 目录绑定
[root@localhost home]# cd /home/
[root@localhost home]# ls
jason test

#该命令会将宿主机目录与容器内的指定目录绑定
[root@localhost test]# echo "flag{dsafaksjfhnajl}" > test01 #在宿主机创建文件 test01 并输入内容
[root@localhost test]# docker attach aa #进入上面创建的容器
[root@aa6af2f953ff /]# cd /home/
[root@aa6af2f953ff home]# ls
test01
[root@aa6af2f953ff home]# cat test01 #查看在宿主机端输入的同步到容器里内容
flag{dsafaksjfhnajl}

#当删除该容器后,在宿主机端输入的内容会被清空,但目录不会被删除
[root@localhost test]# docker rm -f aa #删除容器
aa
[root@localhost test]# ls
test01 test02
[root@localhost test]# cat test01 #test01内容被清空
[root@localhost test]# cat test02 #test02内容也一样被清空
[root@localhost test]# ls #但是 test01,test02 这两个文件还存在
test01 test02

#在容器内输入的同步到宿主机的内容还会存在
[root@localhost test]# docker run -it -v /home/test:/home centos /bin/bash
[root@aa6f8263a1de /]# cd /home
[root@aa6f8263a1de home]# echo "Hello World" > domo01
[root@localhost test]# cat domo01 #退回到宿主机查看容器内创建的文件
Hello World
[root@localhost test]# docker rm -f $(docker ps -qa) #删除容器
aa6f8263a1de
[root@localhost test]# ls
domo01
[root@localhost test]# cat domo01 #宿主机的文件及其内容都还存在
Hello World

#使用 docker inspect 镜像id 命令可查看详细挂载信息
[root@localhost test]# docker inspect aa6
"Mounts": [
{
"Type": "bind",
"Source": "/home/test",
"Destination": "/home",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],

#即使该容器没有启动也可以同步数据
[root@localhost test]# docker stop aa
aa
[root@localhost test]# echo "test file 02" > test02
[root@localhost test]# docker start aa
aa
[root@localhost test]# docker exec -it aa /bin/bash
[root@aa6af2f953ff /]# cd /home/
[root@aa6af2f953ff home]# ls
test01 test02
[root@aa6af2f953ff home]# cat test02
test file 02

实战:安装MySQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#安装 mysql 镜像
docker pull mysql:5.7

#启动并配置mysql,需要挂载mysql配置文件和数据库文件,暴露mysql端口
[root@localhost ~]# docker run -d --name=mysql01 -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
f989642867e44fd097b0da823cbed56e99fcc26b606e8d2618958746ddb7a83a

#测试连接数据库
[root@localhost data]# mysql -h 192.168.1.48 -u root -p123456 -P 3310
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.37 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]>


注意:即使把 mysql 的容器删除了,映射到宿主机内的文件依然还会存在,这就实现了数据持久化功能

具名挂载与匿名挂载

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
#匿名挂载
docker run -d -P -v /etc/nginx nginx

#我们在创建容器的时候 -v 没有指定宿主机的路径,只指定了容器内的路径,这就叫匿名挂载

#查看所有 volume(卷) 的情况
[root@localhost home]# docker volume ls
DRIVER VOLUME NAME
local 3b638d54496eb7e558f07f22be49fb991d67905e2cc9b243945be13da2de70f7
local 369cc4f4988845e564eff04e9684d3e624661bb82c6177a45b59ddb0cba255a9
local c803595c19f42c5d36f16de3e334c270414436657486429ba728b38b05abea50
local e6e8613fa4412b7af191aa03c9cfe1e642dc5abd8ec3a3849b8bbc437de7bc74
local f92e90a908de06ed19b821bef00e77532f06f2c004e34b159ee0f6ed4c6cf089
local fd90c687af476f8a3efc96421b926e8d6b2033b453952b3119f87ee54a3b6dd9

#查看所有 volume(卷) 的详细信息
[root@localhost home]# docker volume inspect 3b638d54496eb7e558f07f22be49fb991d67905e2cc9b243945be13da2de70f7
[
{
"CreatedAt": "2022-03-17T12:17:28+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/3b638d54496eb7e558f07f22be49fb991d67905e2cc9b243945be13da2de70f7/_data",
"Name": "3b638d54496eb7e558f07f22be49fb991d67905e2cc9b243945be13da2de70f7",
"Options": null,
"Scope": "local"
}
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#具名挂载
docker run -d --name=nginx02 -v juming:/etc/nginx nginx

#具名挂载就是 -v 卷名:容器内路径

#查看具名挂载的具体路径
[root@localhost home]# docker volume inspect juming
[
{
"CreatedAt": "2022-03-18T09:24:26+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming/_data",
"Name": "juming",
"Options": null,
"Scope": "local"
}
]

共同特点:所有默认的挂载目录都是在 /var/lib/docker/volumes/ 下

通过具名挂载能够更方便找到我们的一个卷,通常用的都是具名挂载

1
2
3
4
#如何区分匿名挂载、具名挂载和指定路径挂载?
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v 指定路径:容器内路径 #指定路径挂载

拓展:

1
2
3
4
5
6
7
8
9
10
docker run -d -v nginx01:/etc/nginx:ro nginx
docker run -d -v nginx02:/etc/nginx:rw nginx

#如上,很多时候我们会看到 卷名:容器内路径:rw/ro 这种情况
-ro 表示只可以在宿主机内修改卷的内容
-rw 表示既可以在宿主机修改卷的内容,也可以在容器内修改卷的内容

#如果在 -ro 的容器内修改卷的内容,就会修改不成功,且有以下报错提示:
root@bf123badfec0:/# echo ""> /etc/nginx/nginx.conf
bash: /etc/nginx/nginx.conf: Read-only file system

初识Dockerfile

​ Dockerfile 是用来构建 docker 镜像的一个命令脚本,通过这个可以生成镜像,镜像是一层层的,每一个命令代码就是一层。

编辑 Dockerfile 文件,先尝试构建一个 docker 镜像,Dockerfile文件内容如下:

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
#构建 docker 镜像的命令
docker build -f [Dockfile] -t [镜像的REPOSITORY]:[tag] .

#编辑 Dockerfile 文件,并输入以下内容
[root@localhost ~]# vim Dockerfile01
FROM centos

VOLUME ["volume01","volume02"]

CMD echo "---end---"
CMD /bin/bash

#构建 docker 镜像,注意命令最后还有一个小点
[root@localhost ~]# docker build -f Dockerfile01 -t jason/centos:1.0 .

#在 Docekrfile 文件中我们挂载了两个匿名卷,volume01 和 volume02,可以通过 docker inspect 容器id 来查看具体信息

[root@localhost ~]# docker inspect 45b
"Mounts": [
{
"Type": "volume",
"Name": "737360e9fd68fc84b932220854612731e04fdaa6306acc32f1349ae821c63485",
"Source": "/var/lib/docker/volumes/737360e9fd68fc84b932220854612731e04fdaa6306acc32f1349ae821c63485/_data",
"Destination": "volume01",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "554e2768d0b38b18eb975d48c2a27882ab22edd419ce67110256da9173dcad08",
"Source": "/var/lib/docker/volumes/554e2768d0b38b18eb975d48c2a27882ab22edd419ce67110256da9173dcad08/_data",
"Destination": "volume02",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],

数据卷容器

在上面我们已经学会了如何让容器挂载宿主机,使宿主机与容器内的指定目录绑定。那我们可以思考一下,容器与容器之间能不能挂载,使多个容器之间共享数据呢?别说,还真有!

容器二挂载容器一的指定目录,容器一就叫做数据卷容器,它们之间共享数据也不复杂,靠的就是一个 volumes-from 参数

image-20220318201018997

我们用上面 初识Dockerfile 创建的镜像 jason/centos:1.0 来举例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#我们先创建一个数据卷容器 docker01,用于当作被挂载容器
[root@localhost volumes]# docker run -it --name docker01 jason/centos:1.0 /bin/bash

#然后我们再创建一个 docker02 并 volumes-from 挂载 docker01
[root@localhost volumes]# docker run -it --name docker02 --volumes-from docker01 jason/centos:1.0 /bin/bash

#我们可以列出宿主机的默认卷目录查看是否成功,如果像下面那样只生成了 docker01 的两个卷就是成功了
[root@localhost volumes]# ls /var/lib/docker/volumes/
4bff05bb030c0c804d6e967760cd8227967b1c141ca29254fa3f71eace49eb53
bff50c790bc6c4660402cfa63f6a72a269acabd3bc989c9c93f1bb557ff2c991

#我们现在去 docker01 的 volume01 目录创建一个 test.txt 文件,
[root@localhost volumes]# docker attach docker01
[root@75ef626d98eb /]# cd volume01
[root@75ef626d98eb volume01]# touch test.txt
[root@75ef626d98eb volume01]# ls
test.txt

#然后再进入 docker02 容器内的 volume01 目录,发现也有一个 test.txt 文件
[root@localhost volumes]# docker attach docker02
[root@1d5dea5e464f /]# cd volume01
[root@1d5dea5e464f volume01]# ls
test.txt

思考一下,假如 docker01 镜像被删除了,docker02 同步的数据会不会也会跟着被删除?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#查看 docker01 的容器id
[root@localhost volumes]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1d5dea5e464f jason/centos:1.0 "/bin/bash" 11 minutes ago Up 11 minutes docker02
75ef626d98eb jason/centos:1.0 "/bin/bash" 12 minutes ago Up 12 minutes docker01

#将 docker01 这个容器删除
[root@localhost volumes]# docker rm -f 75e
75e

#删除后再进入 docker02 发现同步过来的数据依然存在
[root@localhost volumes]# docker attach 1d5d
[root@1d5dea5e464f volume01]# ls
test.txt


很明显,当 docekr01 镜像被删除后,docker02 同步的数据不跟着被删除

下面是多个 mysql 实现共享的案例

1
2
3
4
#创建数据卷容器
[root@localhost volumes]# docker run -it --name mysql01 -v conf:/etc/mysql/conf.d -v data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7

略..........

总结:容器中数据共享,按我的理解的话就是多个容器挂载宿主机对应的卷目录,当宿主机的卷目录删除了或者清空了就什么都没有了

Dockerfile

Dockerfile 介绍

简单点来说,Dockerfile 是用来构建 docker 镜像的文件的命令脚本。

构建步骤:

  1. 编写一个 Dockerfile 文件
  2. docker build 构建 dockerfile 镜像
  3. docker run 运行镜像
  4. docker push 发布镜像(Dockerhub、阿里云镜像仓库)

Dockerfile命令

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM		# 基础镜像,一切丛这里开始构建
MAINTAINER # 镜像是谁写的,通常是姓名+邮箱
RUN # 镜像构建的时候需要运行的命令
ADD # 添加压缩包或者文件
COPY # 类似 ADD ,将我们的文件拷贝到镜像中
WORKDIR # 镜像的工作目录
VOLUME # 挂载的目录
EXPOST # 暴露端口
ONBUILD # 当构建一个被继承的 Dockerfile 的时候就会运行 ONBUILD 指令,触发指令。
ENV # 构建的时候设置环境变量

CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令

查看源图像

创建一个自己的 centos

原来的 centos 里面是没有 vim 工具的,也用不了 ifconfig 命令,所以我们在自己构建的镜像里安装 net-tools 和 vim

1
2
3
4
5
6
7
8
9
10
11
# 构建自己的 centos
[root@localhost docker]# cat dockerfile
FROM centos
MAINTAINER Jason<1711798892@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum install net-tools -y
RUN yum install vim -y
EXPOSE 80
CMD echo $MYPATH
CMD /bin/bash

构建

1
docker build -f dockerfile

查看镜像构建过程

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
docker history 容器id

# 列出已下载的所有镜像
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat latest 97f970b9f6d1 36 hours ago 680MB
jason/centos 1.0 ce99e148a4bd 3 days ago 231MB
nginx latest f2f70adc5d89 4 days ago 142MB
tomcat <none> 5cae83f90298 5 days ago 685MB
mysql 5.7 11d8667108c2 13 days ago 450MB
centos latest 5d0da3dc9764 6 months ago 231MB

# 查看 tomcat 镜像的构建过程
[root@localhost ~]# docker history 97f
IMAGE CREATED CREATED BY SIZE COMMENT
97f970b9f6d1 36 hours ago /bin/sh -c #(nop) CMD ["catalina.sh" "run"] 0B
<missing> 36 hours ago /bin/sh -c #(nop) EXPOSE 8080 0B
<missing> 36 hours ago /bin/sh -c set -eux; nativeLines="$(catalin… 0B
<missing> 36 hours ago /bin/sh -c set -eux; savedAptMark="$(apt-m… 20.2MB
<missing> 36 hours ago /bin/sh -c #(nop) ENV TOMCAT_SHA512=a9e3c51… 0B
<missing> 36 hours ago /bin/sh -c #(nop) ENV TOMCAT_VERSION=10.0.18 0B
<missing> 37 hours ago /bin/sh -c #(nop) ENV TOMCAT_MAJOR=10 0B
<missing> 37 hours ago /bin/sh -c #(nop) ENV GPG_KEYS=A9C5DF4D22E9… 0B
<missing> 37 hours ago /bin/sh -c #(nop) ENV LD_LIBRARY_PATH=/usr/… 0B
<missing> 37 hours ago /bin/sh -c #(nop) ENV TOMCAT_NATIVE_LIBDIR=… 0B
<missing> 37 hours ago /bin/sh -c #(nop) WORKDIR /usr/local/tomcat 0B
<missing> 37 hours ago /bin/sh -c mkdir -p "$CATALINA_HOME" 0B
<missing> 37 hours ago /bin/sh -c #(nop) ENV PATH=/usr/local/tomca… 0B
<missing> 37 hours ago /bin/sh -c #(nop) ENV CATALINA_HOME=/usr/lo… 0B
<missing> 2 days ago /bin/sh -c #(nop) CMD ["jshell"] 0B
<missing> 2 days ago /bin/sh -c set -eux; arch="$(dpkg --print-… 343MB
<missing> 2 days ago /bin/sh -c #(nop) ENV JAVA_VERSION=11.0.14.1 0B
<missing> 2 days ago /bin/sh -c #(nop) ENV LANG=C.UTF-8 0B
<missing> 2 days ago /bin/sh -c #(nop) ENV PATH=/usr/local/openj… 0B
<missing> 2 days ago /bin/sh -c { echo '#/bin/sh'; echo 'echo "$J… 27B
<missing> 2 days ago /bin/sh -c #(nop) ENV JAVA_HOME=/usr/local/… 0B
<missing> 2 days ago /bin/sh -c set -eux; apt-get update; apt-g… 11.3MB
<missing> 3 days ago /bin/sh -c apt-get update && apt-get install… 152MB
<missing> 3 days ago /bin/sh -c set -ex; if ! command -v gpg > /… 18.9MB
<missing> 3 days ago /bin/sh -c set -eux; apt-get update; apt-g… 10.7MB
<missing> 4 days ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 4 days ago /bin/sh -c #(nop) ADD file:19873be7a1c793d8e… 124MB

CMD 与 ENTRYPOINT 的区别

CMD-test

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
# 我们先创建一个 cnetos 镜像,只执行 ls -l 命令
[root@localhost docker]# cat dockerfile-cmd-test
FROM centos:7
CMD ["ls","-l"]
[root@localhost docker]# docker build -f dockerfile-cmd-test -t cmd_test .

# 然后运行镜像,发现容器执行了 ls -l
[root@localhost docker]# docker run cmd_test
total 12
-rw-r--r--. 1 root root 12114 Nov 13 2020 anaconda-post.log
lrwxrwxrwx. 1 root root 7 Nov 13 2020 bin -> usr/bin
drwxr-xr-x. 5 root root 340 Mar 22 00:52 dev
drwxr-xr-x. 1 root root 66 Mar 22 00:52 etc
drwxr-xr-x. 2 root root 6 Apr 11 2018 home
lrwxrwxrwx. 1 root root 7 Nov 13 2020 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Nov 13 2020 lib64 -> usr/lib64
drwxr-xr-x. 2 root root 6 Apr 11 2018 media
drwxr-xr-x. 2 root root 6 Apr 11 2018 mnt
drwxr-xr-x. 2 root root 6 Apr 11 2018 opt
dr-xr-xr-x. 225 root root 0 Mar 22 00:52 proc
dr-xr-x---. 2 root root 114 Nov 13 2020 root
drwxr-xr-x. 11 root root 148 Nov 13 2020 run
lrwxrwxrwx. 1 root root 8 Nov 13 2020 sbin -> usr/sbin
drwxr-xr-x. 2 root root 6 Apr 11 2018 srv
dr-xr-xr-x. 13 root root 0 Mar 21 23:34 sys
drwxrwxrwt. 7 root root 132 Nov 13 2020 tmp
drwxr-xr-x. 13 root root 155 Nov 13 2020 usr
drwxr-xr-x. 18 root root 238 Nov 13 2020 var

# 假如我们再加个参数 -a 进去,发现原来的"ls -l"命令被替换成了"-a"命令,因为容器没有"-a"这个命令,所以报错
[root@localhost docker]# docker run cmd_test -a
docker: Error response from daemon: failed to create shim: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-a": executable file not found in $PATH: unknown.

ENTRYPOINT-test

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
# 构建镜像
[root@localhost docker]# docker build -f dockerfile-entrypoint-test -t entrypoint .
[root@localhost docker]# cat dockerfile-entrypoint-test
FROM centos:7
ENTRYPOINT ["ls","-l"]

# 发现 entrypoint 可以追加参数致使原来的"ls -l"变成"ls -al"
[root@localhost docker]# docker run entrypoint -a
total 12
drwxr-xr-x. 1 root root 6 Mar 22 00:57 .
drwxr-xr-x. 1 root root 6 Mar 22 00:57 ..
-rwxr-xr-x. 1 root root 0 Mar 22 00:57 .dockerenv
-rw-r--r--. 1 root root 12114 Nov 13 2020 anaconda-post.log
lrwxrwxrwx. 1 root root 7 Nov 13 2020 bin -> usr/bin
drwxr-xr-x. 5 root root 340 Mar 22 00:57 dev
drwxr-xr-x. 1 root root 66 Mar 22 00:57 etc
drwxr-xr-x. 2 root root 6 Apr 11 2018 home
lrwxrwxrwx. 1 root root 7 Nov 13 2020 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Nov 13 2020 lib64 -> usr/lib64
drwxr-xr-x. 2 root root 6 Apr 11 2018 media
drwxr-xr-x. 2 root root 6 Apr 11 2018 mnt
drwxr-xr-x. 2 root root 6 Apr 11 2018 opt
dr-xr-xr-x. 227 root root 0 Mar 22 00:57 proc
dr-xr-x---. 2 root root 114 Nov 13 2020 root
drwxr-xr-x. 11 root root 148 Nov 13 2020 run
lrwxrwxrwx. 1 root root 8 Nov 13 2020 sbin -> usr/sbin
drwxr-xr-x. 2 root root 6 Apr 11 2018 srv
dr-xr-xr-x. 13 root root 0 Mar 21 23:34 sys
drwxrwxrwt. 7 root root 132 Nov 13 2020 tmp
drwxr-xr-x. 13 root root 155 Nov 13 2020 usr
drwxr-xr-x. 18 root root 238 Nov 13 2020 var

总结:CMD 与 ENTRYPOINT 的区别在于,ENTRTPOINT 可以在命令外面追加参数,CMD 却不行