菜单
本页目录

[TOC]

4 Docker数据存储

一、数据卷特性:

启动容器后,创建可写层,在可写层中 ”写时复制“

“卷”是容器上的一个或多个“目录”,此类目录可绕过联合文件系统,与宿主机上的某目录“绑定”

解决的问题: 存在于联合文件系统中,不易于宿主机访问 容器间数据共享不便 删除容器其数据会丢失

二、数据卷结构:

image-20230104215450535

image-20230104215519637

1)Docker 管理卷

Docker-managed volume

核心:写入Dockerfile中,创建镜像时指定挂载目录

VOLUME 容器中挂载的路径

在容器创建以后,会自动在 /var/lib/docker/volumes/随机的目录/_data/ 与容器中挂载的路径关联,持久化

$ docker rm -v 				#删除容器时,连带删除持久卷

$ docker rm -f -v test			#删除容器时,删除持久化存储
								#前提:启动的test容器,基于有volume关键字的镜像

2)绑定挂载卷

Bind mount volume

核心:运行容器时,加入参数,指定挂载目录

$ docker run -v 主机路径:容器路径

注意:当 docker run -v 与 VOLUME 指定的挂载目录冲突时,以 docker run -v 为准(作用域小,优先级高)

实验1:指定挂载位置,实现数据存储

解决:

​ 存在于联合文件系统中,不易于宿主机访问 ​ 删除容器其数据会丢失

1、基于 Dockerfile 中 有 VOLUME 参数创建的镜像,实现

[root@localhost ~]# vim Dockerfile 
[root@localhost ~]# cat Dockerfile
FROM 163
VOLUME /data
WORKDIR /data

[root@localhost ~]# docker build -t volume:v1 .
[root@localhost ~]# docker run --name test -d volume:v1					#基于volume:v1镜像运行容器
												注意:此处不能用 $ docker run --name test --rm -it volume:v1 /bin/bash
[root@localhost ~]# docker exec -it test /bin/bash
[root@4b3da857052b data]# touch yqqq{1..5}.txt
[root@4b3da857052b data]# exit

[root@localhost ~]# cc			#清除所有容器
4b3da857052b
[root@localhost ~]# find /var/lib/docker/volumes/ -name "yqq*"			#能找到文件
/var/lib/docker/volumes/23be7ebe569e133601fa6d8e6cc6cf54603badb5e9080c50c1de26e8f62bd130/_data/yqqq1.txt
/var/lib/docker/volumes/23be7ebe569e133601fa6d8e6cc6cf54603badb5e9080c50c1de26e8f62bd130/_data/yqqq2.txt
/var/lib/docker/volumes/23be7ebe569e133601fa6d8e6cc6cf54603badb5e9080c50c1de26e8f62bd130/_data/yqqq3.txt
/var/lib/docker/volumes/23be7ebe569e133601fa6d8e6cc6cf54603badb5e9080c50c1de26e8f62bd130/_data/yqqq4.txt
/var/lib/docker/volumes/23be7ebe569e133601fa6d8e6cc6cf54603badb5e9080c50c1de26e8f62bd130/_data/yqqq5.txt

2、docker run -v 运行容器时,实现

[root@localhost ~]# docker run --name test -d -v /data:/data1 nginx:latest			#加-v创建容器
2c6d5927c6f3f3727d12d6db3c879312095c1e1942f85b3e9603d5ea774e6825

[root@localhost ~]# cd /data/							#在本地目录中创建文件
[root@localhost data]# touch qweasd
[root@localhost data]# ls
qweasd


[root@localhost data]# docker exec -it test /bin/bash		#进入容器,到指定目录发现数据存在
root@2c6d5927c6f3:/# cd /data1/
root@2c6d5927c6f3:/data1# ls
qweasd

3、测试 VOLUME 与 docker run -v 的优先级

注意:当 docker run -v 与 VOLUME 指定的挂载目录冲突时,以 docker run -v 为准(作用域小,优先级高)

