docker的安装和使用

Docker 基本组成

查看源图像
镜像(image):

相当于一个模板,通过这个模板来创建容器服务,tomcat镜像==>run==>tomcat01容器(提供服务器),通过镜像可以创建多个容器。

服务运行在容器中运行

容器(container):

docker利用容器技术,独立运行一个或一组应用,通过镜像来创建的,

启动,停止,删除,基本命令

可以理解为建议的Linux系统

仓库(repository):

存放镜像的地方

分为公有仓库和私有仓库

需要配置镜像加速

安装docker

环境准备

  1. 会linux系统
  2. CentOS 7
  3. 使用Xshell连接远程服务器(作为学习,我使用的是虚拟机里面安装centOS 7)

环境查看

1
系统内核是3.10以上的

安装

安装时出现错误 如下图:

image-20211204143405152

1
2
3
4
5
解决办法:
1.先用su命令进入root用户下
2.输入visudo 进入配置文件
3.在配置文件中找到“rootALL = (ALL) ALL”行,在下面添加用户“ 用户名 ALL=(ALL) ALL "
4.退出,重新输入命令即可
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
安装命令:
(卸载之前的版本):
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

1.需要的安装包
sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2

2.设置镜像仓库
(国外的仓库,比较慢)
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

(阿里云的镜像仓库,比较快,推荐使用)
sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 更新yum软件包的索引
sudo yum makecache fast

3.安装docker最新版本的

sudo yum install docker-ce docker-ce-cli containerd.io
启动docker
1
2
3
4.运行 sudo systemctl start docker  

5.输入 docker version 判断docker 是不是启动成功
image-20211204145808906
1
6.运行一个 hello-worl程序
image-20211204145948215
1
2
3
4
5
6
7
8
7.查看下载的 hello-world 镜像
输入的命令:
[root@docker01 docker01]# docker images

显示的结果:
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 2 months ago 13.3kB

docker的卸载
1
2
3
4
删除安装包:
yum remove docker-ce docker-ce-cli containerd.io
删除镜像,容器,配置文件等内容:
rm -rf /var/lib/docker
阿里云镜像加速

1.登录阿里云找到容器服务,找到镜像加速地址

image-20211204154604509

2.配置使用

1
2
3
4
5
6
7
8
9
10
11
1.sudo mkdir -p /etc/docker

2.sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://4tbypv0e.mirror.aliyuncs.com"]
}
EOF

3.sudo systemctl daemon-reload

4.sudo systemctl restart docker
底层原理

Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上。通过Socker从客户端访问。

DockerServer接收到Docker-Client的指令,就会执行这个命令。

image-20211204160702631

docker的常用命令

帮助命令


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

docker命令帮助文档的地址:https://docs.docker.com/reference/

镜像命令


docker images 查看所有本地主机上的镜像
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@docker01 docker01]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 2 months ago 13.3kB

# 解释
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的ID
CREATED 镜像的创建时间
SIZE 镜像的大小

# 可选项
-a, --all 列出所有镜像
-q, --quiet 只显示镜像的ID

docker search 搜索镜像命令
1
2
3
NAME                              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
mysql MySQL is a widely used, open-source relation… 11777 [OK]
mariadb MariaDB Server is a high performing open sou… 4487 [OK]
docker pull 下载镜像
1
2
docker pull mysql  [:tag] 下载mysql镜像,如果不写tag,会默认下载最新版本
docker pull mysql:5.7 下载mysql5.7版本的镜像
docker rmi 删除镜像
1
2
3
docker rmi -f 镜像id					#删除指定镜像
docker rmi -f 镜像id 镜像id 镜像id #删除多个镜像
docker rmi -f $(docker images -aq) #删除全部镜像

容器命令


说明:有了镜像才能创建容器,下载一个Linux,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
25
docker run [可选参数] image

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



