docker存储篇

主题一、存储数据
(1)storage driver
定义:docker支持多种storage driver,有AUFS、Device Mapper、Btrfs、OverlayFS、VFS和ZFS。它们都能实现分层的架构,同时又有各自的特性。
优选:对于选择哪种storage driver,docker官方给出了一个简单的答案,就是优先使用linux发行版默认的storage driver。
查看:可以通过docker info查看driver

upload successful
由上图可以看出,Centos用的是overlay2,底层文件系统是extfs,各层数据存放在/var/lib/docker
优缺点:
优点是对于某些容器,直接将数据放在由 storage driver 维护的层中是很好的选择,比如那些无状态的应用。无状态意味着容器没有需要持久化的数据,随时可以从镜像直接创建。比如 busybox,它是一个工具箱,我们启动 busybox 是为了执行诸如 wget,ping 之类的命令,不需要保存数据供以后使用,使用完直接退出,容器删除时存放在容器层中的工作数据也一起被删除;
缺点是对于有持久化数据的需求,容器启动时需要加载已有的数据,容器销毁时希望保留产生的新数据,也就是说,这类容器是有状态的。
这就要用到 Docker 的另一种存储机制:Data Volume。

(2)data volume
定义:Data Volume 本质上是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中。
特点:
Data Volume 是目录或文件,而非没有格式化的磁盘(块设备);
容器可以读写 volume 中的数据;
volume 数据可以被永久的保存,即使使用它的容器已经销毁。
类型:
bind mount:
定义:将host上已存在的目录或文件mount到容器
例子:
1、docker host上有目录$HOME/htdocs:

upload successful
2、通过-v将其 mount 到 httpd 容器:

upload successful
-v的格式为:。/usr/local/apache2/htdocs 就是 apache server 存放静态文件的地方。由于 /usr/local/apache2/htdocs 已经存在,原有数据会被隐藏起来,取而代之的是 host $HOME/htdocs/ 中的数据,这与 linux mount命令的行为是一致的。
3、查看httpd容器的ip:

upload successful
4、在docker host上用curl验证:

upload successful
curl 显示当前主页确实是 $HOME/htdocs/index.html 中的内容
5、更新一下,看是否能生效:

upload successful
6、将容器删除,验证对bind mount的影响:

upload successful
结论:数据依然存在。说明bind mount是docker host系统中的数据,只是借给容器使用
7、设置权限:

upload successful
ro设置了只读权限,在容器中是无法对bind mount数据进行修改的。只有host有权修改数据,提高了安全性。
8、除了mount目录,bind mount还可以单独指定一个文件:

upload successful
使用 bind mount 单个文件的场景是:只需要向容器添加文件,不希望覆盖整个目录。在上面的例子中,我们将 html 文件加到 apache 中,同时也保留了容器原有的数据。使用单一文件有一点要注意:host 中的源文件必须要存在。

docker managed volume:
定义:使用bind mount指定的时候有一个缺点,就是bind mount 需要指定 host 文件系统的特定路径,这就限制了容器的可移植性,当需要将容器迁移到其他 host,而该 host 没有要 mount 的数据或者数据不在相同的路径时,操作会失败。因此引出来docker managed volume,移植性更好的方式是 docker managed volume。
例子:
1、docker managed volume 与 bind mount 在使用上的最大区别是不需要指定 mount 源,指明 mount point 就行了:

upload successful
通过 -v 告诉 docker 需要一个 data volume,并将其 mount 到 /usr/local/apache2/htdocs。
2、查看data volume的位置:docker inspect 28534a2a1452ce(这是容器的短ID),主要关心mount部分:

upload successful
这里会显示容器当前使用的所有 data volume,Source 就是该 volume 在 host 上的目录
3、查看volume里面的内容:

upload successful
volume 的内容跟容器原有 /usr/local/apache2/htdocs 完全一样。
这是因为如果 mount point 指向的是已有目录,原有数据会被复制到 volume 中。我们可以像 bind mount 一样对数据进行操作,例如更新数据。
4、通过docker volume查看volume:

upload successful

备注:总结docker managed volume 的创建过程
1、容器启动时,简单的告诉 docker “我需要一个 volume 存放数据,帮我 mount 到目录 /abc”。
2、docker 在 /var/lib/docker/volumes 中生成一个随机目录作为 mount 源。

两种类型的比较:
相同点:两者都是host文件系统中的某个路径
不同点:

upload successful

两种类型的使用场景:
数据层,或者说镜像层和容器层(storage driver)和volume(data volume)都可以用来存放数据,各自的使用场景:
1、Database软件vs Database数据
2、web应用 vs web应用产生的日志
3、数据分析软件 vs input/output数据
4、Apache server vs 静态html文件
结论:
1、这四种场景中,前者都应该放在数据层,因为这部分内容是无状态的,应该作为镜像的一部分;
2、后者放在data volume。因为这是需要持久化的数据,并且应该与镜像分开存放。

主题二:共享数据
(1)容器与host共享数据
我们有两种类型的 data volume,它们均可实现在容器与 host 之间共享数据,但方式有所区别。
bind mount:直接将要共享的目录 mount 到容器。
docker managed volume:由于 volume 位于 host 中的目录,是在容器启动时才生成,所以需要将共享数据拷贝到 volume 中。

