StephenShawn's Blog

love&&curiosity

Docker容器数据卷

原理:将容器目录挂载到Linux的目录

容器的持久化和同步操作 !容器间也是可以数据共享的

使用数据卷

方式一:直接使用命令来挂载 -v

1
docker run -it -v 主机目录:容器内目录
安装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
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
# 获取镜像 
[root@localhost ~]# docker pull mysql:5.7

# 不挂载数据
## 查看主机是否有msql服务
[root@localhost home]# ps -ef |grep mysql
root 13049 12627 0 14:40 pts/5 00:00:00 grep --color=auto mysql
## 启动mysql容器
[root@localhost home]# docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
95a10c860fd5ab401b7d29f728addff9b99f1f2a6b28286d78d9d78958843a6b
## 查看msql容器是否运行
[root@localhost home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
95a10c860fd5 mysql:5.7 "docker-entrypoint.s…" 6 seconds ago Up 5 seconds 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp kind_shannon
## 进入mysql容器内
[root@localhost home]# docker exec -it 95a10c860fd5 /bin/bash
## 登录mysql
root@95a10c860fd5:/# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.36 MySQL Community Server (GPL)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
## 查看数据库有哪些
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)
## 创建数据库
mysql> create database db01;
Query OK, 1 row affected (0.00 sec)
## 使用数据库
mysql> use db01
Database changed
## 创建表student
mysql> create table student(id int,name varchar(20));
Query OK, 0 rows affected (0.01 sec)
## 向student表插入数据
mysql> insert into student values(1,'z3');
Query OK, 1 row affected (0.04 sec)
## 查询student表所有数据
mysql> select * from student ;
+------+------+
| id | name |
+------+------+
| 1 | z3 |
+------+------+
1 row in set (0.00 sec)

mysql> select * from student;
+------+------+
| id | name |
+------+------+
| 1 | z3 |
| 2 | lisi |
+------+------+
2 rows in set (0.00 sec)
## 查看数据库默认字符集为latin1
mysql> show variables like 'character%' ;
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.01 sec)

# 运行容器 需要做数据挂载!
[root@localhost ~]# docker run -d -p 3306:3306 \
--privileged=true \
-v /home/mysql/conf:/etc/mysql/conf.d \
-v /home/mysql/data:/var/lib/mysql \
-v /home/mysql/log:/var/log/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name mysql01 mysql:5.7
#修改字符集
# 创建my.conf并填入以下内容
vi /home/mysql/conf/my.cnf
# 方法一
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = uft8
# 方法二
[mysql]
default-character-set=utf8mb4
[mysqld]
character_set_server = utf8
init_connect='SET NAMES utf8'
lower_case_table_names=1
# 方法三
[root@localhost ~]# docker run -d -p 3306:3306 \
--privileged=true \
-v /home/mysql/conf:/etc/mysql/conf.d \
-v /home/mysql/data:/var/lib/mysql \
-v /home/mysql/log:/var/log/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--name mysql01 mysql:5.7 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci
##
新项目只考虑utf8mb4
  UTF-8 编码是一种变长的编码机制,可以用1~4个字节存储字符。

  因为历史遗留问题,MySQL 中的 utf8 编码并不是真正的 UTF-8,而是阉割版的,最长只有3个字节。当遇到占4个字节的 UTF-8 编码,例如 emoji 字符或者复杂的汉字,也就是我们通常在聊天时发的小黄脸表情,会导致存储异常。

  从 5.5.3 开始,MySQL 开始用 utf8mb4 编码来实现完整的 UTF-8,其中 mb4 表示 most bytes 4,最多占用4个字节,用来兼容四个字节的Unicode(万国码)。utf8mb4是utf8的一个扩展。从 8.0 之后,将会在某个版本开始用 utf8mb4 作为默认字符编码。
# 重启mysql02
docker restart mysql02

具名与匿名挂载

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
# 查看卷的命令

# [root@localhost home]# docker volume --help

Usage: docker volume COMMAND

Manage volumes

Commands:
create Create a volume
inspect Display detailed information on one or more volumes
ls List volumes
prune Remove all unused local volumes
rm Remove one or more volumes

