--昨夜西风凋碧树,独上高楼,望尽天涯路。
Docker为容器提供了两种存放数据的资源:
(1)由storage driver管理的镜像层和容器层
(2)Data Volume
-
storage driver
docker镜像使用分层结构,分层结构使镜像的创建、共享已经分发变得非常高效,这些都归功于Docker storage driver。
storage driver实现了多层数据的堆叠并为用户提供一个单一的合并之后的统一视图。
Docker安装时会根据当前系统的配置选择默认的driver,centos7使用的storage driver:
比如无状态的应用,直接将数据放在由storage driver维护的层中时很好的选择。无状态意味着容器没有需要持久化的数据,随时可以从镜像直接创建(比如busybox)。
对于有状态的容器并不适合应用这种方式,这类容器有持久化数据的需求,容器启动时需要加载已有的数据,容器销毁时希望保留产生的新数据。
-
Data Volume
Data Volume本质上是Docker Host文件系统中的目录或文件,能够直接被mount到容器的文件系统中。
Data Volume有以下特点:
(1)Data Volume时目录或文件,而非没有格式化的磁盘(块设备)。
(2)容器可以读写volume中的数据。
(3)volume数据可以被永久地保存,即使使用它的容器已经销毁。
对于软件,应用之类的我们可以直接放在数据层中,作为镜像的一部分;对于数据,文件,日志之类的放在Data Volume中,与镜像分开存放。
1.bind mount
bind mount是将host上已存在的目录或文件mount到容器。
在/root目录下新建文件夹htdocs,然后在htdocs中创建index.html:
通过-v参数mount文件夹htdocs到httpd容器:
访问httpd,由于httpd中/usr/local/apache2/htdocs已经存在,源于数据会被隐藏起来,取而代之的是/root/htdocs中的数据:
curl显示的是当前host中index.html中的内容,修改host中文件的内容,再访问httpd,发现挂载生效:
当销毁容器时,bind mount不会改变:
bind mount时还可以指定数据的读写权限,默认是可读可写,可指定为只读:
ro设置了制度权限,再容器中无法对bind mount数据进行修改。只有host有权修改数据:
除了挂载目录,也可以单独挂载文件:
使用bind mount单个文件的场景时:只需要向容器中添加文件,不希望覆盖整个目录。上免得例子中,我们挂载index.html到容器中的new_index.html,保留了容器中原有的数据。
注意:使用单一文件挂载时,host中的源文件必须要存在,不然会当作一个新目录bind mount给容器。
mount point有很多应用场景,比如我们可以将源代码mount到容器中,再host中修改代码就能看到应用的实时效果。再比如将MySQL容器的数据放在bind mount里,这样host可以方便地备份和迁移数据。
bind mount的使用直观高效,但是也有不足的地方:当需要将容器迁移到其他host,而该host没有要mount的数据或者数据不在相同的路径时,操作会失败。
移植性更好的方式是docker managed volume。
2.docker managed volume
docker managed volume与bind mount再使用上最大的区别就是不需要指定mount源,指明mount point就可以了:
通过docker inspect查看:
发现容器申请mount docker managed volume时,docke都会在/var/lib/docker/volumes下生成一个目录,这个目录就是mount源。
volume的内容跟容器原有/usr/local/apache2/htdocs完全一样。这是因为如果mount point指向的是已有目录,原有数据会被复制到volume中。
此时的/usr/local/apache2/htocs已经不再是由storage driver管理的层数据了,它已经是一个data volume。我们可以行bind mount一样对数据进行操作。
总结一下docker managed volume的创建过程:
(1)容器启动时,告诉docker 需要一个volume存放数据,并且mount到mount point下
(2)docker再/var/lib/docker/volumes中生成一个随机目录作为mount源
(3)如果mount point已经存在,则将数据复制到mount源
(4)将volume mount到mount point
通过docker volume查看volume:
docker volume只能看到docker managed volume,看不到bind mount,也无法知道volume对应的容器。具体信息还是要通过docker inspect查看。
两种data volume的比较:
(1)相同点:两者都是host文件系统中的某个路径
(2)不同点:
不同点 | bind mount | docker managed volume |
volume位置 | 可任意指定 | /var/lib/docker/volumes/... |
对已有mount point影响 | 隐藏并替换为volume | 原有数据复制到volume |
是否支持单个文件 | 支持 | 不支持,只能是目录 |
权限控制 | 可设置为只读(默认是读写) | 无控制,均为读写权限 |
移植性 | 移植性弱,与host path绑定 | 移植性强,无须指定host目录 |
-
数据共享
1.容器与host共享数据
两种类型的data volume均可实现容器和host之间的共享数据。
bind mount:直接将要共享的目录mount到容器。
data managed volume:由于volume位于host中的目录,实在容器启动时才生成,所以需要将共享数据复制到volume:
docker cp可以再容器和host之间复制数据,当然我们也可以直接通过Linux的cp命令来复制。
2.容器之间共享数据
有两种方法实现容器之间的共享数据:
(1)将共享数据放在bind mount中,然后将其mount到多个容器。
将$HOMR/htdocs mount到三个httpd容器:
查看数据:
修改volume中的文件,再次查看,发现已改变:
(2)volume container
-
volume container
volume container是专门为其他容器提供volume的容器。它提供的卷可以是bind mount,也可以是docker managed volume。
创建一个volume container:
容器命名为share。这里的命令是docker create,这是由于volume container的作用只是提供数据,本身不需要运行。
容器mount了两个volume:
(1)bind mount
(2)docker managed volume
docker inspect查看这两个volume:
其他容器可以通过--volumes-from使用share这个volume container:
通过docker inspect s1查看s1的volume:
s1容器使用的是shar的volume,并且连mount point也是一样的:
总结:
(1)与bind mount相比,volume不必为每一个容器指定host path,所有的path都在volume container中定义好了,容器只需要与volume container关联,实现了容器与host的解耦。
(2)使用volume container容器,其mount point是一致的,有利于配置的规范和标准化,但也带来一定的局限,使用时需要综合考虑。
-
data-packed volume container
volume container的数据还是再host中,我们可以通过data-packed volume container这种容器来将数据打包到镜像,之后通过docker managed volume 共享。
构建镜像:
VOLUME的作用与-v等效,用来创建docker managed volume,mountpoint为/usr/local/apache2/htdocs,因为这个目录就是ADD添加的目录,所以会将已有的数据复制到volume中。
用新镜像创建data-packed volume container:
由于Dockerfile中已经使用了VOLUME指令,这里不需要指定volume的mount point了。启动httpd容器并使用data-packer volume container:
容器能够正确读取volume中的数据。data-packed volume container是自包含的,不依赖host提供的数据,具有很强的移植性,非常适合只使用静态数据的场景,比如应用的配置信息、Web server的静态文件等。
-
Data Volume生命周期管理
1.备份
因为volume实际上是host文件系统中的目录和文件,所以volume的备份实际上是对文件系统的备份。
搭建好本地的Registry后:
所有本地镜像都保存在host下的/myregistry中,定期备份这个目录。
2.恢复
数据损坏了,直接使用备份的数据复制到/myregistry就可以了。
3.销毁
volume删除后数据无法恢复。
docker 不会销毁bind mount,删除数据只能通过host。对于docker managed volume,在执行docker rm删除容器时带上-v参数,docker会将容器使用到的volume一并删除(前提是没有其他容器mount该volume)。
如果删除容器时没有带-v就会产生孤儿volume,docker提供了volume子命令对docker managed volume 进行维护:
容器使用的docker managed volume可以通过docker volume ls查看:
如果向批量删除孤儿volume执行:
docker volume rm $(docker volume ls -q)