upload successful
备注:
docker cp 可以在容器和 host 之间拷贝数据,当然我们也可以直接通过 Linux 的 cp 命令复制到 /var/lib/docker/volumes/xxx
(2)容器与容器共享数据
方法一:
原理:将共享数据放在 bind mount 中,然后将其 mount 到多个容器。
例子:
1、我们要创建由三个 httpd 容器组成的 web server 集群,它们使用相同的 html 文件:

upload successful
2、修改 volume 中的主页文件,再次查看并确认所有容器都使用了新的主页:

upload successful

方法二:
原理:用 volume container 共享数据
特点:
1、与 bind mount 相比,不必为每一个容器指定 host path,所有 path 都在 volume container 中定义好了,容器只需与 volume container 关联,实现了容器与 host 的解耦。
2、使用 volume container 的容器其 mount point 是一致的,有利于配置的规范和标准化,但也带来一定的局限,使用时需要综合考虑。

例子:
1、volume container 是专门为其他容器提供 volume 的容器。它提供的卷可以是 bind mount,也可以是 docker managed volume

upload successful
我们将容器命名为 vc_data(vc 是 volume container 的缩写)。注意这里执行的是 docker create 命令,这是因为 volume container 的作用只是提供数据,它本身不需要处于运行状态。容器 mount 了两个 volume:
(1)bind mount,存放 web server 的静态文件。
(2)docker managed volume,存放一些实用工具。
2、通过docker inspect vc_data可以查看到这两个volume:

upload successful
3、其他容器通过 –volumes-from 使用 vc_data 这个 volume container

upload successful
4、以webapp4为例

upload successful
webapp4 容器使用的就是 vc_data 的 volume,而且连 mount point 都是一样的。
5、验证数据共享

upload successful
结论:三个容器已经成功共享了volume container中的volume。

方法三:
原理:使用data-packed volume container。其原理是将数据打包到镜像中,然后通过 docker managed volume 共享。
例子:
1、通过Dockerfile创建镜像

upload successful
ADD将静态文件添加到容器目录 /usr/local/apache2/htdocs。VOLUME的作用与-v等效,用来创建docker managed volume,mount point 为/usr/local/apache2/htdocs,因为这个目录就是ADD添加的目录,所以会将已有数据拷贝到volume中。
2、build 新镜像 datapacked

upload successful
备注:htdocs要在当前目录下事先存在
3、用新镜像创建 data-packed volume container

upload successful
4、因为在 Dockerfile 中已经使用了 VOLUME 指令,这里就不需要指定 volume 的 mount point 了。启动 httpd 容器并使用 data-packed volume container

upload successful

data-packed volume container 和 volume container 的区别是:
前者共享的数据是在image中的,不需要修改,任何host上的容器都能用;后者共享的是某个特定host上的数据,只有同一个host上的容器才能用。也就是说, data-packed volume 可以在任何host中使用,这就是区别。这样的方式迁移起来相当方便,但是如果数据有变动的话,只能通过重新构建image的方式来修改。用来做data-packed volume container的base image是越小越好,比如busybox

主题三、volume生命周期管理
1、备份
定义:因为 volume 实际上是 host 文件系统中的目录和文件,所以 volume 的备份实际上是对文件系统的备份。
操作:搭建本地registry

upload successful
所有的本地镜像都存在 host 的 /myregistry 目录中,我们要做的就是定期备份这个目录。
2、恢复
定义:volume 的恢复也很简单,如果数据损坏了,直接用之前备份的数据拷贝到 /myregistry 就可以了。
3、迁移
如果我们想使用更新版本的 Registry,这就涉及到数据迁移,方法是:
(1)docker stop 当前 Registry 容器。
(2)启动新版本容器并 mount 原有 volume
docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:latest
4、销毁
对于bind mount,docker 不会销毁 bind mount,删除数据的工作只能由 host 负责。
对于 docker managed volume,在执行 docker rm 删除容器时可以带上 -v 参数,docker 会将容器使用到的 volume 一并删除,但前提是没有其他容器 mount 该 volume,目的是保护数据。如果没有带上-v参数,这样会产生孤立volume。
例子:
(1)使用docker managed volume 可以创建一个容器bbox

upload successful
(2)删除bbox

upload successful
(3)因为没有使用 -v,volume 遗留了下来。对于这样的孤儿 volume,可以用 docker volume rm 删除

upload successful
(4)也可以这样删除孤儿 volume: docker volume prune
如果想批量删除孤儿 volume,可以执行:
docker volume rm $(docker volume ls -q)

最后总结:
1、docker 为容器提供了两种存储资源:数据层和 Data Volume。
2、数据层包括镜像层和容器层,由 storage driver 管理。
3、Data Volume 有两种类型:bind mount 和 docker managed volume。
4、bind mount 可实现容器与 host 之间,容器与容器之间共享数据。
5、volume container 是一种具有更好移植性的容器间数据共享方案,特别是 data-packed volume container。
6、备份、恢复、迁移和销毁 Data Volume。