-v 容器内路径!
docker run -d -P

# 匿名挂载
[root@localhost home]# docker run -d -P --name nginx01 -v /etc/nginx nginx
# 具名挂载
# -v 卷名:容器内路径
[root@localhost home]# docker run -d -P --name nginx02 -v my-nginx:/etc/nginx nginx
# 查看挂载路径
[root@localhost home]# docker volume inspect my-nginx
[
{
"CreatedAt": "2022-06-28T22:46:09-04:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/my-nginx/_data",
"Name": "my-nginx",
"Options": null,
"Scope": "local"
}
]
# 所有的docker容器内的卷,没有自定义目录的情况下都是在/var/lib/docker/volumes/xxx/_data
1
2
3
4
5
6
7
8
9
10
11
# 如何确定是具名挂载还是匿名挂载,还是指定路径挂载!
-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /宿主机路径:/容器内路径 # 指定路径挂载

# 通过 -v 容器内路径:ro rw 改变读写权限
ro readonly #只读
rw readwrite #读写
# 一旦这个设置容器权限,容器对我们挂载出来的内容就有先限定了!
docker run -d -P --name nginx02 -v my-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v my-nginx:/etc/nginx:rw nginx

初识Dockerfile

Dockerfile 就是用来构建 docker 镜像的构建文件 ! 命令脚本!

通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个个的命令,每个命令都是一层!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 编写dockerfile脚本
[root@localhost docker-test-volume]# vi dockerfile1
[root@localhost docker-test-volume]# cat dockerfile1
FORM centos

VOLUME ["volume01","volume02"]

CMD echo "------end------"
CMD /bin/bash
# 构建镜像
[root@localhost docker-test-volume]# docker build -f dockerfile1 -t shawn/centos:1.0 .
-f 指定dockerfile文件
-t 指定镜像名以及版本
. 在当前目录生成

# 数据卷同步
docker run -it --name docker03 --volumes-from docker01 shawn/centos:1.0(镜像启动)

结论:

容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。

但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的

DockerFile构建过程

基础知识

1、每个保留关键字(指令)都是必须是大写字母

2、执行从上到下顺序执行

3、#表示注释

4、每个指令都会创建提交一个新的镜像层,并提交!

1
2
3
4
5
可写容器(container)
镜像(tomcat)
镜像(jdk)
rootfs(基础镜像 centos/ubuntu)
bootfs

dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单!

Docker镜像逐渐成为企业交付的标准,必须要掌握 !

步骤:开发 部署 运维 缺一不可 !

DockerFile:构建文件,定义了一切的步骤,源代码

DockerImages:通过DockerFile构建生成镜像,最终发布与运行的产品

Docker容器:容器就是镜像运行起来提供服务的

Dockerfile指令

1
2
3
4
5
6
7
8
9
10
11
12
FROM       # 基础镜像,一切从这里开始构建
MAINTAINER # 镜像是谁写的,姓名+邮箱
RUN # 镜像构建的时候需要运行的命令
ADD # 步骤:tomcat镜像,这个tomcat压缩包!添加内容
WORKDIR # 镜像的工作目录
VOLUME # 挂载的目录
EXPOSE # 保留端口配置
CMD # 指定容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT # 指定容器启动的时候要运行的命令,可以追加命令
ONBUILD # 当构建一个被继承DockerFile 这个时候就会运行 ONBUILD 的指令。触发指令。
COPY # 类似ADD,将我们文件拷贝到镜像中
ENV # 构建的时候设置环境变量!
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
FROM

功能为指定基础镜像,并且必须是第一条指令。

如果不以任何镜像为基础,那么写法为:FROM scratch。

同时意味着接下来所写的指令将作为镜像的第一层开始

语法:

FROM <image>
FROM <image>:<tag>
FROM <image>:<digest>
三种写法,其中<tag>和<digest> 是可选项,如果没有选择,那么默认值为latest

RUN

功能为运行指定的命令

RUN命令有两种格式

1. RUN <command>
2. RUN ["executable", "param1", "param2"]
第一种后边直接跟shell命令

在linux操作系统上默认 /bin/sh -c

在windows操作系统上默认 cmd /S /C