#wordpress镜像中默认有VOLUME选项,基于wordpress镜像,加-v选项启动容器
[root@localhost ~]# docker run --name wordpress -d -v /html:/var/www/html wordpress
3a5ba96b5d92101e62b1d042502e69580e8aa6bc31847d7e6021b5c9bdc8eb18
[root@localhost ~]# ls /html/					#到/html目录下发现wordpress的文件
index.php        wp-admin              wp-config-sample.php  wp-links-opml.php  wp-settings.php
license.txt      wp-blog-header.php    wp-content            wp-load.php        wp-signup.php
readme.html      wp-comments-post.php  wp-cron.php           wp-login.php       wp-trackback.php
wp-activate.php  wp-config-docker.php  wp-includes           wp-mail.php        xmlrpc.php
[root@localhost ~]# touch /html/yangqindaociyiyou			#创建一个文件
[root@localhost ~]# docker exec -it wordpress /bin/bash		#进入容器,发现有刚才创建的文件,持久化存储成功,docker run -v 优先级高
root@3a5ba96b5d92:/var/www/html# ls |grep yangqin
yangqindaociyiyou

实验2:容器间的数据共享

解决:容器间数据共享不便

[root@localhost ~]# docker run --name wordpress1 -d wordpress				#先启动一个wordpress1容器
bb06b81560eff736acc7583a8f22d2536b7abd4d9af9301293002d2533755823
[root@localhost ~]# docker inspect wordpress1 |grep  Source					#找到数据存储位置
                "Source": "/var/lib/docker/volumes/b81ff34f82ba5e253d6f30e5c246b5130beaa2e40b310f5c28b46b759e4d0864/_data",


#基于找到的位置,加-v选项启动wordpress2、wordpress3
[root@localhost ~]# docker run --name wordpress2 -d -v /var/lib/docker/volumes/b81ff34f82ba5e253d6f30e5c246b5130beaa2e40b310f5c28b46b759e4d0864/_data:/var/www/html wordpress
1c27bd5267bfaa3c49843f27cc56f911103a886617f1cc632a7536a5ee789a22
[root@localhost ~]# docker run --name wordpress3 -d -v /var/lib/docker/volumes/b81ff34f82ba5e253d6f30e5c246b5130beaa2e40b310f5c28b46b759e4d0864/_data:/var/www/html wordpress
c700222b21a2e2489dbaf573e8e4aa035b68561f29a60b344a0ec7340a289216


#测试:在本地目录中创建文件,进入容器中查看,实现容器间的数据共享
[root@localhost _data]# touch QQQQQQQQQQQQQQQQQQQQQQQ
[root@localhost _data]# docker exec wordpress1 ls

[root@localhost _data]# docker exec wordpress2 ls

[root@localhost _data]# docker exec wordpress3 ls

拓展:--volumes-from #指定其他容器的挂载路径启动容器

$ docker run --volumes-from 容器名			#指定其他容器的挂载路径,启动容器

将实验2步骤简化:

[root@localhost ~]# docker run --name wordpress1 -d wordpress

[root@localhost ~]# docker run --name wordpress2 -d --volumes-from wordpress1 wordpress

[root@localhost ~]# docker run --name wordpress3 -d --volumes-from wordpress1 wordpress

[root@localhost ~]# docker exec wordpress1 touch AAAAAAAAAAAAAAA

[root@localhost ~]# docker exec wordpress2 ls

[root@localhost ~]# docker exec wordpress3 ls

三、存储驱动

#对应关系
UFS			类比		webserver	(类型,归纳)
overlay		类比		nginx		(具体项)

1)Docker 存储驱动 ( storage driver )

是 Docker 的核心组件,它是 Docker 实现分成镜像的基础

    1、device mapper ( DM ):性能和稳定性存在问题,不推荐生产环境使用
    		centos6 默认为DM
    		老版本的docker默认采用DM
    2、btrfs:社区实现了 btrfs driver,稳定性和性能存在问题
    3、overlayfs:内核 3.18 overlayfs 进入主线,性能和稳定性优异,第一选择
    		NAS:(不是网络NAS网络附加存储,是NAS网络附加存储延伸出的一个概念)
    			FREENAS
    			TRUENAS
    		overlayv2 128层限制

2)启用 overlay 存储引擎

