Docker入门之-存储(一):两类存储资源

最后都变了- 提交于 2019-12-16 09:11:46

Docker 为容器提供了两种存放数据的资源,一种是由 storage driver 管理的镜像层和容器层,另一种是Data Volume;

一、storage driver

在学习镜像的时候我们知道Docker 镜像的分层结构:容器由最上面一个可写的容器层,以及若干只读的镜像层组成,容器的数据就存放在这些层中。这样的分层结构最大的特性是 Copy-on-Write:

  • 新数据会直接存放在最上面的容器层;
  • 修改现有数据会先从镜像层将数据复制到容器层,修改后的数据直接保存在容器层中,镜像层保持不变;
  • 如果多个层中有命名相同的文件,用户只能看到最上面那层中的文件

分层结构使镜像和容器的创建、共享以及分发变得非常高效,而这些都要归功于 Docker storage driver;

Docker 支持多种 storage driver,它们都能实现分层的架构,同时又有各自的特性。对于 Docker 用户来说,具体选择使用哪个 storage driver 是一个难题,主要是因为:

  • 没有哪个 driver 能够适应所有的场景。

  • driver 本身在快速发展和迭代

不过 Docker 官方给出了一个简单的答案:优先使用 Linux 发行版默认的 storage driver;

Docker 安装时会根据当前系统的配置选择默认的 driver。默认 driver 具有最好的稳定性,因为默认 driver 在发行版上经过了严格的测试,运行docker info查看 Ubuntu 的默认 driver:

 对于某些容器,直接将数据放在由 storage driver 维护的层中是很好的选择,比如那些无状态的应用。无状态意味着容器没有需要持久化的数据,随时可以从镜像直接创建,比如 busybox,它是一个工具箱,我们启动 busybox 是为了执行诸如 wget,ping 之类的命令,不需要保存数据供以后使用,使用完直接退出,容器删除时存放在容器层中的工作数据也一起被删除,这没问题,下次再启动新容器即可;

但对于另一类应用这种方式就不合适了,它们有持久化数据的需求,容器启动时需要加载已有的数据,容器销毁时希望保留产生的新数据,也就是说,这类容器是有状态的。这就要用到 Docker 的另一种存储机制:Data Volume

二、Data Volume

Data Volume 本质上是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中。

Data Volume 有以下特点:

  • Data Volume 是目录或文件,而非没有格式化的磁盘(块设备)

  • 容器可以读写 volume 中的数据

  • volume 数据可以被永久的保存,即使使用它的容器已经销毁

现在有数据层(镜像层和容器层)和 volume 都可以用来存放数据,具体使用的时候要怎样选择呢?考虑下面几个场景:

  • Database 软件 vs Database 数据;
  • Web 应用 vs 应用产生的日志
  • 数据分析软件 vs input/output 数据
  • Apache Server vs 静态 HTML 文件

相信大家会做出这样的选择:

  • 前者放在数据层中,因为这部分内容是无状态的,应该作为镜像的一部分

  • 后者放在 Data Volume 中,这是需要持久化的数据,并且应该与镜像分开存放

还有个大家可能会关心的问题:如何设置 voluem 的容量?因为 volume 实际上是 docker host 文件系统的一部分,所以 volume 的容量取决于文件系统当前未使用的空间,目前还没有方法设置 volume 的容量。

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

第一种:bind mount是将 host 上已存在的目录或文件 mount 到容器

简单挂载:

通过 -v 将其 mount 到 httpd 容器:-v 的格式为 <host path>:<container path>:

更新一下,看是否能生效:

host 中的修改确实生效了,bind mount 可以让 host 与容器共享数据。这在管理上是非常方便的;

下面我们将容器销毁,看看对 bind mount 有什么影响:

可见,即使容器没有了,bind mount 也还在;

另外,bind mount 时还可以指定数据的读写权限,默认是可读可写,可指定为只读:

第二种: docker managed volume

docker managed volume 与 bind mount 在使用上的最大区别是不需要指定 mount 源,指明 mount point 就行了。

还是以 httpd 容器为例:

 -v 告诉 docker 需要一个 data volume,并将其 mount 到 /usr/local/apache2/htdocs;

终端执行命令:

docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd

 具体结果如下所示:

 

那么这个 data volume 具体在哪儿呢?可以在容器的配置信息中找到,执行 docker inspect 19548c4663b4 命令,

注意,docker inspect 的输出很多,我们感兴趣的是 Mounts 这部分,这里会显示容器当前使用的所有 data volume,包括 bind mount 和 docker managed volume,Source 就是该 volume 在 host 上的目录

即每当容器申请 mount docker manged volume 时,docker 都会在/var/lib/docker/volumes 下生成一个目录,这个目录就是 mount 源;

下面继续研究这个 volume,看看里面有些什么东西:

执行命令如下所示:

ls -l  /var/lib/docker/volumes/29032d6997df522d02bcfa46b1dea8d5cfa0cd964d53baffd35a89c9c56ff761/_data

具体结果如下:

 volume 的内容跟容器原有 /usr/local/apache2/htdocs 完全一样,这是因为:如果 mount point 指向的是已有目录,原有数据会被复制到 volume 中,但要明确一点:此时的 /usr/local/apache2/htdocs 已经不再是由 storage driver 管理的层数据了,它已经是一个 data volume,我们可以像 bind mount 一样对数据进行操作,例如更新数据;

执行命令如下:

echo "update volume from host!" > //var/lib/docker/volumes/29032d6997df522d02bcfa46b1dea8d5cfa0cd964d53baffd35a89c9c56ff761/_data/index.html

具体结果如下:

 

 

 现在,简单回顾一下 docker managed volume 的创建过程:

  • 容器启动时,简单的告诉 docker "我需要一个 volume 存放数据,帮我 mount 到目录 /abc" "
  • docker 在 /var/lib/docker/volumes 中生成一个随机目录作为 mount 源
  • 如果 /abc 已经存在,则将数据复制到 mount 源
  • 将 volume mount 到 /abc

除了通过 docker inspect 查看 volume,我们也可以用 docker volume 命令:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!