docker数据卷

  • 一、为什么要用数据卷
  • 二、docker卷
  • 1.bind mount
  • 2.docker managed volume
  • 1.自动创建volume
  • 2.改进方式读方式
  • 3.docker管理卷的总结
  • 3.bind mount和docker managed volume的区别

一、为什么要用数据卷

Docker的数据持久化即使数据不随着container的结束而结束,数据存在于host机器上——要么存在于host的某个指定目录中(使用bind mount),要么使用docker自己管理的volume(/var/lib/docker/volumes下)。

Docker中,要想实现数据的持久化(所谓Docker的数据持久化即数据不随着Container的结束而结束),需要将数据从宿主机挂载到容器中。

docker分层文件系统
  性能差
  生命周期与容器相同
docker数据卷
  mount到主机中,绕开分层文件系统
  和主机磁盘性能相同,容器删除后依然保留
  仅限本地磁盘,不能随容器迁移

二、docker卷

docker提供了两种卷:
bind mount
docker managed volume

1.bind mount

(1)基本设置
bind mount 是将 host 上已存在的目录或文件 mount 到容器。
例如 docker host 上有目录 /data/nginx:

[root@localhost ~]# cd /data/nginx/
[root@localhost nginx]# pwd
/data/nginx
[root@localhost nginx]# ls
index.html

通过 -v 将其 mount 到 nginx容器:
-v 的格式为 host path:container path。

[root@localhost ~]# cd /data/nginx/
[root@localhost nginx]# pwd
/data/nginx
[root@localhost nginx]# ls
index.html

#没有mount之前,可以看到目录/usr/share/nginx/html下面是有两个文件的
[root@localhost nginx]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
77f85615efca        nginx               "/docker-entrypoint.…"   3 seconds ago       Up 2 seconds        80/tcp              affectionate_meninsky
[root@localhost nginx]# docker exec -it 77f85615efca /bin/bash
root@77f85615efca:/# ls /usr/share/nginx/html/
50x.html  index.html
 
#挂载之后 /usr/share/nginx/html下面只有一个文件了
[root@localhost nginx]# docker run -itd --name=nginx -p 80:80 -v /data/nginx:/usr/share/nginx/html nginx
3c9be3ad8788544f5533f4e1519592f4b37d4a19f4ea584e0b2d96d76d7f510d
[root@localhost nginx]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
3c9be3ad8788        nginx               "/docker-entrypoint.…"   3 seconds ago       Up 2 seconds        0.0.0.0:80->80/tcp   nginx
 
[root@localhost nginx]# docker exec -it nginx ls /usr/share/nginx/html
index.html
[root@localhost nginx]# cat index.html 
hello nginx
[root@localhost nginx]# docker exec -it nginx cat  /usr/share/nginx/html/index.html
hello nginx

bind9 docker部署 docker bind mount_容器


(2)设置权限

默认权限是读写rw,可以在挂载时指定只读ro。 -v选项指定的路径,如果不存在,挂载时会自动创建。创建后宿主机文件会自动覆盖容器的文件。

bind9 docker部署 docker bind mount_容器_02

2.docker managed volume

1.自动创建volume

docker 管理卷 是docker引擎自动为我们创建的。他在创建前会读取镜像中有没有挂载相关的参数,若有,才会自动创建。

测试:

step1:先将之前docker仓库相关的volume回收。

bind9 docker部署 docker bind mount_bind9 docker部署_03


step2:以nginx镜像为例,它并没有关于卷的挂载,所以使用nginx镜像运行容器后,并没有自动为我们创建卷,这就是因为容器本身就没有定义卷的挂载:

bind9 docker部署 docker bind mount_html_04


反之,registry有定义卷的挂载,所以它可以自动创建卷:

bind9 docker部署 docker bind mount_容器_05


docker inspect demo 中的mounts部分如下:

