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 的文件不受到影响。
#首先在本地新建文件夹以挂载到容器
cd ~
vim htdocs/index.html #写入部分内容
#通过 -v 将其 mount 到 httd 容器
docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd
#进入容器之后,发现容器 htdocs 下文件和 host 的 htdocs 一致。
-v 的格式:<host path>:<containerpath>
/usr/local/apache2/htdocs 就是 Apache Server 存放静态文件的地方。由于 /usr/local/apache2/htdocs 已经存在,原有数据会被隐藏起来,取而代之的是 host ~/htdocs/ 中的数据。
#处了绑定目录,还可以绑定文件
docker run -d -p 80:80 -v ~/htdocs/index.html:/usr/local/apache2/htdocs/index.html httpd
使用 bind mount 单个文件的场景是:只需要向容器添加文件,不希望覆盖整个目录。
bind mount 的使用直观高效,易于理解,但它也有不足的地方:bind mount 需要指定 host 文件系统的特定路径,这就限制了容器的可移植性,当需要将容器迁移到其他 host,而该 host 没有要 mount 的数据或者数据不在相同的路径时,操作会失败。
Docker Managed Volume
<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 目录 |