以前版本没有启用 overlay 存储引擎,启用 overlay 存储引擎(现阶段默认已经启用,一般不会用到)

$ echo "overlay" > /etc/modules-load.d/overlay.conf
$ cat /proc/modules|grep overlay						#若能截取到overlay关键字,即overlay已经启用
$ reboot										#若未启用,重启电脑 
$ vim /etc/systemd/system/docker.service		#修改docker配置文件(根据系统版本不同,配置文件位置不一样)
	--storage-driver=overlay				#在启动命令后加入选项

image-20230105104139835

3) overlay 存储驱动使用实例

1、核心命令:

$ mount -t overlay overlay -o lowerdir=./low,upperdir=./upper,workdir=./work ./merged

$ mount -t overlay overlay -o lowerdir=./lower1:./lower2:./lower3,upperdir=./upper,workdir=./work ./merged
           ------- -------     ----------------------------------  --------------   ------------   -------
			  |	  	  |                      |                            |               |           |
			  |		  |                      |                            |               |           |
			  V		  |                      |                            |               |           |
指定overlay文件系统     |                      |                            |               |           |
                      V                      |                            |               |           |
       指定当前挂载的路径                       |                            |               |           |
                                             V                            |               |           |
                    指定lower的路径,对应于仅读层,多个用 : 隔开                |               |           |
                                                                          V               |           |
                                                          指定upper的路径,相当于可写层       |           |
                                                                                         V            |
                                                                         指定work目录,工作缓存目录       |
                                                                                    				  |
                                                                                    				  V
                                                                                    		指定merged的位置,对应挂载点位置

2、实验详细:

1.创建环境目录,挂载overlay文件系统

#创建实验环境的目录
[root@localhost ~]# mkdir overlay
[root@localhost ~]# cd overlay/
[root@localhost overlay]# mkdir lower1 lower2 lower3 upper work merged

#向对应仅读层中写入数据
[root@localhost overlay]# echo "1" > lower1/1.html
[root@localhost overlay]# echo "2" > lower2/2.html
[root@localhost overlay]# echo "3" > lower3/3.html


#挂载overlay文件系统				
[root@localhost overlay]# mount -t overlay ./overlay -o lowerdir=./lower1:./lower2:./lower3,upperdir=./upper,workdir=./work ./merged
[root@localhost overlay]# mount |grep overlay
/dev/mapper/centos-root on /var/lib/docker/overlay type xfs (rw,relatime,attr2,inode64,noquota)
./overlay on /root/overlay/merged type overlay (rw,relatime,lowerdir=./lower1:./lower2:./lower3,upperdir=./upper,workdir=./work)

2.测试 overlay 文件系统使用

仅在挂载目录,对数据进行操作,符合“写时复制”规则(对其他目录的操作不合理)

启用overlay文件系统后,挂载目录中,会自动挂载仅读层的数据

[root@localhost overlay]# tree .
.
├── lower1
│   └── 1.html
├── lower2
│   └── 2.html
├── lower3
│   └── 3.html
├── merged
│   ├── 1.html
│   ├── 2.html
│   └── 3.html
├── upper
└── work
    └── work

7 directories, 6 files

[root@localhost overlay]# cat merged/1.html 
1
[root@localhost overlay]# cat merged/2.html 
2
[root@localhost overlay]# cat merged/3.html 
3

a.写入

[root@localhost overlay]# echo "123123" >> merged/1.html 			#符合写时复制,将复制lower仅读层到可写层upper中,再对数据进行修改
[root@localhost overlay]# echo "222222" >> merged/2.html 
[root@localhost overlay]# tree .
.
├── lower1
│   └── 1.html
├── lower2
│   └── 2.html
├── lower3
│   └── 3.html
├── merged
│   ├── 1.html
│   ├── 2.html
│   └── 3.html
├── upper
│   ├── 1.html
│   └── 2.html
└── work
    └── work

7 directories, 8 files
[root@localhost overlay]# cat upper/1.html 				#用户使用的挂载点,显示的内容跟可写层相关
1
123123
[root@localhost overlay]# cat merged/1.html 
1
123123

[root@localhost overlay]# cat upper/2.html 
2
222222
[root@localhost overlay]# cat merged/2.html 
2
222222


