Docker学习笔记(三)docker数据存储

一、Docker分层结构

docker里的镜像绝大部分都是在别的镜像的基础上去进行创建的,也就是使用镜像的分层结构。
比如说使用dockerfile去创建一个最简单的hello镜像。创建好对应的dockerfile之后去进行创建:

FROM alpine:latest
MAINTAINER sbb
CMD echo "hello world"

执行了上面的命令我们可以看到存在着两个镜像,其中hello_world是我刚刚创建好的镜像。

[root@docker ~]# docker imgaes
alpine
hello_world

容器由最上面的一个可写的容器层和若干只读的镜像层组成,容器的数据就存放在这些层中,这些分层结构的最大特性是Copy-on-Write:
新数据会存放在最上面的容器层;
修改现有数据会先从镜像层复制到容器层,修改后的数据存放在容器层,镜像层不变;
如果多个层中有名字相同的文件,用户只能看到最上层的那个文件。
分层结构使镜像和容器的创建、共享及分发变得非常高效,而这些都要归功于Docker Storange driver,正是他实现了多层数据的堆叠并为用户提供了一个单一的合并之后的统一视图。
Docker支持多种Storange driver,有AUFS,Device Mapper,Btrfs等,每个容器会使用自己的操作系统默认的Storange driver,比如Ubuntu是AUFS,CentOS是Device Mapper。
如何查看镜像或容器的Storange driver?使用docker info可以查看:

二、Docker的数据卷

数据卷又叫DataVolume,实际上是宿主机上的目录或文件,可以被挂载到容器中修改或使用,有以下特点:
是目录或文件,而不是磁盘;
挂载后,容器可以读写数据卷中的数据;
即使容器删除了,数据卷也依然存在于宿主机上。
在具体使用上,docker提供了两种类型的Volume:bind mount和docker managed volume。

三、Volume之bind mount

bind mount是把宿主机上的文件或目录挂载到容器,如果容器中有相同的目录或文件,则会把容器中的文件隐藏起来,只显示挂载的文件或目录,命令格式为:

host path:container path

比如,nginx的容器中,web文件index.html放在/usr/share/nginx/html/目录中,访问该页面显示为:

现在我们新建一个index.html,页面内容为“宿主机上的index.html”,存放在宿主机的/data/nginx/html中,并挂载到新的nginx容器中:

[root@docker ~]# docker run --name volume-test -P -d \
-v /data/nginx/html/index.html:/usr/share/nginx/html/index.html \
docker.io/nginx

访问页面显示为(汉字乱码了):
在这里插入图片描述
挂载成功且覆盖了容器中的index.html。
这种方法是只向容器中添加单个文件,即使覆盖也只会影响到容器中的单个文件。如果直接挂载文件目录,则会把容器中的整个文件目录连同里面的文件会全部覆盖。
另外,bind mount还可以在挂载时指定数据的读写权限,默认是可读可写,也可以指定为只读,如:

[root@docker ~]# docker run --name nginx -d -P \
-v /data/nginx/html/index.html:/usr/share/nginx/html/index.html:ro \
docker.io/nginx
e19052f33d61ac3a7f7f8e0f9d40a7143e567264d5463e171578acfdb9edc45d

启动容器后,目录挂载完成,我们尝试进入容器内修改一下index.html文件:

root@e19052f33d61:/# echo "hello world" > /usr/share/nginx/html/index.html
bash: /usr/share/nginx/html/index.html: Read-only file system
root@e19052f33d61:/#

因为我们设置了ro只读权限,所以无法修改。

四、Volume之docker managed volume:

docker managed volume 与 bind mount在使用上的最大区别就是前者不需要手动指定mount源,指明容器内的目的路径就行了。以httpd容器为例:
[root@docker ~]# docker run --name httpd -d -p 80:80 -v /usr/local/apache2/htdocs docker.io/httpd:latest
a4d223d35fe1a24256a08ba20574a42d3731076527ac363295c2b6083130e019
如上,我们的 -v参数后面只需要指明容器内的路径,那么这个源在哪儿呢?我们使用docker inspect container name 就可以看到了:

[root@docker ~]# docker inspect a4d223d35fe1a24256a08ba20574a42d3731076527ac363295c2b6083130e019
 "Mounts": [
            {
                "Type": "volume",
                "Name": "d6366e7ac82498286cc5b51c7057c11d02eba620cf6c3974ee39914ac7f7e76a",
                "Source": "/var/lib/docker/volumes/d6366e7ac82498286cc5b51c7057c11d02eba620cf6c3974ee39914ac7f7e76a/_data",
                "Destination": "/usr/local/apache2/htdocs",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

从上面可以看出:
“Source”: “/var/lib/docker/volumes/d6366e7ac82498286cc5b51c7057c11d02eba620cf6c3974ee39914ac7f7e76a/_data”
就是mount源。可以查看一下这个目录里是什么文件:

[root@docker ~]# ls /var/lib/docker/volumes/d6366e7ac82498286cc5b51c7057c11d02eba620cf6c3974ee39914ac7f7e76a/_data
index.html

目录里存放的文件为index.html,和/usr/local/apache2/htdocs里存放的文件一致。这是为什么呢?这是因为:如果目的路径指向的是容器内的已存在目录,则目的路径内的数据会被复制到源路径中。必须要明确的是:此时的目的路径不再是storange driver管理的层数据,他是一个data volume。我们可以和bind mount 一样对数据进行操作,如:

[root@docker ~]# echo "Update for httpd container" > /var/lib/docker/volumes/d6366e7ac82498286cc5b51c7057c11d02eba620cf6c3974ee39914ac7f7e76a/_data/index.html

此时刷新网页,发现内容已经变了:
在这里插入图片描述
回顾一下docker managed volume创建过程:
容器启动时,告诉docker:我需要一个volume存放数据,挂载到/abc目录;
docker在/var/lib/docker/volumes目录中随机生成一个目录作为mount源;
如果容器中/abc目录已经存在,则把目录中的数据复制到源中;
将源挂载到/abc目录。

五、总结

上面学习了bind mount和docker managed volume这两种data volume,下面来总结一下两者的异同:
位置:bind mount源可以是宿主机上任意位置,而docker managed volume必须是/var/lib/docker/volumes目录内,并且是docker在启动容器时随机指定volume目录名称;
文件类型:bind mount可以挂在文件或目录,而docker managed volume只能是目录;
对容器内数据的影响:bind mount 是把文件或目录从宿主机复制到容器,并且隐藏容器内的同名文件,而后者是把容器内的文件复制到宿主机的volume中;
权限控制:前者可以设置为只读,默认为读写都有的权限,而后者无法控制,默认为读写权限。
可移植性:前者与宿主机的目录绑定,可移植性差,后者无需指定宿主机目录,可移植性强。

bind mount docker managed volume
volume 位置 可任意指定 /var/lib/docker/volumes/…
对已有mount point 影响 隐藏并替换为 volume 原有数据复制到 volume
是否支持单个文件 支持 不支持,只能是目录
权限控制 可设置为只读,默认为读写权限 无控制,均为读写权限
移植性 移植性弱,与 host path 绑定 移植性强,无需指定 host 目录
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章