六、容器数据卷
6.1什么是数据卷?
1.docker理念回顾
将应用和环境打包成一个镜像!
数据应该在哪?如果数据都放在容器中,那么我们容器删除,数据就会丢失!
需求:数据可以持久化
【例如】:MySQL,容器删了,删库跑路!
需求:MySQL的数据可以存储在本地!
所以就需要,容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到本地,这就是卷技术!说白了,就是目录的挂载,将我们容器的目录挂载到Linux上面!
总结:为什么用卷?容器的持久化和同步操作!容器间也是可以数据共享的!
方式一:直接使用命令挂载
[root@kikistudy /]# docker run -it -p 主机端口:容器内端口 映射
[root@kikistudy /]# docker run -it -v 主机目录地址:容器内目录
测试
docker run -it -v 主机目录:容器内目录
# 测试
[root@kikistudy home]# docker run -it -v /home/ceshi:/home centos /bin/bash
# 启动起来时候我们可以通过docker inspect 容器id
[root@fb2ce0871f3f /]#
[root@kikistudy /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fb2ce0871f3f centos "/bin/bash" About a minute ago Up About a minute sad_franklin
[root@kikistudy /]# docker inspect fb2ce0871f3f
[
{
"Id": "fb2ce0871f3f913a3f26bc34e9f038f17e73756fa2b2cca9d7721f4d89e4af75",
"Created": "2020-12-31T07:26:32.109756264Z",
"Path": "/bin/bash",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 31692,
"ExitCode": 0,
"Error": "",
"StartedAt": "2020-12-31T07:26:32.949832598Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:300e315adb2f96afe5f0b2780b87f28ae95231fe3bdd1e16b9ba606307728f55",
"ResolvConfPath": "/var/lib/docker/containers/fb2ce0871f3f913a3f26bc34e9f038f17e73756fa2b2cca9d7721f4d89e4af75/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/fb2ce0871f3f913a3f26bc34e9f038f17e73756fa2b2cca9d7721f4d89e4af75/hostname",
"HostsPath": "/var/lib/docker/containers/fb2ce0871f3f913a3f26bc34e9f038f17e73756fa2b2cca9d7721f4d89e4af75/hosts",
"LogPath": "/var/lib/docker/containers/fb2ce0871f3f913a3f26bc34e9f038f17e73756fa2b2cca9d7721f4d89e4af75/fb2ce0871f3f913a3f26bc34e9f038f17e73756fa2b2cca9d7721f4d89e4af75-json.log",
"Name": "/sad_franklin",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": [
"/home/ceshi:/home"
],
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Capabilities": null,
"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/66214b19402922b6df320c755c0408f5eb0e06b4b3af0a9efc3edf2bdcc7a7b0-init/diff:/var/lib/docker/overlay2/a197712d50b7a67a39b70e7ddda9d1dd07a21af6693750747175b501bf7e7466/diff",
"MergedDir": "/var/lib/docker/overlay2/66214b19402922b6df320c755c0408f5eb0e06b4b3af0a9efc3edf2bdcc7a7b0/merged",
"UpperDir": "/var/lib/docker/overlay2/66214b19402922b6df320c755c0408f5eb0e06b4b3af0a9efc3edf2bdcc7a7b0/diff",
"WorkDir": "/var/lib/docker/overlay2/66214b19402922b6df320c755c0408f5eb0e06b4b3af0a9efc3edf2bdcc7a7b0/work"
},
"Name": "overlay2"
},
"Mounts": [
{
"Type": "bind",
"Source": "/home/ceshi",
"Destination": "/home",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
"Config": {
"Hostname": "fb2ce0871f3f",
"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": "20201204",
"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": "c5d709e6728405e250c9897439ec9f4f69ee571d689f706919b8840ad621208c",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/c5d709e67284",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "fafa2f601295119afeeec9f0f3c1092526e46fe7df34f54961a250e4c384aa41",
"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": "b17bb849524a9addbf0eebc6576046d7e26e1f2dd1f900da5a3b88bcc006e277",
"EndpointID": "fafa2f601295119afeeec9f0f3c1092526e46fe7df34f54961a250e4c384aa41",
"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
}
}
}
}
]
在容器下的home目录创建test.java,发现在本机的/home/ceshi/下也有该文件
测试说明,容器内添加了,会帮我们同步到外边
再来测试:
1.先停止这个容器
2.在宿主机修改文件
3.再次启动容器
4.容器中的数据依旧是同步的
好处:我们以后修改只需要在本地修改即可,容器内会自动同步!
6.2实战:安装MySQL
思考:MySQL的数据持久化的问题
[root@kikistudy home]# docker search mysql
# 获取镜像
[root@kikistudy home]# docker pull mysql:5.7
# 运行容器:需要做数据挂载!安装启动时,需要配置密码,这是注意点!
# 官方测试 docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
# 命令解读
# -d 后台运行
# -p 端口映射
# -v 数据卷挂载
# -e 环境配置
# --name 容器名字
[root@kikistudy home]# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
# 启动我们的mysql
[root@kikistudy home]# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
c76b6a616238e4b9a44c263ebb2770777f96ced5fa245d0568cd30be70f92515
[root@kikistudy home]#
# 启动成功之后,我们在本地使用navicat测试连接,正常运行
回顾它是如何连接上去的:
# navicat 账号、密码、主机 连接到服务器的3310,和容器内的3306映射,这个时候我们就可以连接上了
# 在本地测试创建一个数据库,查看一下我们映射的路径是否ok
# 假设我们将容器删除,发现挂载到本地的数据卷依旧没有丢失,这就实现了,数据持久化功能。
[root@kikistudy home]# docker rm -rf mysql01 #删除容器
6.2具名挂载和匿名挂载
6.2.1匿名挂载
# 匿名挂载
-v 容器内路径!
docker run -d -P --name nginx01 -v /etc/nginx nginx # 这里只指定了容器内的名字,并没有指定容器外的名字,而下列的VOLUME NAME 就是匿名挂载
[root@kikistudy data]# docker run -d -P --name nginx02 -v /etc/nginx nginx
d2d6e17945f4b9bf8676927e50ef7d12410140a1a958746d191ad48fc113ad47
# 查看所有的卷的情况
[root@kikistudy data]# docker volume ls
DRIVER VOLUME NAME
local a16d50c40ac3ec32c2768737a222f16bad832b18f080dac7c08f258b65b0d2e6
local ebee35b178c8815d828b96735c1b20ae314f451f6198b347f289f5d96cd7b81d
# 这里发现,这种就是匿名挂载,我们在 -v 只写了容器内的路径,并没有写容器外的路径!
#具名挂载
[root@kikistudy data]# docker run -d -P --name nginx03 -v juming-nginx:/etc/nginx nginx
9a34191d0710d585485ccf7c19f4f69d2c39e4468de1bec0e47b9ed3cc093b20
[root@kikistudy data]# docker volume ls
DRIVER VOLUME NAME
local a16d50c40ac3ec32c2768737a222f16bad832b18f080dac7c08f258b65b0d2e6
local ebee35b178c8815d828b96735c1b20ae314f451f6198b347f289f5d96cd7b81d
local juming-nginx
[root@kikistudy data]#
# 通过 -v 卷名:容器内路径
# 查看一下这个卷
[root@kikistudy data]# docker volume inspect juming-nginx
[
{
"CreatedAt": "2020-12-31T17:04:45+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
"Name": "juming-nginx",
"Options": null,
"Scope": "local"
}
]
[root@kikistudy data]#
所有的docker容器内的卷,没有指定目录的情况下,都是在/var/lib/docker/volumes/卷名/_data
我们通过我们的具名挂载可以方便的找到我们的一个卷,大多数情况在使用的具名挂载
。
# 如何区分是具名挂载还是匿名挂载,还是指定路径挂载
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
拓展:
# 通过 -v 容器内路径:ro rw 改变读写权限
ro readonly #只读
rw readwrite #可读可写
# 一旦设置了容器权限,容器对我们挂载出来的内容就有限定了!
[root@kikistudy volumes]# docker run -d -P --name nginx03 -v juming-nginx:/etc/nginx:ro nginx
[root@kikistudy volumes]# docker run -d -P --name nginx03 -v juming-nginx:/etc/nginx:rw nginx
# ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作!,默认rw
6.2.2初始DockerFile
DockerFile就是用来构建Docker镜像的构建文件!就是一段命令脚本!先体验一下!
方式二: