docker为容器提供了两种存放数据的资源; 1.由storage driver管理的镜像层和容器层 2.Data Volume
在前面镜像章节我们学习到Docker镜像的分层结构,我们来简单回顾一下 容器由最上面的一个可写的容器层,以及若干只读的镜像层组成,容器的数据就存放在这些层中,这样的分层结构最大的特性就是Copy-on-Write: 1.数据会直接存放在最上面的容器层 2.修改现有的数据会先从镜像层将数据复制到容器层,修改后的数据直接操存在容器层中,镜像层保持不变 3.如果有多个层中有命名相同的文件,用户只能看到最上面的那层中的文件 分层结构使镜像和容器的创建,共享以及分发变得非常高效,而这些都要归功于Docker storage diriver,正是storage diriver实现了多层数据的堆叠并为用户提供一个单一的合并之后的统一视图
[root@docker ~]# docker info|grep Storage Storage Driver: overlay2 #Docker安装时会根据当前系统的配置选择默认的driver #默认的driver具有最好的稳定性对于某些容器,直接将数据放在由storage diriver维护的层中是很好的选择,比如那些无状态的应用,无状态意味着容器没有需要持久话的数据,随时可以从镜像直接创建 但是对于另一类应用这种方式就不合适了,它们有持久化数据的需求,容器启动时需要加载已有的数据,容器销毁时希望保留产生的新数据,也就是说,这类容器是有状态的 这就要用到docker的另一种机制:Data Volume Data Volume 本质上是 Docker Host文件系统中的目录或文件,能够直接被mount到容器的文件系统中,具有以下特点: 1.Data Volume是目录或者文件,而非没有格式化的磁盘(块设备) 2.容器可以读写volume中的数据 3.volume数据可以白永久地保存,即使使用它的容器已经被销毁
bind mount 是将host上已经存在的目录或文件 mount到容器
[root@foundation0 htdocs]# pwd /mnt/htdocs [root@foundation0 htdocs]# cat index.html <h1>Have a nice day!</h1> # -v的格式为:<host path>:<container path> [root@foundation0 htdocs]# docker run -d -p 8080:80 -v /mnt/htdocs:/usr/local/apache2/htdocs httpd eaaad31d18a5a53464f057c60c43a1438e5b16a988fd5351ed3b0fb48994df02 [root@foundation0 ~]# curl 127.0.0.1:8080 <h1>Have a nice day!</h1> [root@foundation0 htdocs]# echo 'lucky!!' > index.html [root@foundation0 htdocs]# curl -I 127.0.0.1:8080 HTTP/1.1 200 OK Date: Tue, 21 May 2019 08:03:23 GMT Server: Apache/2.4.39 (Unix) Last-Modified: Tue, 21 May 2019 08:03:03 GMT ETag: "8-5896147425d6b" Accept-Ranges: bytes Content-Length: 8 Content-Type: text/html [root@foundation0 htdocs]# curl 127.0.0.1:8080 lucky!! [root@foundation0 htdocs]# curl 127.0.0.1:8080 lucky!! # 即使我们停止并且删除容器,本地文件也不会删除 [root@foundation0 htdocs]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES eaaad31d18a5 httpd "httpd-foreground" 3 minutes ago Up 3 minutes 0.0.0.0:8080->80/tcp xenodochial_kilby [root@foundation0 htdocs]# docker stop eaaad31d18a5 eaaad31d18a5 [root@foundation0 htdocs]# docker rm -f eaaad31d18a5 eaaad31d18a5 [root@foundation0 htdocs]# cat index.html lucky!! # 整个目录的映射 [root@foundation0 htdocs]# docker run -d -p 8080:80 -v /mnt/htdocs/:/usr/local/apache2/htdocs httpd970f628c4b1fd25e54747c5acbdfb6670afe845faeeeb45fe049895559fb9955 [root@foundation0 htdocs]# curl 127.0.0.1:8080/test_index.html test!!!!!!!! [root@foundation0 htdocs]# ls index.html test_index.html 另外,bind mount时还可以指定数据的读写权限 [root@foundation0 htdocs]# docker run -d -p 8080:80 -v /mnt/htdocs:/usr/local/apache2/htdocs:ro httpd a4753bd187caa049e6782a38d676032285c59f198bde9a3239cf51b0ef81945e [root@foundation0 htdocs]# docker exec -it a4753bd187 /bin/bash root@a4753bd187ca:/usr/local/apache2# echo "do some changes" > htdocs/index.html bash: htdocs/index.html: Read-only file system #ro 设置了只读权限,在容器中是无法对bind mount数据进行修改的,只有host有权修改数据,提高了安全性 除了bind mount 目录,还可以单独指定一个文件 [root@foundation0 htdocs]# docker run -d -p 8080:80 -v /mnt/htdocs/index.html:/usr/local/apache2/htdocs/new_index.html httpd 292129fc9a5a850dfed1c0cc8416c7699833454821f3362ff7cc1bbfea251c4a [root@foundation0 htdocs]# curl 127.0.0.1:8080 <html><body><h1>It works!</h1></body></html> [root@foundation0 htdocs]# curl 127.0.0.1:8080/new_index.html lucky!! #使用bind mount单个文件的场景是:只需要向容器添加文件,不希望覆盖整个目录 # 使用单一文件有一点要注意:host中的源文件必须要存在 """ mount point 有很多应用场景,比如我们可以将源代码目录mount到容器中, 在host中修改代码就能看到应用的实时效果,再比如将Mysql容器的数据 放在bind mount里,这样host可以方便地备份和迁移数据 bind mount的使用直观高效,易于理解,但它也有不足的地方: bind mount需要指定host文件系统的特定路径,这就限制了容器的可移植性, 当需要将容器迁移到其他host,该host没有要mount的数据或者数据在 不同的路径时,操作会失败 """docker managed volume与bind mount在使用上最大的区别是不需要指定mount 源,指明mount point就行了
[root@foundation0 htdocs]# docker run -d -p 8080:80 -v /usr/local/apache2/htdocs httpd 0a8b3290d4fff435bfc24fa8024d8470092e976b699fc21317d819a924cbd431 [root@foundation0 htdocs]# docker inspect 0a8b3290d4fff43 "Mounts": [ { "Type": "volume", "Name": "05e10fc94bc6ad3156d423aefb72b739753832764f99494fe5d658ba82fa9463", "Source": "/var/lib/docker/volumes/05e10fc94bc6ad3156d423aefb72b739753832764f99494fe5d658ba82fa9463/_data", "Destination": "/usr/local/apache2/htdocs", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], [root@foundation0 volumes]# cd 05e10fc94bc6ad3156d423aefb72b739753832764f99494fe5d658ba82fa9463 [root@foundation0 05e10fc94bc6ad3156d423aefb72b739753832764f99494fe5d658ba82fa9463]# ls _data [root@foundation0 05e10fc94bc6ad3156d423aefb72b739753832764f99494fe5d658ba82fa9463]# cd _data/ [root@foundation0 _data]# ls index.html [root@foundation0 _data]# cat index.html <html><body><h1>It works!</h1></body></html> [root@foundation0 _data]# pwd /var/lib/docker/volumes/05e10fc94bc6ad3156d423aefb72b739753832764f99494fe5d658ba82fa9463/_data [root@foundation0 _data]# echo 'update volume from host!!!' > index.html [root@foundation0 _data]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0a8b3290d4ff httpd "httpd-foreground" 33 minutes ago Up 33 minutes 0.0.0.0:8080->80/tcp wizardly_edison [root@foundation0 _data]# curl 127.0.0.1:8080 update volume from host!!! [root@foundation0 _data]# pwd /var/lib/docker/volumes/05e10fc94bc6ad3156d423aefb72b739753832764f99494fe5d658ba82fa9463/_data """ 回顾一下docker managed volume的创建过程 1.容器启动时,简单的告诉docker我需要一个volume存放数据,帮我mount到目录 2.docker在/var/lib/docker/volumes中生成一个随机目录作为mount源 3.如果/abc已经存在,则将数据复制到mount源 4.如果/abc已经存在,则将数据复制到mount源 4.将volume mount到/abc """