Skip to content

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 ./           #将容器中文件放入本地