"Mounts": [
            {
                "Type": "volume",
                "Name": "aa58d391a02d4afcb29d3b4b0f1fdff0e376483f0f7bec1f80026e3d57f03412",
                "Source": "/var/lib/docker/volumes/aa58d391a02d4afcb29d3b4b0f1fdff0e376483f0f7bec1f80026e3d57f03412/_data",
                "Destination": "/var/lib/registry",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

2.改进方式读方式

由上述代码可以看出,根据镜像中关于卷的定义,会为他自动创建一个卷(source部分),然后把他挂载到"Destination"部分,(Destination是容器内的数据路径),但是这种方式 不好读,source部分的位置是随机分配的,我们可以采用以下方式进行:

[root@server1 ~]# docker volume create vol1
vol1
[root@server1 ~]# docker volume inspect vol1
[
    {
        "CreatedAt": "2022-03-12T16:34:02+08:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/vol1/_data",
        "Name": "vol1",
        "Options": {},
        "Scope": "local"
    }
]

bind9 docker部署 docker bind mount_bind9 docker部署_06


这样一比,比之前的/var/lib/docker/volumes/aa58d391a02d4afcb29d3b4b0f1fdff0e376483f0f7bec1f80026e3d57f03412/_data要好的多。

然后 再次运行容器:

docker run -d --name demo -v vol1:/var/lib/registry registry

bind9 docker部署 docker bind mount_nginx_07


docker inspect demo显示的mounts部分如下所示:

bind9 docker部署 docker bind mount_html_08

3.docker管理卷的总结

[root@localhost ~]# cd /var/lib/docker/volumes/a2ddf154e5e224acc154d4895017b65d310f6ca430fadd89ff5d3630e8939e7c/_data
[root@localhost _data]# ls
[root@localhost _data]# touch a.txt
 
[root@localhost _data]# docker exec -it busybox ls /etc/managed
a.txt

原来,每当容器申请 mount docker manged volume 时,docker 都会在/var/lib/docker/volumes 下生成一个目录(例子中是 “/var/lib/docker/volumes/a2ddf154e5e224acc154d4895017b65d310f6ca430fadd89ff5d3630e8939e7c/_data” ),这个目录就是 mount 源。

简单回顾一下 docker managed volume 的创建过程:

1.容器启动时,简单的告诉 docker “我需要一个 volume 存放数据,帮我 mount 到目录 /abc”

2.docker 在 /var/lib/docker/volumes 中生成一个随机目录作为 mount 源

3.如果 /abc 已经存在,则将数据复制到 mount 源

4.将 volume mount 到 /abc

注意:如果你要mount的目录下已经存在了文件,这些文件还是会显示出来不会被隐藏起来,这个和bind mount是不同的

[root@localhost ~]# docker run -itd -v /etc/nginx/ nginx
ee81653a884cff75bdcfae540e814fca19e25b64d546a1ff1761892d227028e5
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
ee81653a884c        nginx               "/docker-entrypoint.…"   4 seconds ago       Up 2 seconds        80/tcp              charming_northcutt
 
[root@localhost ~]# docker exec -it ee81653a884c /bin/bash
root@ee81653a884c:/# cd /etc/nginx/
root@ee81653a884c:/etc/nginx# ls
conf.d	fastcgi_params	koi-utf  koi-win  mime.types  modules  nginx.conf  scgi_params	uwsgi_params  win-utf
 
[root@localhost ~]# docker inspect ee81653a884c
        "Mounts": [
            {
                "Type": "volume",
                "Name": "b923a5a77222defdc83ebd03b79ea121d87d9296535b9d335828a91b2d7d5a2c",
                "Source": "/var/lib/docker/volumes/b923a5a77222defdc83ebd03b79ea121d87d9296535b9d335828a91b2d7d5a2c/_data",
                "Destination": "/etc/nginx",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
[root@localhost ~]# cd /var/lib/docker/volumes/b923a5a77222defdc83ebd03b79ea121d87d9296535b9d335828a91b2d7d5a2c/_data
[root@localhost _data]# ls
conf.d  fastcgi_params  koi-utf  koi-win  mime.types  modules  nginx.conf  scgi_params  uwsgi_params  win-utf

3.bind mount和docker managed volume的区别

bind9 docker部署 docker bind mount_bind9 docker部署_09


(1)volume的位置

由下图可以看出 新创建的卷vol2,它的目录就在/var/lib/docker/volumes/下:

[root@server1 data1]# docker volume create vol2
vol2
[root@server1 data1]# cd /var/lib/docker/volumes/
[root@server1 volumes]# ls
backingFsBlockDev  metadata.db  vol1  vol2
[root@server1 volumes]#

(2)对挂载点的影响

由下图可以看出,以docker管理卷的方式 并不会对挂载点原内容造成覆盖,而以bind mount方式就会对挂载点造成覆盖。

(我们之前自己创建的volume 所以是docker 管理卷 ;而bind mount方式却是直接指定路径)

bind9 docker部署 docker bind mount_容器_10


(3)权限控制

其实,docker managed volume是有一种方式可以指定权限的:

[root@server1 volumes]# docker run -d --name demo -v vol2:/usr/share/nginx/html:ro nginx
aca9d8ca84f76cab0a50bd9ec412f789d05438610eb74746ae44e2bd2ee3d8be
[root@server1 volumes]# docker exec -it demo bash
root@aca9d8ca84f7:/# cd /usr/share/nginx/html
root@aca9d8ca84f7:/usr/share/nginx/html# ls
50x.html  index.html
root@aca9d8ca84f7:/usr/share/nginx/html# touch file1
touch: cannot touch 'file1': Read-only file system