第二种是类似于函数调用。

可将executable理解成为可执行文件,后面就是两个参数。

两种写法比对:

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME
RUN ["/bin/bash", "-c", "echo hello"]
注意:多行命令不要写多个RUN,原因是Dockerfile中每一个指令都会建立一层.

多少个RUN就构建了多少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错。

RUN书写时的换行符是\

CMD

功能为容器启动时要运行的命令

语法有三种写法

1. CMD ["executable","param1","param2"]
2. CMD ["param1","param2"]
3. CMD command param1 param2
第三种比较好理解了,就时shell这种执行方式和写法

第一种和第二种其实都是可执行文件加上参数的形式

举例说明两种写法:

CMD [ "sh", "-c", "echo $HOME"
CMD [ "echo", "$HOME" ]
补充细节:这里边包括参数的一定要用双引号,就是",不能是单引号。千万不能写成单引号。

原因是参数传递后,docker解析的是一个JSON array

RUN & CMD

不要把RUN和CMD搞混了。

RUN是构件容器时就运行的命令以及提交运行结果

CMD是容器启动时执行的命令,在构件时并不运行,构件时紧紧指定了这个命令到底是个什么样子

LABEL

功能是为镜像指定标签

语法:

LABEL <key>=<value> <key>=<value> <key>=<value> ...
一个Dockerfile种可以有多个LABEL,如下:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
但是并不建议这样写,最好就写成一行,如太长需要换行的话则使用\符号

如下:

LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
说明:LABEL会继承基础镜像种的LABEL,如遇到key相同,则值覆盖

MAINTAINER

指定作者

语法:

MAINTAINER <name>
EXPOSE

功能为暴漏容器运行时的监听端口给外部

但是EXPOSE并不会使容器访问主机的端口

如果想使得容器与主机的端口有映射关系,必须在容器启动的时候加上 -P参数

ENV

功能为设置环境变量

语法有两种

1. ENV <key> <value>
2. ENV <key>=<value> ...
两者的区别就是第一种是一次设置一个,第二种是一次设置多个

ADD

一个复制命令,把文件复制到景象中。

如果把虚拟机与容器想象成两台linux服务器的话,那么这个命令就类似于scp,只是scp需要加用户名和密码的权限验证,而ADD不用。

语法如下:

1. ADD <src>... <dest>
2. ADD ["<src>",... "<dest>"]
<dest>路径的填写可以是容器内的绝对路径,也可以是相对于工作目录的相对路径

<src>可以是一个本地文件或者是一个本地压缩文件,还可以是一个url

如果把<src>写成一个url,那么ADD就类似于wget命令

如以下写法都是可以的:

ADD test relativeDir/
ADD test /relativeDir
ADD http://example.com/foobar /
尽量不要把<scr>写成一个文件夹,如果<src>是一个文件夹了,复制整个目录的内容,包括文件系统元数据

COPY

看这个名字就知道,又是一个复制命令

语法如下:

1. COPY <src>... <dest>
2. COPY ["<src>",... "<dest>"]
ADD的区别

COPY的<src>只能是本地文件,其他用法一致

ENTRYPOINT

功能是启动时的默认命令

语法如下:

1. ENTRYPOINT ["executable", "param1", "param2"]
2. ENTRYPOINT command param1 param2
如果从上到下看到这里的话,那么你应该对这两种语法很熟悉啦。

第二种就是写shell

第一种就是可执行文件加参数

CMD比较说明(这俩命令太像了,而且还可以配合使用):

1. 相同点:

只能写一条,如果写了多条,那么只有最后一条生效

容器启动时才运行,运行时机相同

2. 不同点:

ENTRYPOINT不会被运行的command覆盖,而CMD则会被覆盖

如果我们在Dockerfile种同时写了ENTRYPOINT和CMD,并且CMD指令不是一个完整的可执行命令,那么CMD指定的内容将会作为ENTRYPOINT的参数

如下:

FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
如果我们在Dockerfile种同时写了ENTRYPOINT和CMD,并且CMD是一个完整的指令,那么它们两个会互相覆盖,谁在最后谁生效

如下:

FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ls -al
那么将执行ls -al ,top -b不会执行。

Docker官方使用一张表格来展示了ENTRYPOINT 和CMD不同组合的执行情况

(下方表格来自docker官网)



VOLUME

可实现挂载功能,可以将内地文件夹或者其他容器种得文件夹挂在到这个容器种

语法为:

VOLUME ["/data"]


说明:

["/data"]可以是一个JsonArray ,也可以是多个值。所以如下几种写法都是正确的

VOLUME ["/var/log/"]
VOLUME /var/log
VOLUME /var/log /var/db
一般的使用场景为需要持久化存储数据时

容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。

所以当数据需要持久化时用这个命令。

USER

设置启动容器的用户,可以是用户名或UID,所以,只有下面的两种写法是正确的

USER daemo
USER UID
注意:如果设置了容器以daemon用户去运行,那么RUN, CMD 和 ENTRYPOINT 都会以这个用户去运行

WORKDIR

语法:

WORKDIR /path/to/workdir
设置工作目录,对RUN,CMD,ENTRYPOINT,COPY,ADD生效。如果不存在则会创建,也可以设置多次。

如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
pwd执行的结果是/a/b/c

WORKDIR也可以解析环境变量

如:

ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
pwd的执行结果是/path/$DIRNAME

ARG

语法:

ARG <name>[=<default value>]
设置变量命令,ARG命令定义了一个变量,在docker build创建镜像的时候,使用 --build-arg <varname>=<value>来指定参数

如果用户在build镜像时指定了一个参数没有定义在Dockerfile种,那么将有一个Warning

提示如下:

[Warning] One or more build-args [foo] were not consumed.


我们可以定义一个或多个参数,如下:

FROM busybox
ARG user1
ARG buildno
...
也可以给参数一个默认值:

FROM busybox
ARG user1=someuser
ARG buildno=1
...
如果我们给了ARG定义的参数默认值,那么当build镜像时没有指定参数值,将会使用这个默认值

ONBUILD

语法:

ONBUILD [INSTRUCTION]
这个命令只对当前镜像的子镜像生效。

比如当前镜像为A,在Dockerfile种添加:

ONBUILD RUN ls -al
这个 ls -al 命令不会在A镜像构建或启动的时候执行

此时有一个镜像B是基于A镜像构建的,那么这个ls -al 命令会在B镜像构建的时候被执行。

STOPSIGNAL

语法:

STOPSIGNAL signal
STOPSIGNAL命令是的作用是当容器推出时给系统发送什么样的指令

HEALTHCHECK

容器健康状况检查命令

语法有两种:

1. HEALTHCHECK [OPTIONS] CMD command
2. HEALTHCHECK NONE
第一个的功能是在容器内部运行一个命令来检查容器的健康状况

第二个的功能是在基础镜像中取消健康检查命令

[OPTIONS]的选项支持以下三中选项:

--interval=DURATION 两次检查默认的时间间隔为30

--timeout=DURATION 健康检查命令运行超时时长,默认30

--retries=N 当连续失败指定次数后,则容器被认为是不健康的,状态为unhealthy,默认次数是3



注意:

HEALTHCHECK命令只能出现一次,如果出现了多次,只有最后一个生效。

CMD后边的命令的返回值决定了本次健康检查是否成功,具体的返回值如下:

0: success - 表示容器是健康的

1: unhealthy - 表示容器已经不能工作了

2: reserved - 保留值

例子:

HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1


健康检查命令是:curl -f http://localhost/ || exit 1

Docker network (容器网络)

Docker compose(容器编排)

Docker Swarm(集群)

CI/CD jenkins (流水线)

ansible (自动化工具,部署)

Docker镜像讲解

镜像是什么

  • 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码,运行时,库、环境变量和配置文件。
  • 所有的应用,直接打包docker镜像,就可以直接跑起来!
  • 如何得到镜像:
    1. 从远程仓库下载
    2. 朋友拷贝给你
    3. 自己制作一个镜像DockerFile

Docker镜像加载原理

UnionsFS( 联合文件系统 Union Filesystem) )

