|NO.Z.00016|——————————|CloudVirtualiZation|——|Cloud&Docker存储.V01|——|数据存储|
一、数据卷特性

### --- 数据卷特性
~~~ #Docker镜像由多个只读层叠加而成,启动容器时,docker会加载只读镜像层并在
~~~ #镜像栈顶部添加一个读写层。
~~~ 如果运行中的容器修改了现有的一个已经存在的文件,
~~~ 那么改文件将会从读写层下面的读写层复制到读写层,该文件的只读版本依然存在,
~~~ 只是已经被读写层中改文件的副本所隐藏,次既“写时复制”机制。
### --- 数据卷的意义:
~~~ 关闭并重启容器,器数据不受影响;但删除docker容器,则其改变将会全部丢失
~~~ # 存在的问题
~~~ 存在于联合文件系统中,不易于宿主机访问
~~~ 容器间数据共享不变
~~~ 删除容器其数据会丢失
~~~ # 解决方案:“卷”
~~~ “卷”是容器上的一个或多个“目录”,此类目录可绕过联合文件系统,与宿主机上的某目录“绑定”



~~~ # volume可以在运行容器时即完成创建于绑定操作,当然,前提需要拥有对应的声明
~~~ volume的初衷就是数据持久化
~~~ Bind mount volume
~~~ Docker-managed volume
二、容器中的数据卷Volume(yuanjian)
### --- 容器中的数据卷Volume(yuanjian)
docker-managed Volume //1、容器自管理卷
docker run -it --name roc -v MOUNTDIR roc/lamp:v1.0
docker inspect -f {{.Mounts}} roc
Bind-mount Volume //2、绑定卷,个人操作的
Docker run -it --name roc -v HOSTDIR:VOLUMEDIR roc/lamp:v1.0 //HOSTDIR:VOLUMEDIR说明需要告诉宿主机的工作目录和容器的内部目录
Union Volume //3、联合卷,既不想借助宿主机的工作目录,又想实现容器之间的目录共享解决方案:
docker run -it --name roc --volumes-from ContainerName roc/lamp:v1.0
### --- docker-managed Volume:容器自管理卷
[root@hub ~]# docker run --name wordpress -d wordpress
7b7364016246ec2e908253dbed31fe51ecae1d6ff5b0f2419eff5143e2e45f55
[root@hub ~]# docker run --name tomcat -d tomcat:v1.0
[root@hub ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7b7364016246 wordpress "docker-entrypoint..." About a minute ago Up About a minute 80/tcp wordpress
ac2cd6511c27 tomcat:v1.0 "/bin/sh -c '/root..." 3 hours ago Up 8 seconds tomcat
[root@hub ~]# docker inspect tomcat
"Mounts": [], // 当前是空的,意味着当前并没有用任何的数据在使用,也就是说没有数据卷的挂载
[root@hub ~]# docker inspect wordpress
"Image": "wordpress",
"Volumes": {
"/var/www/html": {} // Apache的站点,新版的会有挂载信息
},
"WorkingDir": "/var/www/html",
[root@hub ~]# cd /var/lib/docker/volumes/
[root@hub volumes]# ls
03e24157109b612c13b89c8572aa6b40dffbefa26d0aa80d1c06cf55a54ca449 88bcc0dd06d82b38c178252f25b452140f9e73a99fcc76030caa13ba06f66804
1855483754eb9c1b2722c5b47dfecb4a48828193aca00e46af8f479063012643 a07a07b5fed27f78505618f3c2bfb709fad0809e27fe6e7c34663281bff81678
[root@hub volumes]# docker rm -f $( docker ps -a -q ) // 删除所有容器,发现我们的管理卷还在,
// 也就说明当我们删除容器的时候这些管理卷并不会删除
[root@hub volumes]# rm -rf * // 删除所有的管理卷
### --- 重新启动tomcat和WordPress容器
~~~ 启动了两个容器只产生了一个管理卷目录;
~~~ 原因是我们在dockerfile中声明需要自管理卷的只有WordPress,
~~~ 而tomcat没有声明自管理卷。所以它不会创建
[root@hub ~]# docker run --name wordpress -d wordpress
7c94019d4dcfbc09bc9051a72176ba446bfdc098c5ab4b4c1b7b3caf47f36a06
[root@hub ~]# docker run --name tomcat -d tomcat:v1.0
8788994bc479fe7355fddc6a23c60c2e5678fb0886d42e23aefb96096eccae2c
[root@hub ~]# cd /var/lib/docker/volumes/a1b7aff5c6fb9f0fac3ec0a277906b061d22103e0875cb46ff6726a02466b63a/_data/
[root@hub _data]# ls // 里面的文件内容为WordPress的网页文件
index.php readme.html wp-admin wp-comments-post.php wp-content wp-includes wp-load.php wp-mail.php wp-signup.php xmlrpc.php
license.txt wp-activate.php wp-blog-header.php wp-config-sample.php wp-cron.php wp-links-opml.php wp-login.php wp-settings.php wp-trackback.php
[root@hub _data]# touch yanqi // 标识一下
[root@hub _data]# docker exec -it wordpress /bin/bash
root@7c94019d4dcf:/var/www/html#
root@7c94019d4dcf:/var/www/html# ls
yanqi // 进入容器之后发现我们在宿主机上创建的文件也会存在
// 说明:如果我们在启动镜像的时候需要使用自管理目录的时候,就会以为这在启动容器或者镜像的时候它会把目标目录与/var/lib/docker/volumes/a1b7aff5c6fb9f0fac3ec0a277906b061d22103e0875cb46ff6726a02466b63a/创建的这个随机目录与之挂载
root@7c94019d4dcf:/var/www/html# touch {1..100}.txt // 创建100个.txt文件
[root@hub _data]# docker rm -f wordpress // 删除WordPress容器后发现100个txt文件还是存在
wordpress
[root@hub _data]# ls
### --- 自己在编辑镜像的时候,怎么样达到自管理卷的效果,
~~~ 保存数据文件在宿主机的目录的效果呢?
~~~ 使用centos6.8创建两个不同的容器
~~~ test1容器使用VOLUME创建挂载点,不生成自管理卷文件
[root@hub ~]# vim Dockfile
FROM centos:6.8
RUN touch /tmp/1.txt
RUN mkdir /data
CMD tail -f /tmp/1.txt
[root@hub ~]# docker build -t test:v1.0 .
Sending build context to Docker daemon 614.6 MB
Step 1/4 : FROM centos:6.8
---> 82f3b5f3c58f
Step 2/4 : RUN touch /tmp/1.txt
---> Running in 342dc5bed915
---> bb4bdf0ddef4
Removing intermediate container 342dc5bed915
Step 3/4 : RUN mkdir /data
---> Running in e612e66a58b8
---> f901b5f6e1fc
Removing intermediate container e612e66a58b8
Step 4/4 : CMD tail -f /tmp/1.txt
---> Running in 0a86b9a502cc
---> 129c32445f24
Removing intermediate container 0a86b9a502cc
Successfully built 129c32445f24
[root@hub ~]# docker run --name test1 -d test:v1.0
be577d8d058ace68faaa9a9b0c89f03e068ca0a9db8bb81aece56ea870c2da76
[root@hub ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
be577d8d058a test:v1.0 "/bin/sh -c 'tail ..." 19 seconds ago Up 19 seconds test1
[root@hub ~]# docker exec -it test1 /bin/bash
[root@be577d8d058a /]# cd /data/
[root@be577d8d058a data]# touch 1
[root@be577d8d058a data]# ls
1
~~~ 还是只有一个数据卷,也就意味着创建的这个镜像没有创建一个新的数据卷
[root@hub ~]# cd /var/lib/docker/volumes/
[root@hub volumes]# ls
a1b7aff5c6fb9f0fac3ec0a277906b061d22103e0875cb46ff6726a02466b63a
### --- 我们需要为容器创建挂载点,就是用我们dockerfile中的VOLUME(指定挂载点)
~~~ test2容器使用VOLUME创建挂载点,生成自管理卷文件
[root@hub ~]# vim Dockerfile
FROM centos:6.8
RUN touch /tmp/1.txt
RUN mkdir /data
VOLUME /data
CMD tail -f /tmp/1.txt
~~~ 带了容器自管理卷的定义
[root@hub ~]# docker build -t test:v2.0 .
Sending build context to Docker daemon 614.6 MB
Step 1/5 : FROM centos:6.8
---> 82f3b5f3c58f
Step 2/5 : RUN touch /tmp/1.txt
---> Using cache
---> bb4bdf0ddef4
Step 3/5 : RUN mkdir /data
---> Using cache
---> f901b5f6e1fc
Step 4/5 : VOLUME /data
---> Running in 8bd939c63e03
---> 6fdf2c7dff97
Removing intermediate container 8bd939c63e03
Step 5/5 : CMD tail -f /tmp/1.txt
---> Running in dec5d7cab0d5
---> 1c3005cfca5c
Removing intermediate container dec5d7cab0d5
Successfully built 1c3005cfca5c
[root@hub ~]# docker run --name test2 -d test:v2.0
37c8d769a03533432ad3dad8ded3f44afb2c682417d354642152e80850af052f
[root@hub ~]# cd /var/lib/docker/volumes/
~~~ 查看会多了一个自管理卷目录文件
[root@hub volumes]# ls
19f2d88d91c8ac1b70f21bee605f8247f2a713680e9e5e6c6feceacb1549ea39 a1b7aff5c6fb9f0fac3ec0a277906b061d22103e0875cb46ff6726a02466b63a
[root@hub volumes]# cd 19f2d88d91c8ac1b70f21bee605f8247f2a713680e9e5e6c6feceacb1549ea39/
~~~ 进来后发现目录是空的,因为定义的/data目录,/data本来就没有数据,
[root@hub 19f2d88d91c8ac1b70f21bee605f8247f2a713680e9e5e6c6feceacb1549ea39]# ls _data/
### --- 发现容器卷的文件还是存在,说明子管理卷的文件没有删除
~~~ 这就是怎么定义容器的自管理卷,以及容器自管理卷的一些特性。
[root@hub ~]# docker exec -it test2 /bin/bash
[root@37c8d769a035 /]# cd data/
[root@37c8d769a035 data]# ls
[root@37c8d769a035 data]# touch {1..66}.txt
[root@hub 19f2d88d91c8ac1b70f21bee605f8247f2a713680e9e5e6c6feceacb1549ea39]# ls _data/
10.txt 13.txt 16.txt // 发现data目录下已经生成文件了,说明我们自定义的容器已经被持久化了,生成了自管理文件
[root@hub ~]# docker rm -f test1 test2 // 删除test1和test2 容器
test1
test2
[root@hub volumes]# ls
19f2d88d91c8ac1b70f21bee605f8247f2a713680e9e5e6c6feceacb1549ea39 a1b7aff5c6fb9f0fac3ec0a277906b061d22103e0875cb46ff6726a02466b63a
### --- 容器的自管理卷在删除容器的时候默认不删除,
~~~ 但我们想删除容器的时候默认删除容器的自管理卷设定
~~~ 在我们删除镜像的时候,容器的自管理卷都存在,并且不会删除;
~~~ 容器的自管理卷我们在定义镜像的时候就定义了这个目录,
~~~ 就代表了这个目录下的数据是非常重要的,默认不删除,这是合理选项。
~~~ 但是我想在删除容器的时候同步删除容器的自管理卷。
~~~ 删除容器的时候一起把自管理卷删除,加上-v选项即可
[root@hub ~]# docker run --name test2 -d test:v2.0 // 启动一个容器且带有容器自管理卷
fdf84fc1485d1c0700fb58041e04a03696e885bb8ff0ee61e44643d02782ed11
[root@hub volumes]# ls
19f2d88d91c8ac1b70f21bee605f8247f2a713680e9e5e6c6feceacb1549ea39 cae221727a169860bcca74dde686cc67b40193a77b7caf54fa9dea5ef8bcee30
a1b7aff5c6fb9f0fac3ec0a277906b061d22103e0875cb46ff6726a02466b63a // 产生了一个容器子管理卷文件
[root@hub ~]# docker rm -f -v test2 // -v同步删除容器子管理卷
test2
[root@hub volumes]# ls // 自管理卷也会自动删除,持久化就删除了。//volumes目录为空,说明删除容器的时候同步删除了宿主机上容器的自管理卷
19f2d88d91c8ac1b70f21bee605f8247f2a713680e9e5e6c6feceacb1549ea39 a1b7aff5c6fb9f0fac3ec0a277906b061d22103e0875cb46ff6726a02466b63a
三、Bind-mount Volume:绑定卷
### --- 查看没有文件,这种的是不带容器子管理卷的。
[root@hub ~]# docker rm -f -v $( docker ps -a -q )
[root@hub ~]# cd /var/lib/docker/volumes/
[root@hub volumes]# rm -rf *
[root@hub volumes]# docker run --name test1 -d test:v1.0
bf7761882c638f52151dee83b1d2ff4ecd7177aa932c8c14e0072ec77bfe02c1
[root@hub volumes]# ls
### --- 像这种情况不带容器子管理卷,且我们还想让他用子管理卷,解决方案
~~~ 定义在容器启动的时候让宿主机的卷和容器内部的两个不同的卷进行绑定。
[root@hub volumes]# mkdir /data
[root@hub volumes]# docker run --name test11 -v /data:/data -d test:v1.0 //-v添加子管理卷。/data表示宿主机的子管理卷 :/data表示容器内部的/data
09ccd119260db0689a11eab22dfbd54c688725ee39db755923774701cfda0162
[root@hub data]# touch yanqi // 在宿主机下/data下创建文件yanqi
[root@hub volumes]# docker exec -it test11 /bin/bash
[root@09ccd119260d /]# ls /data/
yanqi // 有yanqi这个文件,说明宿主机/data和容器内部/data子管理卷已经完成绑定
### --- 如果在dockerfile中添加了子管理卷定义和在容器启动的时候
~~~ 又添加了-v自定义了子管理卷的绑定,那个会优先生效,
~~~ test镜像已在dockerfile中定义了vloume卷的镜像,所以启动容器时候会有子管理卷出现;
[root@hub volumes]# docker run --name test2 -v /data/:/data/ test:v2.0
### --- 理论上启动的容器创建的子管理卷不会放在vloume目录中,
~~~ 会创建对应的目录与之绑定;现在我们又声明了-v,那么vloume下的子管理卷还会生效吗?
~~~ # 说明:我们在dockerfile中定义了vloume卷的某个目录又在容器启动的时候加入
~~~ -v选项定义自管理卷的绑定,它在启动的时候会按照管理员的自绑定卷进行生效,
~~~ 因为-v权限要高于dockerfile中定义的权限。
[root@hub volumes]# docker run --name test2 -v /data/:/data/ -d test:v2.0
506baf8aff4be13d048d9dfb4f065a112a58db8b0b516173ecf660ef40953e58
[root@hub volumes]# ls // vloume下没有生成自管理卷。
[root@hub data]# touch yanqi2 // 在/data下创建yanqi2文件
[root@hub volumes]# docker exec -it test2 /bin/bash
[root@506baf8aff4b /]# ls /data/
yanqi yanqi2 // 在容器/data目录下也会创建yanqi2文件。
### --- 如果我们现在有两个容器test1和test2;他们想要之间的使用同一个共享子管理卷,怎么做。
~~~ 实现容器之间目录之间的共享操作。若有多个目录,加多个-v即可
[root@hub ~]# docker rm -f -v $( docker ps -a -q )
[root@hub ~]# docker run --name test1 -v /data:/data -d test:v1.0
bc3f877aafc1253a2f20159448da037836cb131e430c7b7548677377ce35902f
~~~ test1yanqi文件在test2容器/data/目录下可以查看到在test1容器创建的test1yanqi文件。
[root@hub ~]# docker run --name test2 -v /data:/data -d test:v1.0
d1b92fea6940b31f53d2dc34b83060175fd7ff4a1f8933625a9a7438be536545
[root@hub ~]# docker exec -it test1 /bin/bash
[root@bc3f877aafc1 /]# touch /data/test1yanqi
[root@bc3f877aafc1 /]# ls /data/
test1yanqi yanqi yanqi2
[root@hub ~]# docker exec -it test2 /bin/bash
[root@d1b92fea6940 /]# ls /data/
test1yanqi yanqi yanqi2
四、Union Volume:联合卷
### --- 既不想借助宿主机的工作目录,又想实现容器之间的目录共享解决方案:
~~~ 意味着在使用第二个容器的时候,要去使用第一个容器的目录文件,
~~~ 要依赖于dockerfile中的容器子管理卷
~~~ 如果启动容器的第一个镜像没有定义那个目录,需要去持久化,
~~~ 需要使用到union volume的;因为它根本不知道你那个目录去调用
[root@hub ~]# docker rm -f -v $( docker ps -a -q )
[root@hub ~]# cd /var/lib/docker/volumes/ // 里面是空的,没有任何子管理卷目录
[root@hub volumes]# docker run --name test2 -d test:v2.0
f138101b0a89501a4634c2964a5e591730c6147d85cd0173e69dc4c6f12fd843
[root@hub volumes]# ls
1f89c1f445cc68734677d7ee758388162232340377b6b64dcc2197dfe9d39b0f // volumes下出现容器子管理卷的持久化的目录
[root@hub volumes]# docker run --name test22 --volumes-from test2 -d test:v2.0 //--volumes-from test2 从test2容器里去
48c0f9a0e6a7f34277623f900da41076a53e7c85a004c712eb111ac628d8020f
[root@hub volumes]# ls // 还是一个子管理卷,而我们在dockerfile中声明创建一个子管理卷,理论上是应该创建的,而我们在创建容器的时候添加了--volumes-from test2与容器test2持久化子管理容器管理卷与之绑定
1f89c1f445cc68734677d7ee758388162232340377b6b64dcc2197dfe9d39b0f
[root@hub volumes]# docker exec -it test2 /bin/bash
[root@f138101b0a89 /]# touch /data/test2yanqi // 创建test2yanqi文件
[root@f138101b0a89 /]# ls /data/
test2yanqi
[root@hub volumes]# docker exec -it test22 /bin/bash
[root@48c0f9a0e6a7 /]# ls /data/ // 在test22容器中也可以查看test2yanqi文件,
test2yanqi // 这就实现了不借助宿主机,又可以实现容器之间的目录共享。
Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart
——W.S.Landor
分类:
cdv011-docker
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」