# 测试,启动并进入容器
[root@docker01 docker01]# docker run -it centos /bin/bash
[root@870a4fc7d3c0 /]# ls #查看容器内的centos,基础版本
bin etc lib lost+found mnt proc run srv tmp var
dev home lib64 media opt root sbin sys usr


# 从容器中退出
[root@870a4fc7d3c0 /]# quit

列出所有运行过的容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# docker ps 命令
#列出正在运行的容器o
-a # 列出运行过的容器
-n=? #显示最近创建的容器
-q # 只显示容器的编号

#命令可以混合使用 docker ps -aq 显示所有运行过的容器的编号

[root@docker01 docker01]# docker ps # 列出正在运行的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

[root@docker01 docker01]# docker ps -a # 列出运行过的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
870a4fc7d3c0 centos "/bin/bash" 3 minutes ago Exited (130) About a minute ago optimistic_kalam
e767aeb92078 hello-world "/hello" 7 minutes ago Exited (0) 7 minutes ago keen_yonath
eaa74af3c185 hello-world "/hello" 2 hours ago Exited (0) 2 hours ago cranky_goldwasser

退出容器
1
2
exit   #直接停止容器退出
Ctrl + q + p #容器不停止但退出
删除容器
1
2
3
docker rm 容器id				   #删除指定的容器,不能删除正在运行的容器,强制删除 rm -f
docker rm -f $(docker ps -aq) #删除全部的容器
docker ps -a -q|xargs docker rm #删除全部的容器
启动和停止容器的操作
1
2
3
4
docker start 容器id		#启动容器
docker restart 容器id #重新启动容器
docker stop 容器id #停止当前正在运行的容器
docker kill 容器id #强制停止容器

常用其他命令


后台启动容器
1
2
3
4
5
6
# docker run -d 镜像名

#问题docker ps ,发现 镜像停止了

#常见的坑:docker 容器在后端运行,就必须要有一个前台的进程,就会自动停止
#nginx,容器启动后,发现自己没有提供服务,就会立即停止,就是没有程序了
查看日志
1
2
3
4
5
6
7
8
# docker logs -t -f --tail=n -a(n代表查询日志的数量)
# docker logs -t -f --tail=n 容器id

#显示日志
-a # 查询所有容器的日志
- tf # 显示所有日志
-- tail num # 要显示日志的条数

查看容器中的进程信息
1
docker top 容器id
查看镜像的源数据
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
# 命令
docker inspect 容器id