联合文件系统:union文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下,union文件系统是docker镜像的基础。镜像可以通过分层来继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

特性:一次同时加载多个文件系统,但在外面来看,只是看到一个文件系统,联合加载会把各层文件系统叠加,这样最终的文件系统会包含所有底层

的文件和目录

Docker镜像加载原理

docker镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。

bootfs(boot file system)主要包含bootloader和kernel,bootloader主要引导加载kernel,Linux刚启动会加载bootfs文件系统,Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核,当boot加载完成之后整个内核就在内存中了,此时内存的使用权已经由bootfs转交给内核,此时系统也会卸载bootfs。

rootfs(root file system),在bootfs之上。包含的就是典型linux系统中/dev,/proc,/bin/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

虚拟机的Centos都是好几个G,为什么Docker这里才200M?

对于精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同发行版可以公用bootfs。。

虚拟机是分钟级,容器是秒级。

1
2
3
# 查看镜像信息
[root@localhost ~]# docker image inspect redis:latest

.分层理解

Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像顶部!

这一层就是我们通常说的容器层,容器之下的都叫镜像层!

commit镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
docker commit 提交容器成为一个新的副本
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[tag]
# 查看运行的容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
01f17edc0c92 tomcat "catalina.sh run" 3 months ago Up 5 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp tomcat01
# 创建自己的tomcat镜像
[root@localhost ~]# docker commit -a="StephenShawn" -m="add webapps" 01f17edc0c92 tomcat01:0.1
sha256:5da731531f9fea322cbf4cb2a971c5924672001746de2871171537faf4e6abe9
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat01 0.1 5da731531f9f 14 seconds ago 684MB
tomcat 9.0 b8e65a4d736d 6 months ago 680MB
tomcat latest fb5657adc892 6 months ago 680MB


