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

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

(2)容器可以读写 volume 中的数据。

(3)volume 数据可以被永久地保存,即使使用它的容器已经销毁。

举例:(1)Database 软件 & Database数据。(2)Web 应用 & 应用产生的日志。(3)数据分析软件 & input/output 数据。(4)Apache Server & 静态 HTML 文件。

几个例子中,前者都是无状态的,应该作为镜像的一部分。后者放在 Data Volume 中。这是需要持久化的数据,并且应该与镜像分开存放。

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

Bind Mount

将 host 上已经存在的文件或目录 mount 到容器,删除容器后,host 的文件不受到影响。

  1. #首先在本地新建文件夹以挂载到容器
  2. cd ~
  3. vim htdocs/index.html #写入部分内容
  4. #通过 -v 将其 mount 到 httd 容器
  5. docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd
  6. #进入容器之后,发现容器 htdocs 下文件和 host 的 htdocs 一致。
  7. -v 的格式:<host path>:<containerpath>
  8. /usr/local/apache2/htdocs 就是 Apache Server 存放静态文件的地方。由于 /usr/local/apache2/htdocs 已经存在,原有数据会被隐藏起来,取而代之的是 host ~/htdocs/ 中的数据。
  9. #处了绑定目录,还可以绑定文件
  10. docker run -d -p 80:80 -v ~/htdocs/index.html:/usr/local/apache2/htdocs/index.html httpd
  11. 使用 bind mount 单个文件的场景是:只需要向容器添加文件,不希望覆盖整个目录。

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

Docker Managed Volume

  1. <br />docker managed volume 与 bind mount 在使用上的最大区别是不需要指定 mount源,指明 mount point 就行了。
docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
#-v 告诉 docker 需要一个 data volume,并将其 mount 到 /usr/local/apache2/htdocs
docker inspect [ID]
"Mounts": [
            {
                "Type": "volume",
                "Name": "d543be37ff6dd2cd6c596fcd33578e8d6d1f590aa9dc83bf2935255d69d2a692",
                "Source": "/var/lib/docker/volumes/d543be37ff6dd2cd6c596fcd33578e8d6d1f590aa9dc83bf2935255d69d2a692/_data",
                "Destination": "/usr/local/apache2/htdocs",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],
其中,Source 就是该 volume 在 host 上的,目录。容器申请 mount docker manged volume 时,docker 都会在  /var/lib/docker/volumes 下生成一个目录。这个目录就是 mount 源。这里不同的操作系统会有不同效果。使用 Docker desktop 时,目录 Source 结构内容都可以在软件中看到,但是找不到对应的目录。

在 Linux 服务器(centos 系统中)可以按照 Source 找到对应的目录。查找到之后发现 volume 内容跟容器原有 /usr/local/apache2/htdocs。原因是 mount point 指向的是容器中已有目录,原有数据会被复制到 volume 中,容器中的内容和 host volume 中的内容始终保持一致。

docker managed volume 的创建过程:

(1)容器启动时,简单地告诉 docker “我需要一个 volume 存放数据,帮我mount 到目录 /abc (容器内部)”。

(2)docker 在 /var/lib/docker/volumes 中生成一个随机目录作为 mount 源。

(3)如果 /abc 已经存在,则将数据复制到 mount 源。

(4)将 volume mount 到 /abc。

root@Wangying:/# docker volume ls
DRIVER    VOLUME NAME
local     d543be37ff6dd2cd6c596fcd33578e8d6d1f590aa9dc83bf2935255d69d2a692
root@Wangying:/# docker volume inspect d543be37ff6dd2cd6c596fcd33578e8d6d1f590aa9dc83bf2935255d69d2a692 [
    {
        "CreatedAt": "2022-03-30T13:38:44Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/d543be37ff6dd2cd6c596fcd33578e8d6d1f590aa9dc83bf2935255d69d2a692/_data",
        "Name": "d543be37ff6dd2cd6c596fcd33578e8d6d1f590aa9dc83bf2935255d69d2a692",
        "Options": null,
        "Scope": "local"
    }
]

两者都是 host 文件系统中的某个路径。表格展示不同点:

不同点 bind mount docker managed volume
对已有 mount point 影响 隐藏并替换为 volume /var/lib/docker/volumes/…
是否支持单个文件 支持 不支持,只能目录
权限控制 可以设置为只读,默认读写 无控制,均为读写
移植性 弱,与 host path 绑定 强,无需指定 host 目录