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
命令:
来源:CSDN
作者:w与荒野
链接:https://blog.csdn.net/wuyundong123/article/details/103457327