Docker的常用命令

一、帮助命令


1
2
3
docker version # 显示docker的版本
docker info
docker 命令 --help # 万能命令

二、镜像命令


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
# 查看镜像
docker images # 列出所有镜像
docker images -a
docker images -aq # 只显示镜像id
# 搜索镜像
docker search --filter=STARS=3000 #搜索镜像star大于3000
# 下载镜像
docker pull 镜像[:tag] # 如果不写tag 默认是 latest
[root@localhost ~]# docker pull mysql
Using default tag: latest
latest: Pulling from library/mysql
72a69066d2fe: Pull complete # 分层下载,docker image的核心 联合文件系统
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.io/library/mysql:latest #真实地址
# 删除镜像
docker rmi -f 容器id # 删除指定的镜像
docker rmi -f 容器id 容器id 容器id # 删除多个的镜像
docker rmi -f $(docker images -aq) # 删除全部镜像

三、容器命令

新建容器并启动

1
2
3
4
5
6
7
8
9
10
docker run [可选参数] image
# 参数说明
--name="Name" 容器名字 tomcat01 tomcat02 用来区分容器
-d 后台运行方式
-it 使用交互式运行 进入容器查看内容
-p 指定容器的端口 -p 8080:8080
—P 主机端口:容器端口
-p 容器端口
容器端口
-P 随机端口

列出所有的运行的容器

1
2
3
4
5
6
7
8
9
10
11
12
# docker ps 命令
# 列出当前正在运行的容器
-a # 列出当前正在运行的容器+带历史运行过的容器
-n=? # 最近创建过的容器
-q # 只显示容器的编号
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@localhost ~]# docker ps -aq
1a8af1ce6330
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1a8af1ce6330 centos "/bin/bash" 12 minutes ago Exited (127) About a minute ago zealous_bartik

退出容器

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

删除容器

1
2
3
docker rm 容器id       			# 删除指定容器
docker rm -f $(docker ps -aq) # 删除全部容器
docker ps -a -q|xargs docker run # 删除全部容器(linux命令)

启动和停止容器的操作

1
2
3
4
docker start 容器id
docker restart 容器id
docker stop 容器id
docker kill 容器id

四、常用其他命令