# 测试
[root@docker01 docker01]# docker inspect 42f22ae12579
[
{
"Id": "42f22ae12579008a7c3d161273cce8bf4ad4746d9acd2e40923f2745d463a626",
"Created": "2021-12-04T09:54:04.229855998Z",
"Path": "/bin/bash",
"Args": [],
"State": {
"Status": "exited",
"Running": false,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 0,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-12-04T09:54:04.56940188Z",
"FinishedAt": "2021-12-04T09:55:31.08471425Z"
},
"Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6",
"ResolvConfPath": "/var/lib/docker/containers/42f22ae12579008a7c3d161273cce8bf4ad4746d9acd2e40923f2745d463a626/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/42f22ae12579008a7c3d161273cce8bf4ad4746d9acd2e40923f2745d463a626/hostname",
"HostsPath": "/var/lib/docker/containers/42f22ae12579008a7c3d161273cce8bf4ad4746d9acd2e40923f2745d463a626/hosts",
"LogPath": "/var/lib/docker/containers/42f22ae12579008a7c3d161273cce8bf4ad4746d9acd2e40923f2745d463a626/42f22ae12579008a7c3d161273cce8bf4ad4746d9acd2e40923f2745d463a626-json.log",
"Name": "/hungry_noether",
"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/31be9ff3ac2da6207f80d25f317db896cfc693020a84eb098efb024c8e0df2e4-init/diff:/var/lib/docker/overlay2/c34b4aa3040fde719ffc648c55ec1bb8f4ba831f980fcbb9b37a30051b4d5910/diff",
"MergedDir": "/var/lib/docker/overlay2/31be9ff3ac2da6207f80d25f317db896cfc693020a84eb098efb024c8e0df2e4/merged",
"UpperDir": "/var/lib/docker/overlay2/31be9ff3ac2da6207f80d25f317db896cfc693020a84eb098efb024c8e0df2e4/diff",
"WorkDir": "/var/lib/docker/overlay2/31be9ff3ac2da6207f80d25f317db896cfc693020a84eb098efb024c8e0df2e4/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "42f22ae12579",
"Domainname": "",
"User": "",
"AttachStdin": true,
"AttachStdout": true,
"AttachStderr": true,
"Tty": true,
"OpenStdin": true,
"StdinOnce": true,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash"
],
"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": "e4fd3d35da7d401a907c0fb46b987679106b02613ed4bcc3b83fbc2ddbccff72",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/e4fd3d35da7d",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "",
"Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"MacAddress": "",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "a52d4e4bff610bdcbca9763774038725794ae4910aeac74f5fe3b7587d2509f3",
"EndpointID": "",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"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
# 容器通常都是使用后台运行的,需要进入容器,修改一些配置

# 命令
docker exec -it 容器id bashShell

# 测试
[root@docker01 docker01]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1c1e914eb3cb centos "/bin/bash" 12 seconds ago Up 11 seconds romantic_bartik
[root@docker01 docker01]# docker exec -it 1c1e914eb3cb /bin/bash
[root@1c1e914eb3cb /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 10:00 pts/0 00:00:00 /bin/bash
root 15 0 0 10:01 pts/1 00:00:00 /bin/bash
root 29 15 0 10:02 pts/1 00:00:00 ps -ef

# 方式二
docker attach 容器id

# 测试
[root@docker01 docker01]# docker attach 1c1e914eb3cb
正在执行当前的代码....

# docker exec #进入一个新的终端,可以在里面操作(常用)
# docker attach # 进入容器中正在执行的终端,不会启动新的进程
从容器内拷贝文件到主机
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 cp 容器id:容器内路径   目的主机路径

# 查看当前主机目录
[root@docker01 home]# ls
docker01 likunsong.java
[root@docker01 home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
620084e2d74d centos "/bin/bash" 3 minutes ago Up 3 minutes elated_antonelli

# 进入docker 内部
[root@docker01 home]# docker attach 20084e2d74d
Error: No such container: 20084e2d74d
[root@docker01 home]# docker attach 620084e2d74d
[root@620084e2d74d /]# cd /home
[root@620084e2d74d home]# ls
# 在容器内新建一个文件
[root@620084e2d74d home]# touch text.java
[root@620084e2d74d home]# exit
exit
[root@docker01 home]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@docker01 home]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
620084e2d74d centos "/bin/bash" 5 minutes ago Exited (0) 22 seconds ago elated_antonelli

# 将容器内的文件拷贝到主机上
[root@docker01 home]# docker cp 620084e2d74d:/home/text.java /home
[root@docker01 home]# ls
docker01 likunsong.java text.java

练习

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 1. 搜索镜像, search 
# 2. 下载镜像 pull
# 3. 运行测试

# -d 后台运行
# -- name 给容器命名
# -p 宿主机端口,容器内部端口
[root@iZ0jl26t6u4l56lb52dskvZ ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest f652ca386ed1 2 days ago 141MB

[root@iZ0jl26t6u4l56lb52dskvZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
52cc76a3f6e5 nginx "/docker-entrypoint.…" 14 seconds ago Up 14 seconds 0.0.0.0:3344->80/tcp nginx01

[root@iZ0jl26t6u4l56lb52dskvZ ~]# curl localhost:3344
<!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>

# 进入容器

[root@iZ0jl26t6u4l56lb52dskvZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
52cc76a3f6e5 nginx "/docker-entrypoint.…" 12 minutes ago Up 12 minutes 0.0.0.0:3344->80/tcp nginx01
[root@iZ0jl26t6u4l56lb52dskvZ ~]# docker exec -it nginx01 /bin/bash
root@52cc76a3f6e5:/# whereis nginx
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx

docker 安装 tomcat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 官方的使用
docker run -it --rm tomcat:9.0
(一般用于测试,用完自动删除)

# 下载再启动
docker pull tomcat

# 启动
docker run -d -p 3355:8080 --name tomcat01 tomcat

# 测试访问,没有问题

#进入容器
docker exec -it tocat01 /bin/bash

部署 es + kibana

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# es 暴露的端口很多
# es 十分耗内存
# es 的数据一般需要放置在安全目录 挂载

# --net somenetword 网络配置


# 启动 elasticsearch
$ docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:tag

# 启动之后 Linux服务器就会卡 docker stats 查看cpu的状态

# es 是十分耗内存的

$ docker run -d --name elasticsearch --net somenetwork -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m _Xmx512m" elasticsearch:tag

# -e ES_JAVA_OPTS="-Xms64m _Xmx512m" 设置配置文件,为了不让服务器被占用内存太大
image-20211209210523336

可视化


  • portainer(不是最佳选择)

  • Rancher(CI/CD再用)

    Docker是图形化界面管理工具

1
2
3
docker run -d -p 8088:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

访问测试:自己外网端口:8088/

通过它来访问(访问界面):(账号: admin 密码:12345678)

image-20211209211702279

注册完密码后,选择本地的

image-20211210154759637

进去之后会展示这样的一个面板

image-20211210154836546

点开后

image-20211210155406811

可视化一般不会用

Docker镜像


镜像是什么


所有的应用,直接打包docker镜像,就可以直接跑起来

如何得到镜像:

  • 从远程仓库下载
  • 朋友 拷贝
  • 自己制作一个镜像 DockerFile

镜像加载原理

UnionFS (联合文件系统)

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

特性:一次同时加载多个文件系统,但从外面只能看见一个文件,联合加载会把各个文件系统叠加起来,这样最终文件系统会包含所有底层的文件和目录

docker 镜像加载原理

Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS(联合文件系统)。

分为两个部分:

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

    即:系统启动时需要的引导加载,这个过程会需要一定时间。就是黑屏到开机之间的这么一个过程。电脑、虚拟机、Docker容器启动都需要的过程。在说回镜像,所以这一部分,无论是什么镜像都是公用的。

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

    即:镜像启动之后的一个小的底层系统,这就是我们之前所说的,容器就是一个小的虚拟机环境,比如Ubuntu,Centos等,这个小的虚拟机环境就相当于rootfs。

img

对于一个精简的OS系统,rootfs可以很小,只需要包含最基本的命令、工具和程序库就可以了,因为底层直接用Host(宿主机)的kernel(也就是宿主机或者服务器的boosfs+内核),自己只需要提供rootfs就可以了。

由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs部分

这就是我们之前说:虚拟机的启动是分钟级的,容器的启动是秒级的**

分层理解

分层的镜像

image-20211210161710037

是一层一层的安装的

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
[root@nanxing ~]# docker image inspect redis:latest
[
{
"Id": "sha256:aea9b698d7d1d2fb22fe74868e27e767334b2cc629a8c6f9db8cc1747ba299fd",
"RepoTags": [
"redis:latest"
],
"RepoDigests": [
"redis@sha256:2f502d27c3e9b54295f1c591b3970340d02f8a5824402c8179dcd20d4076b796"
],
···# 中间省略
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:9321ff862abbe8e1532076e5fdc932371eff562334ac86984a836d77dfb717f5",
"sha256:aa2858ea5edc9c0981901a1b63b49a8f4a6e7099b4304b49e680ffdcc6b71b3e",
"sha256:93079bf13a6d5fe7c4bd9f00cb96183f9d1db9968c4bd15b395df2f3867bf8e5",
"sha256:9ca504b88e256aa6f6c04ec65aeeed6b926661ea30a0b97f829fbe230155241a",
"sha256:9468a3f0498bd5cc298ce25ea6ce9c6adf14aa2ce152856b5f389510a9bb9e01",
"sha256:b7851a62867d82784052d7662862adc0b47b2bddcddc89ae78307f75ba1b29ae"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]

理解

所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
  举一个简单的例子,假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。
  该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。

img

在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而整体的镜像包含了来自两个镜像层的6个文件。

img

上图中的鏡像层跟之前图中的略有区别,主要目的是便于展示文件。

下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。

img

这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。
  Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。

如上边的三层镜像,Docker最终会把所有镜像层堆叠并合并,对外提供统一的视图,如下图
img

特点

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

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

commit镜像

1
2
3
4
docker commit 提交容器成为一个新副本

# 命令和git相似
docker commit -m="提交描述信息" -a="作者" 容器id 目标镜像名:[TAG]

测试

1
2
3
4
5
# 启动一个tomcat
docker run -it -p 8080:8080 tomcat
# 发现默认的tomcat 没有webapps应用 镜像的原因 官方镜像下默认tomcat是没有文件的

# 自己拷贝进去基本的文件

image-20211210165543754

1
# 将我们修改后的容器通过commit 提交作为一个镜像。我们以后可以使用我们修改过的镜像,这是我们自己修改的镜像

image-20211210170143024

容器数据卷


什么是容器数据卷

docker理念回顾

Docker容器数据卷,即Docker Volume(卷)。

当Docker容器运行的时候,会产生一系列的数据文件,这些数据文件会在关闭Docker容器时,直接消失的。但是其中产生部分的数据内容,我们是希望能够把它给保存起来,另作它用的。关闭Docker容器=删除内部除了image底层数据的其他全部内容,即删库跑路

  1. 将应用与运行的环境打包形成容器运行,伴随着容器运行产生的数据,我们希望这些数据能够持久化。
  2. 希望容器之间也能够实现数据的共享

Docker容器产生的数据同步到本地,这样关闭容器的时候,数据是在本地的,不会影响数据的安全性。
docker的容器卷技术也就是将容器内部目录和本地目录进行一个同步,即挂载。

总结: 容器的持久化和同步化操作,容器之间也是可以数据共享的(但是注意挂载不是等同于同步!!!)

使用数据卷

直接使用命令进行挂载 -v

1
2
3
4
docker run -it -v 主机目录:容器内目录

[root@nanxing home]# docker run -it -v /home/ceshi:/home centos /bin/bash

image-20211210172813793

image-20211210172834931

1
# 启动起来后可以通过docker inspect 容器id 查看是否挂载成功

image-20211210173211453

测试文件的同步

image-20211210173708604

再来测试

  1. 停止容器
  2. 宿主机上修改文件
  3. 启动容器
  4. 容器内的数据依旧是同步的

image-20211210174437507

优点:只用在本地修改,容器上就会自动同步

安装MySQL

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
# 获取镜像
[root@nanxing ceshi]# docker pull mysql:5.7

# 运行容器, 做数据挂载 # 安装启动mysql需要设置密码

# 官方测试 docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

# 启动mysql
-d 后台运行
-p 端口映射
-v 卷挂载 通过两个-v 挂载两个目录
-e 环境配置
--name 容器的名字
# 该命令行无法正常启动mysql

[root@nanxing ~]# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e SQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
(问题:该段代码运行后发现没有docker容器运行,通过查阅书籍,发现应该挂载一个地址即可正确运行mysql)

# 正确运行的命令

docker run --name mysql03 -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /my/custom:/etc/mysql/conf.d -d mysql:5.7

# 测试
通过Navicat软件进行连接测试,

具名和匿名挂载


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 匿名挂载
-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx

# 查看所有volume的情况
docker volume ls

[root@nanxing ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
666e563c18473783613a5c11459ac7cd869742eb74b5b77b4218fdbf3b8487e4
[root@nanxing ~]# docker volume ls
DRIVER VOLUME NAME
local juming-nginx

# 通过 -v 卷名:容器内路径
# 查看一下卷

image-20211211001040946

所有的docker容器内的卷,没有指定目录的情况下都是在 /var/lib/docker/volumes/xxx

我们通过具名挂载找到我们的卷,大多数情况下使用具名挂载

1
2
3
4
# 如何确定是具名挂载还是匿名挂载,还是指定路径挂载
-v 容器内路径 # 匿名挂载
-v 卷名:容器内路径 # 具名挂载
-v /宿主机路径:容器内路径 # 指定路径挂载

拓展:

1
2
3
4
5
6
7
8
# 通过 -v 容器内路径 ,ro rw 改变权限
ro readonly # 只读
rw readwrite # 可读可写

# 一旦设定了容器的权限,容器对我们挂载出来的文件就有限定了
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
# ro 只要看到了ro就说明只能通过宿主机进行操作,容器内是无法操作的

初识DockerFIle


DockerFile 就是用来构建docker 镜像的构建文件,是一个命令脚本

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

1
2
3
4
5
6
7
8
9
# 创建一个dockerfile文件,名字随机,建议dockerfile
# 文件中的内容 指令(大写) 参数

FROM centos # 添加基础镜像
VOLUME ["volume01", "volume02"] # 添加两个容器数据卷,属于匿名挂载
CMD echo "--finished----success--" # 容器构建完成输出的信息
CMD /bin/bash # 指定终端命令

# 这里的每个命令就是单个的一层

image-20211211111056018

1
# 启动我们自己写的容器

image-20211211111603629

这个卷和外部一定有一个同步的目录

查看一下挂载的路径

image-20211211112221253

测试一下是否同步了

这种方式我们未来使用的十分多,我们通常会构建自己的镜像

假设构建镜像的时候没有挂载卷,手动镜像挂载 -v 卷名:容器内路径

数据卷容器


两个mysql 同步数据

image-20211211113148244

1
# 启动三个容器,通过自己写的镜像启动
image-20211211113544539 image-20211211151428336
1
# 测试,删除docker01(父容器) docker02 和docker03 文件依旧存在,且可以访问

用于实现多个mysql 实现数据共享

DockerFile


dockerfile 是用来构建docker镜像的文件,命令参数脚本

构建步骤:

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

官方的镜像都是基础包,很多功能都没有,我们通常要自己搭建自己的镜像!

DockerFile的构建过程


基础知识

  1. 每个保留关键字(指令) 都必须是大写字母
  2. 指令是从上到下顺序执行的
  3. #表示注释
  4. 每个指令都会提交一个镜像层

img

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

步骤:开发,部署,运维

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

DockerImags:通过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 # 狗酱的时候设置环境变量 用户名,密码

查看源图像

实战测试

Docker Hub 中大部分都是从一个基础镜像出来的FROM scratch,然后配置需要的软件和配置进行构建

创建一个自己的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
25
26
#  1.编写一个dockerfile 文件
[root@nanxing dockerfile]# cat mydockerfile-centos
FROM centos
MAINTAINER likunsong<1537628435@qq.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

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

# 2.通过这个文件构建镜像
# 命令 docker build -f dockerfile文件 -t 镜像名:[tag]

Successfully built 298fb113f5dd
Successfully tagged mycentos:0.1

# 3.测试运行
docker run -it centos
docker run -it mycentos:0.1

对比:我们之前原生的centos

image-20211211162441961

我们增加后的镜像

image-20211211162522230

我们可以列出我们的给本地镜像的一个变更历史

image-20211211162751360

可以研究镜像是怎么做的

CMD 和 ENTRYPOINT 的区别

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

测试cmd

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
# 编写dockerfile文件
[root@nanxing dockerfile]# vim dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]

# 构建镜像
[root@nanxing dockerfile]# docker build -f dockerfile-cmd-test -t mdtest .


# run运行 发现ls-a实现成功
Successfully built fb8dd831cb5d
Successfully tagged mdtest:latest
[root@nanxing dockerfile]# docker run fb8dd831cb5d
.
..
.dockerenv
bin
dev
etc
home
lib
lib64

# 想追加一个命令 -l ls-al
[root@nanxing dockerfile]# docker run fb8dd831cb5d -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
ERRO[0000] error waiting for container: context canceled

# cmd的清理下 -l 替换了CMD["ls","-a"]命令,-l不是命令,所以报错

测试ENTRYPOINT

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
[root@nanxing dockerfile]# vim dockerfile-cmd-entrypoint
FROM centos
ENTRYPOINT ["ls","-a"]

[root@nanxing dockerfile]# docker build -f dockerfile-cmd-entrypoint -t entrypoint-test .
Sending build context to Docker daemon 4.096kB
Step 1/2 : FROM centos
---> 5d0da3dc9764
Step 2/2 : ENTRYPOINT ["ls","-a"]
---> Running in e97b12187fc8
Removing intermediate container e97b12187fc8
---> 9d0e6bdfc7d7
Successfully built 9d0e6bdfc7d7
Successfully tagged entrypoint-test:latest
[root@nanxing dockerfile]# docker run 9d0e6bdfc7d7
.
..
.dockerenv
bin
dev
etc
home
lib
lib64

# 我们的追加命令是直接拼接到我们的 ENTRYPOINT 命令后面
[root@nanxing dockerfile]# docker run 9d0e6bdfc7d7 -l
total 56
drwxr-xr-x 1 root root 4096 Dec 12 01:54 .
drwxr-xr-x 1 root root 4096 Dec 12 01:54 ..
-rwxr-xr-x 1 root root 0 Dec 12 01:54 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 5 root root 340 Dec 12 01:54 dev
drwxr-xr-x 1 root root 4096 Dec 12 01:54 etc
drwxr-xr-x 2 root root 4096 Nov 3 2020 home
lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------ 2 root root 4096 Sep 15 14:17 lost+found
drwxr-xr-x 2 root root 4096 Nov 3 2020 media
drwxr-xr-x 2 root root 4096 Nov 3 2020 mnt
drwxr-xr-x 2 root root 4096 Nov 3 2020 opt
dr-xr-xr-x 187 root root 0 Dec 12 01:54 proc
dr-xr-x--- 2 root root 4096 Sep 15 14:17 root
drwxr-xr-x 11 root root 4096 Sep 15 14:17 run
lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Nov 3 2020 srv
dr-xr-xr-x 13 root root 0 Dec 12 01:54 sys
drwxrwxrwt 7 root root 4096 Sep 15 14:17 tmp
drwxr-xr-x 12 root root 4096 Sep 15 14:17 usr

实战:制作tomcat镜像


  1. 准备一个镜像文件 tomcat 的压缩包,jdk的压缩包 (下面是jdk和tomcat的压缩包)

    image-20211212122840181

    1
    链接:https://pan.baidu.com/s/1KvWWj1xS5DVL-uGcQYQEsA            提取码:abcd
  2. 编写dockerfile,官方命名 Dockerfile,build的时候会自动寻找这个文件,不需要 - f 指定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
COPY readme.txt /usr/local/readme.txt

ADD jdk-8u11-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.22.tar.gz /usr/local/

RUN yum -y install -vim

ENV MYPATH /usr/local
WORKDIR $MYPATH

ENV JAVA_HOME /usr/local/jdk1.8.0_11
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.22
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.22
ENV PATH $PATH:$JAVA_HOME/bin/:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080

CMD /usr/local/apache-tomcat-9.0.22/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.22/bin/logs/catalina.out

  1. 构建镜像
1
# docker build -t diytomcat .
  1. 启动镜像
  2. 访问测试
  3. 发布项目(由于做了卷挂载,我们在本地编写项目就可以发布)
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
</web-app>
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
<!DOCTYPE html>
<html>
<head>
<title>九九乘法口诀表</title>
</head>
<meta charset="utf-8">
<body bgcolor="white">
<h1 align="center" >
<font color="purple red" face="华文楷体" size="10">乘法口诀表</font>
</h1>
<p>
<table border="1" width="700" height="100" bgcolor="white" align="center">
<tr bgcolor="red purple">
<td>1*1=1</td>
</tr>
<tr bgcolor="purple">
<td>1*2=2</td>
<td>2*2=4</td>
</tr>
<tr bgcolor="purple green">
<td>1*3=3</td>
<td>2*3=6</td>
<td>3*3=9</td>
</tr>
<tr bgcolor="white purple">
<td>1*4=4</td>
<td>2*4=8</td>
<td>3*4=12</td>
<td>4*4=16</td>
</tr>
<tr bgcolor="purple green">
<td>1*5=5</td>
<td>2*5=10</td>
<td>3*5=15</td>
<td>4*5=20</td>
<td>5*5=25</td>
</tr>
<tr bgcolor="green purple">
<td>1*6=6</td>
<td>2*6=12</td>
<td>3*6=18</td>
<td>4*6=24</td>
<td>5*6=30</td>
<td>6*6=36</td>
</tr>
<tr bgcolor="black blue">
<td>1*7=7</td>
<td>2*7=14</td>
<td>3*7=21</td>
<td>4*7=28</td>
<td>5*7=35</td>
<td>6*7=42</td>
<td>7*7=49</td>
</tr>
<tr bgcolor="blue black">
<td>1*8=8</td>
<td>2*8=16</td>
<td>3*8=24</td>
<td>4*8=32</td>
<td>5*8=40</td>
<td>6*8=48</td>
<td>7*8=56</td>
<td>8*8=64</td>
</tr>
<tr bgcolor="white blue">
<td>1*9=9</td>
<td>2*9=18</td>
<td>3*9=27</td>
<td>4*9=36</td>
<td>5*9=45</td>
<td>6*9=54</td>
<td>7*9=63</td>
<td>8*9=72</td>
<td>9*9=81</td>
</tr>
</table>
</p>
</body>
</html>

项目部署完成,直接访问就ok

需要掌握Dockerfile的编写,之后都是使用docker镜像来进行发布运行

发布自己的镜像


DockerHub

  1. 注册自己的账号
  2. 登录账号
  3. 在我们服务器上提交镜像
1
2
3
4
5
6
7
8
9
10
11
12
[root@nanxing tomcat]# docker login --help

Usage: docker login [OPTIONS] [SERVER]

Log in to a Docker registry.
If no server is specified, the default is defined by the daemon.

Options:
-p, --password string Password
--password-stdin Take the password from stdin
-u, --username string Username

  1. 登录完之后就可以提交镜像了
1
2
3
4
5
6
7
8
9
10
11
12
1.在dockerhub上创建一个自己仓库
2.给本地镜像加标签
# docker tag 本地镜像名字 [hub-name]/[repository-name]:[Tag]
# [hub-name]为注册时使用的账号
# [repository-name]为建立的仓库名
# [Tag]为版本号
docker tag diytomcat lilunsong/ditomcat:1.0
3.上传镜像
# docker push [hub-name]/[repository-name]:[Tag]
# 其中[hub-name]/[repository-name]:[Tag]为上文Tag完成的镜像

docker push likunsong/ditomcat:1.0

image-20211212142933024

Docker网络

pdf版本

百度网盘

链接:https://pan.baidu.com/s/1B25GH8L8WGhRKS49J0Jagw
提取码:abcd