storage driver 和 data volume

storage driver方式


docker info | grep "Storage Driver"  #查看系统底成文件系统
Ubuntu 用的 AUFS,底层文件系统是 extfs,各层数据存放在 /var/lib/docker/aufs。 
Redhat/CentOS 的默认 driver 是 Device Mapper,SUSE 则是 Btrfs。

这种方式存储方式在构建镜像过程中把数据copy在镜像中



data volume 方式:

1.data volume介绍



Data Volume 本质上是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中。Data Volume 有以下特点: 
    1. Data Volume 是目录或文件,而非没有格式化的磁盘(块设备)。 
    2. 容器可以读写 volume 中的数据。 
    3. volume 数据可以被永久的保存,即使使用它的容器已经销毁。 
好,现在我们有数据层(镜像层和容器层)和 volume 都可以用来存放数据,具体使用的时候要怎样选择呢?考虑下面几个场景: 
    1. Database 软件 vs Database 数据 
    2. Web 应用 vs 应用产生的日志 
    3. 数据分析软件 vs input/output 数据 
    4. Apache Server vs 静态 HTML 文件 
相信大家会做出这样的选择: 
    1. 前者放在数据层中。因为这部分内容是无状态的,应该作为镜像的一部分。 
    2. 后者放在 Data Volume 中。这是需要持久化的数据,并且应该与镜像分开存放。 
还有个大家可能会关心的问题:如何设置 voluem 的容量? 
因为 volume 实际上是 docker host 文件系统的一部分,所以 volume 的容量取决于文件系统当前未使用的空间,目前还没有方法设置 volume 的容量。 

在具体的使用上,docker 提供了两种类型的 volume:bind mount 和 docker managed volume。



2.data volume 的bind mount 方式



例如 docker host 上有目录 $HOME/htdocs: 
通过 -v 将其 mount 到 httpd 容器: 
  docker run -tid -v $HOME/htdocs:/usr/local/nginx/html httpd 
  [-v 的格式为 <host path>:<container path>。
  /usr/local/apache2/htdocs 就是 apache server 存放静态文件的地方。
  由于 /usr/local/apache2/htdocs 已经存在,原有数据会被隐藏起来,取而代之的是 host $HOME/htdocs/ 中的数据,
  这与 linux mount 命令的行为是一致的。
  bind mount 可以让 host 与容器共享数据。这在管理上是非常方便的.即使容器没有了,bind mount 也还在。
  这也合理,bind mount 是 host 文件系统中的数据,只是借给容器用用,哪能随便就删了啊] 
另外,bind mount 时还可以指定数据的读写权限,默认是可读可写,可指定为只读:
  docker run -tid -v $HOME/htdocs:/usr/local/nginx/html:ro httpd ro 
  设置了只读权限,在容器中是无法对 bind mount 数据进行修改的。
  只有 host 有权修改数据,提高了安全性.
 另外,bind mount 可以挂载当个文件
  [docker run -tid -v /etc/passwd:/etc/passwd httpd.
  注意:使用单一文件有一点要注意:host 中的源文件必须要存在,不然会当作一个新目录 bind mount 给容器]

缺点:bind mount 的使用直观高效,易于理解,但它也有不足的地方:
  bind mount 需要指定 host 文件系统的特定路径,这就限制了容器的可移植性,
  当需要将容器迁移到其他 host,而该 host 没有要 mount 的数据或者数据不在相同的路径时,操作会失败。



2.data volume 的dockermanaged volume方式



docker managed volume 与 bind mount 在使用上的最大区别是不需要指定 mount 源,指明 mount point 就行了。还是以 httpd 容器为例:
docker run -tid -v /usr/local/nginx/html httpd
我们通过 -v 告诉 docker 需要一个 data volume,并将其 mount 到 /usr/local/apache2/htdocs。那么这个 data volume 具体在哪儿呢?
这个答案可以在容器的配置信息中找到,执行 docker inspect xxxxx(容器id)命令:
"Mounts": [ 
    { 
        "Name": "f4a0a1018968f47960efe760829e3c5738c702533d29911b01df9f18babf3340", 
        "Source": "/var/lib/docker/volumes/f4a0a1018968f47960efe760829e3c5738c702533d29911b01df9f18babf3340/_data", 
        "Destination": "/usr/local/apache2/htdocs", 
        "Driver": "local", 
        "Mode": "", 
        "RW": true, 
        "Propagation": "" 
    } 
], 
docker inspect 的输出很多,我们感兴趣的是 Mounts 这部分,这里会显示容器当前使用的所有 data volume,包括 bind mount 和 docker managed volume。
Source 就是该 volume 在 host 上的目录
原来,每当容器申请 mount docker manged volume 时,docker 都会在/var/lib/docker/volumes 下生成一个目录(例子中是 "/var/lib/docker/volumes/f4a0a1018968f47960efe760829e3c5738c702533d29911b01df9f18babf3340/_data ),这个目录就是 mount 源。
volume 的内容跟容器原有 /usr/local/apache2/htdocs 完全一样,这是怎么回事呢?
这是因为:如果 mount point 指向的是已有目录,原有数据会被复制到 volume 中。 
但要明确一点:此时的 /usr/local/apache2/htdocs 已经不再是由 storage driver 管理的层数据了,它已经是一个 data volume。
我们可以像 bind mount 一样对数据进行操作,例如更新数据 : 
echo "this is test...." >> /var/lib/docker/volumes/f4a0a1018968f47960efe760829e3c5738c702533d29911b01df9f18babf3340/_data/index.html
简单回顾一下 docker managed volume 的创建过程:
1.容器启动时,简单的告诉 docker "我需要一个 volume 存放数据,帮我 mount 到目录 /abc"。 
2. docker 在 /var/lib/docker/volumes 中生成一个随机目录作为 mount 源。 
3. 如果 /abc 已经存在,则将数据复制到 mount 源, 
4. 将 volume mount 到 /abc



3.我们已经学习了两种 data volume 的原理和基本使用方法,下面做个对比

  •   相同点:两者都是 host 文件系统中的某个路径。        
  • 不同点:        

 

bind mount            

                docker managed volume            

                volume 位置            

                可任意指定            

/var/lib/docker/volumes/...            

对已有mount point 影响            

                隐藏并替换为 volume            

原有数据复制到 volume            

是否支持单个文件            

                支持            

                不支持,只能是目录            

                权限控制            

                可设置为只读,默认为读写权限            

                无控制,均为读写权限            

                移植性            

                移植性弱,与 host path 绑定            

                移植性强,无需指定 host 目录