b.删除

[root@localhost overlay]# rm -rf merged/2.html 			#删除数据,在可写层标记文件删除
														#挂载点向下读取时,经过可写层标记已删除,即不在挂载点显示
														#本质上没有删除lower仅读层的数据
[root@localhost overlay]# tree .
.
├── lower1
│   └── 1.html
├── lower2
│   └── 2.html
├── lower3
│   └── 3.html
├── merged
│   ├── 1.html
│   └── 3.html
├── upper
│   ├── 1.html
│   └── 2.html
└── work
    └── work

7 directories, 7 files
[root@localhost overlay]# ls -l upper/*
-rw-r--r-- 1 root root    9 1月   5 18:21 upper/1.html
c--------- 1 root root 0, 0 1月   5 18:22 upper/2.html			#可写层中,文件类型为c,表示:标记文件删除


#以下操作不合理,只是为了演示:在挂载点处删除的文件,本质上没有对lower仅读层文件删除
[root@localhost overlay]# rm -rf upper/2.html 			#删除可写层中的,标记文件删除
[root@localhost overlay]# tree .
.
├── lower1
│   └── 1.html
├── lower2
│   └── 2.html
├── lower3
│   └── 3.html
├── merged
│   ├── 1.html
│   ├── 2.html										#在挂载点中 2.html 找回
│   └── 3.html
├── upper
│   └── 1.html
└── work
    └── work

7 directories, 7 files
[root@localhost overlay]# cat merged/2.html 		#且数据为lower仅读层中数据
2

4)容器中 overlay 存储驱动使用实例

可写层随着容器的删除而删除,可写层所挂载的位置也会删除

(再次强调:仅能对挂载点位置数据进行修改,对其他目录进行修改可能会造成数据损坏)

[root@localhost ~]# docker run --name wordpress -d wordpress				#运行一个wordpress容器
a91d43dd8947b27c32a107650794d6768a7f7e50243ae90c0bb4f743e8d9c514
[root@localhost ~]# docker exec -it wordpress /bin/bash						#进入容器,到 /root/ 下创建文件
root@a91d43dd8947:/var/www/html# cd && ls
root@a91d43dd8947:~# touch yangqindaociyiyou
root@a91d43dd8947:~# 
exit
[root@localhost ~]# find /var/lib/docker/overlay/ -name yangqindaociyiyou	#在本地找到刚才创建文件的位置
/var/lib/docker/overlay/cfd7b36a48172c0f7739759b690d43f4b0ab7b95a89b77e39d57e42b19937e73/upper/root/yangqindaociyiyou
/var/lib/docker/overlay/cfd7b36a48172c0f7739759b690d43f4b0ab7b95a89b77e39d57e42b19937e73/merged/root/yangqindaociyiyou

[root@localhost ~]# ls /var/lib/docker/overlay/cfd7b36a48172c0f7739759b690d43f4b0ab7b95a89b77e39d57e42b19937e73
lower-id  merged  upper  work			
									#lower-id:记录可写层
									#merged:挂载点位置
									#upper:可写层目录
									#work:工作缓存目录

#下面测试:在挂载目录创建文件,进入容器中验证文件存在(即验证容器使用 overlay 文件系统)
[root@localhost ~]# cd /var/lib/docker/overlay/cfd7b36a48172c0f7739759b690d43f4b0ab7b95a89b77e39d57e42b19937e73/merged/
[root@localhost merged]# ls root/
yangqindaociyiyou
[root@localhost merged]# touch root/daociyiyouyangqin

[root@localhost merged]# docker exec -it wordpress /bin/bash
root@a91d43dd8947:/var/www/html# cd ;ls
daociyiyouyangqin  yangqindaociyiyou

5)拓展 docker cp

docker cp 					#本地与容器之间的文件复制
							(原理:找到容器可写层的挂载点位置中文件所在位置,再进行复制)

$ docker cp Dockerfile wordpress:/root/				#将本地文件上传到容器中
				|			|
				V			|
			本地文件		 |
						   |
						   V
						容器位置
						
$ docekr cp wordpress:/root/Dockerfile ./			#将容器中文件放入本地