后台启动容器
1
2
3
4
5
# docker run -d 镜像名
[root@localhost ~]# docker run -d centos
# 问题docker ps ,发现 centos 停止了
# 常见的坑, docker 容器使用后台运行,就必须要有一个前台进程,docker 发现没有应用,就会自动停止
# nginx 容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了
查看日志
1
2
3
4
5
6
7
8
9
10
11
12
docker logs
# 自己编写一段shell脚本
[root@localhost ~]# docker run -d centos /bin/sh -c "while true; do echo test;sleep 1;done"
# 查看当前在运行的容器
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9916a0298bfd centos "/bin/sh -c 'while t…" 19 seconds ago Up 18 seconds condescending_curie
113e7bdad55e centos "/bin/bash" 12 minutes ago Up 12 minutes serene_pasteur
# 显示日志
-tf
--tail number # 要显示日志的条数
[root@localhost ~]# docker logs -f -t --tail 10 113e7bdad55e
查看容器中进程信息
1
2
3
4
# 命令 docker top 容器id
[root@localhost ~]# docker top 9916a0298bfd
UID PID PPID C STIME
root 180675 180655 0 20:05 root 183113 180675 0 20:44
查看镜像的元数据
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
# 命令 docker inspect 容器id
[root@localhost ~]# docker inspect 9916a0298bfd
[
{
"Id": "9916a0298bfd3fb37d142bdd8bc056a5c943f8aa3c08bc7e1bb75081ee2a3ed0",
"Created": "2022-03-23T00:05:18.49632074Z",
"Path": "/bin/sh",
"Args": [
"-c",
"while true; do echo test;sleep 1;done"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 180675,
"ExitCode": 0,
"Error": "",
"StartedAt": "2022-03-23T00:05:19.263635448Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6",
"ResolvConfPath": "/var/lib/docker/containers/9916a0298bfd3fb37d142bdd8bc056a5c943f8aa3c08bc7e1bb75081ee2a3ed0/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/9916a0298bfd3fb37d142bdd8bc056a5c943f8aa3c08bc7e1bb75081ee2a3ed0/hostname",
"HostsPath": "/var/lib/docker/containers/9916a0298bfd3fb37d142bdd8bc056a5c943f8aa3c08bc7e1bb75081ee2a3ed0/hosts",
"LogPath": "/var/lib/docker/containers/9916a0298bfd3fb37d142bdd8bc056a5c943f8aa3c08bc7e1bb75081ee2a3ed0/9916a0298bfd3fb37d142bdd8bc056a5c943f8aa3c08bc7e1bb75081ee2a3ed0-json.log",
"Name": "/condescending_curie",
"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/2db2e17cdb47f8a05997664e4e31dc8f59b611e2d23388bc52b56c4407d27cc3-init/diff:/var/lib/docker/overlay2/e75ba16da0fef020c7930a9b6190dbd33a83a8324702c144c689c5cd4e323146/diff",
"MergedDir": "/var/lib/docker/overlay2/2db2e17cdb47f8a05997664e4e31dc8f59b611e2d23388bc52b56c4407d27cc3/merged",
"UpperDir": "/var/lib/docker/overlay2/2db2e17cdb47f8a05997664e4e31dc8f59b611e2d23388bc52b56c4407d27cc3/diff",
"WorkDir": "/var/lib/docker/overlay2/2db2e17cdb47f8a05997664e4e31dc8f59b611e2d23388bc52b56c4407d27cc3/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "9916a0298bfd",
"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",
"while true; do echo test;sleep 1;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": "f28f51fd2c85ab7e8ba88827ec901c9ef4b517428747bd1cdf5196810db622c7",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/f28f51fd2c85",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "41b020afb72dc9602f5a030e56d816692170c2f0427377829da822e62976732a",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:03",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "d91d646c67beba9f1d4aa5cfa191bad1f24cf153ae1c6e3a37cf34599502a27f",
"EndpointID": "41b020afb72dc9602f5a030e56d816692170c2f0427377829da822e62976732a",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
}
}
}
]
进入当前正在运行的容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置
# 命令
docker exec -it 容器id bashShell
# 测试
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9916a0298bfd centos "/bin/sh -c 'while t…" About an hour ago Up About an hour condescending_curie
113e7bdad55e centos "/bin/bash" About an hour ago Up About an hour serene_pasteur
[root@localhost ~]# docker exec -it 9916a0298bfd /bin/bash
[root@9916a0298bfd /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 00:05 ? 00:00:01 /bin/sh -c while true; do echo test;sleep 1;done
root 4061 0 0 01:12 pts/0 00:00:00 /bin/bash
root 4088 1 0 01:12 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
root 4089 4061 0 01:12 pts/0 00:00:00 ps -ef

# 方式二
docker attach 容器id
正在执行当前的代码...
# docker exec # 进入容器后开启一个新的终端,可以在里面操作(常用)
# docker attach # 进入容器正在执行的终端,不会启动新的进程
从容器内烤贝文件到主机上
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

docker cp b4bb1f3f7685:/home/test.java /home
#进入docker容器内
[root@b4bb1f3f7685 /]# cd /home
[root@b4bb1f3f7685 home]# ls
# 创建java文件
[root@b4bb1f3f7685 home]# touch test.java
[root@b4bb1f3f7685 home]# ls
test.java
[root@b4bb1f3f7685 home]# exit
exit
docker cp 容器id:容器内部路径 目的的主路径
[root@localhost home]# docker cp b4bb1f3f7685:/home/test.java /home
[root@localhost home]# ls
shawn test.java

五、安装服务器软件

安装Tomcat
1
2
3
4
5
# 官方的使用
docker run -it --rm tomcat:9.0
# 我们之前的启动都是后台,停止了容器之后,容器还是可以查到 docker run -it --rm 一般用来测试,用完就删除
#下载在启动
docker pull tomcat:9.0
安装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
33
34
35
# es 暴露的端口很多
# es 十分的耗内存
# es 的数据一般需要放置到安全目录 挂载
# --net somenetwork 网路配置

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

# 启动了 linux就卡住了 docker stats 查看cpu的状态

# es 是十分耗内存的 1.xG 1核2G

# 查看 docker stats

# 测试一下es是否成功了
[root@localhost ~]# curl localhost:9200
{
"name" : "6620e2b536c4",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "9i4LLjxvTVKf46Hp1qHkqA",
"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"
}
# 赶紧关闭,增加内存的限制,修改配置文件 -e 环境配置修改
docker run -d --name elasticsearch02 -p 9200:9200 -p 9300:9300 -e ES_JAVA_OPTS="-Xms64m -Xmx512m" -e "discovery.type=single-node" elasticsearch:7.6.2
可视化

docker 图形化界面管理工具!提供一个后台供我们操作

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

rockylinux安装教程

[install on CentOS](Install Docker Engine on CentOS | Docker Documentation)

Uninstall old versions


1
2
3
4
5
6
7
8
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

Install using the repository


1
2
3
4
sudo yum install -y yum-utils
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

Install Docker Engine


1
2
sudo yum update
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin

Start Docker


1
sudo systemctl start docker

Uninstall Docker Engine

1
2
3
sudo yum remove docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd

/var/lib/docker 为默认工作目录

阿里云镜像加速


1
2
3
4
5
6
7
8
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://rz9fml8b.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

逻辑与/或

  • 注意AND、OR必须大写,否则会被认为是普通的单词,而不是搜索指令
  • 与普通编程语言不一样的是,OR指令优先于AND指令
  • 简写:AND指令一般以空格代替,不明确写出。另外AND指令还可以用+代替。OR指令可用|代替
逻辑非:-

  • 样例:搜索引擎 历史 -文化 -中国历史 -世界历史
完整匹配 “ “

  • 样例:”world war I” 表示搜索一次世界大战
通配符:*?

  • 与我们通常的习惯一致,“*”代表一连串字符,“?”代表单个字符
site: 在某个网站或域名下搜索

  • 样例:搜索引擎 技巧 site:edu.cn
  • 这表示要在中文教育科研网站(edu.cn)上关于搜索引擎技巧的页面
filetype: 搜索某种类型的文件

  • 样例:天文学 filetype:pdf
  • 简写: 天文学:pdf
  • 这表示只搜索pdf文件
  • tips:样例 天文学三个字位置任意写
in指令: 位置关键词查找

  • intitle: 在网页标题中查找。这通常对讨论比较多的热门话题很有效。例如:intitle:”GeForce 7800”+测试
  • 例如:allintitile:”GeForce 7800” 测试 与 intitle:”GeForce 7800”+测试 的含义一致。但是,allintitile是排他的,不能加上其他非intitle方面的限制条件
  • inurl: 在网页的url地址中查找。例如:inurl:dowload 表示查找url中包含download的网页
  • allinurl: inurl的排他指令
  • inanchor: 在网页的链接锚中查找

  • 例如:link:www.newhua.com 表示所有指向“华军软件园”外部链接。

  • 例如:related:www.newhua.com 表示找和“华军软件园”类似的网页。
cache: 网页快照(略)

  • 查看网站的 Google 缓存版本,会直接显示缓存页面
  • cache:weibo.com 查看微博的谷歌快照
daterange 查找特定时间网页

  • 例如:”Spice Girls“ daterange:2450958-2450968。这里时间日期的格式是按天文学的儒略日
  • 儒略日数(Julian Day Number,JDN)的计算是从格林威治标准时间的中午开始,包含一个整天的时间,起点的时间(0日)回溯至儒略历的公元前4713年1月1日中午12点(在格里历是公元前4714年11月24日),这个日期是三种多年周期的共同起点,且是历史上最接近现代的一个起点。例如,2000年1月1日的UT12:00是儒略日2,451,545。
  • 世界时UT即格林尼治平太阳时间,是指格林尼治所在地的标准时间,也是表示地球自转速率的一种形式。以地球自转为基础的时间计量系统。
  • 格林尼治(Greenwich),是英国伦敦的一个区,位于伦敦东南、泰晤士河南岸
.. 表示数值范围

  • 例如:数码相机 600..900 万像素 3000..4000 元
  • 注意:“900”与“万”之间必须有空格。
@

  • 在用于搜索社交媒体的字词前加上@ trump @twitter 搜索trump的twitter
$

  • 在数字前加上$搜索特定价格 camera $400 搜索400$的camera
#

  • 搜索 # 标签 #throwbackthursday
  • 搜索标签throwbackthursday
info

  • 在网址前加info:,获取网站详情 info:github.com 搜索github网站详情
intext

  • 搜索查询词出现在页面正文(title)中的页面,支持中文和英文 SEO intext:搜索引擎 在正文包含【搜索引擎】的网页中搜索【SEO】
allintext

  • 即all+inanchor 页面正文包含多个关键词的页面 allintext:SEO 搜索引擎优化 相当于:intext:SEO intext:搜索引擎优化
inanchor

  • 搜索链接锚文字(即链接显示的文字)中包含搜索词的页面 inanchor:前端 搜索链接锚文字中包含【前端】的页面
allinanchor

  • 即all+inanchor 页面链接锚文字包含多个关键词的页面	allinanchor:SEO 搜索引擎优化	相当于:inanchor:SEO inanchor:搜索引擎优化
    
weather

  • weather/time/sunrise/sundown+城市名,返回城市的天气/时间/日出时间/日落时间
  • weather:beijing 显示北京的天气
music

  • music或者用songs,歌手名字+music/songs 周杰伦 music 返回周杰伦的各首歌曲

1.全局配置

1
2
git config --global user.name "Your Name"
git config --global user.email "your_email@example.com"

2.全局配置删除

1
2
git config --global --unset user.name
git config --global --unset user.email

3.系统配置删除

系统配置会影响系统上所有用户的所有 Git 仓库,操作时需谨慎。删除系统配置的用户和邮箱信息,使用以下命令:

1
2
git config --system --unset user.name
git config --system --unset user.email

4.查看全局配置

1
git config --global --list

5.查看系统配置

1
git config --system --list

二进制

0b00000001

八进制

0o001(python)

十六进制

0xFE

原码

将数字表述为二进制数,方便人看

反码

1
2
正数与原码相同
负数符号位不变,其余位取反

补码

1
2
3
正数与原码相同
反码符号位不变其余位取反加一
补码的补码是原码

浮点数存储方式

算术运算

比较运算符

逻辑运算

  • &&
  • ||

位运算

  • &
  • |
  • ~
  • ^
  • >>
  • <<
0%