跳到主要内容Docker 存储卷深度剖析:从创建到实战,掌握容器数据持久化 | 极客日志Shell / Bash
Docker 存储卷深度剖析:从创建到实战,掌握容器数据持久化
深入解析 Docker 存储卷机制,涵盖 Volume、Bind Mount 和 Tmpfs 三种类型的特性与区别。详细演示了 docker volume 系列命令的使用,对比了-v 与--mount 参数的差异,并通过 MySQL 容器数据持久化案例验证了绑定卷在容器销毁后的数据恢复能力。文章还探讨了临时卷的内存特性及常见使用问题,帮助开发者在实际场景中选择合适的存储方案以确保数据安全。
萤火微光1 浏览 一、存储卷相关概念
理解 Docker 存储卷,可以将其视为 Docker Daemon 内部管理的持久化存储机制。
- 存储卷定义:将宿主机本地文件系统中的某个目录,与容器内部文件系统上的某一目录建立绑定关系。
- 数据写入原理:在容器对应目录写入数据时,内容直接写入宿主机上与之绑定的目录。
- 存储卷本质:是存在于
宿主机上的文件或目录,可绕过默认联合文件系统,直接以文件或目录形式存在。
例如宿主机的 /data 目录与容器的 /container/data 目录绑定,容器进程向该目录写数据直接写在宿主机目录上,绕过容器文件系统建立关联,实现宿主机和容器内共享数据内容,二者数据读写同步。因此,如果容器销毁了,那么对应的存储卷还是存在的,也就是对应的数据还在。
二、为什么需要存储卷
- 数据丢失问题:容器分无状态(数据无需持久化)和有状态(数据需持久化)两类。未持久化数据的容器根目录生命周期同容器,删除容器读写层消失。但实际有数据持久化需求,故 Docker 提出卷(Volume)概念。
- 性能问题:UnionFS(联合文件系统)对修改删除等操作效率低,对 I/O 要求高的应用(如 Redis),底层存储时性能要求高(比如需要找某个文件就需要从顶层往底层找,耗性能)。
- 宿主机和容器互访不方便:宿主机与容器互访需通过
docker cp 完成,操作困难。
- 容器和容器共享不方便。
Docker Volume 的出现正是为了解决上面的四大核心问题。
三、存储卷分类
首先可以理解为挂载就是给一个设备提供一个入口,而这个入口可以认为是对应的目录,如磁盘挂载到设备上;也可以理解成新建了一个快捷方式,两者对对应的目录下的内容是一起操作的(同时维护的是一个内容),有一个同步过程。
-
Volume(Docker 管理卷):
- 默认映射到宿主机的
/var/lib/docker/volumes 目录。
- 用户只需指定容器内的挂载点,宿主机下的目录由容器引擎 daemon 自行创建或使用已有目录。
- 解耦用户与存储目录的耦合关系,适合临时存储,但用户无法指定宿主机目录(比如两容器不想共用同一个对应的存储目录)。
-
Bind Mount(绑定数据卷):
- 映射到宿主机指定路径,在宿主机和容器中都需指定特定路径建立关联。
- 宿主机路径需人工指定(优缺点与上面相反,需要自己手动判断对应目录是否有其他东西需要移除)。
-
Tmpfs Mount(临时数据卷):
- 映射到宿主机内存中,容器停止后,tmpfs mounts 被移除,数据丢失。
- 用于高性能的临时数据存储(快,安全)。
总结下:所有的 volumes 的操作(比如 docker volume ls, /var/lib/docker/volumes 等)只是对管理卷(命名卷、匿名卷)的操作;而绑定卷、临时卷都是无效的,也就是上面的那些操作指令,看不了对应的绑定卷、临时卷的信息;要想看就 inspect 容器进行 mount 挂载查看。
四、存储卷使用之管理卷
Volume 命令操作
1. docker volume create
功能:创建存储卷。
语法:docker volume create [OPTIONS] [VOLUME]
关键参数:
-d, --driver:指定驱动,默认是 local。
--label:指定元数据。
不起名字,系统自动默认:
![操作截图]
指定对应名字:
![操作截图]
下面看下详情:
![操作截图]
![操作截图]
发现里面没有东西。
也可以指定标签进行创建:
![操作截图]
![操作截图]
2. docker volume inspect
功能:查看 Docker 卷的详细信息。
语法:docker volume inspect [OPTIONS] VOLUME [VOLUME...]
关键参数:
3. docker volume ls
功能:列出卷。
语法:docker volume ls [OPTIONS]
关键参数:
--format:指定格式,如 json、table。
--filter,-f:过滤。
-q:仅显示名称。
过滤查询与只显示名字:
![操作截图]
![操作截图]
这可以联合其他命令进行批量操作。
4. docker volume rm
功能:删除 Docker 卷,要求卷未被容器使用。
语法:docker volume rm [OPTIONS] VOLUME [VOLUME...](Shell 环境下)。
关键参数:
使用如下:
![操作截图]
成功给没有容器使用的卷写入数据。
![操作截图]
成功清除容器不使用的卷。
5. docker volume prune
命令:docker volume prune
功能:删除不使用的本地卷(匿名卷)
语法:docker volume prune [OPTIONS]
关键参数:
--filter:过滤
-f, --force:不提示是否删除
使用如下:
![操作截图]
这里只会删除不使用的匿名卷,如果是命名卷就需要 rm 来操作。
| 命令 | 别名 | 功能 | 备注 |
|---|
| docker volume create | 无 | 创建存储卷 | 无 |
| docker volume inspect | 无 | 显示存储卷详细信息 | 无 |
| docker volume ls | docker volume list | 列出存储卷 | 无 |
| docker volume prune | 无 | 清理所有无用数据卷 | 无 |
| docker volume rm | 无 | 删除卷,使用中的无法删除 | 无 |
-v 或者 --mount 指定
-v 模式
功能:完成目录映射(默认读写方式)。
语法:docker run -v name:directory[:options] ........
参数:
- 第一个参数:卷名称
- 第二个参数:卷映射到容器的目录(指定容器目录)
- 第三个参数:选项,如
ro 表示 readonly
说明:-v 和 --mount 都可以完成管理卷的创建。
下面以 nginx 容器来测试下无选项模式:
映射对应容器目录到系统默认位置的 n2v 对应下面(手动指定了卷名):
![操作截图]
![操作截图]
![操作截图]
发现映射成功。
下面手动删除容器对应的目录文件:
![操作截图]
发现删除后对应的卷下文件也没有了。
下面再加上 ro 选项试试:
![操作截图]
read only 模式:说明对应的映射后,对应卷内容不能删,映射前的容器对应位置也就不能删除。
--mount 模式
功能:完成目录映射。
语法:在 Shell 中使用 --mount '<key>=<value>,<key>=<value>' 的格式。
关键参数:
type:类型表示为 bind、volume 或 tmpfs。
source / src:对于命名卷,这是卷的名称;对于匿名卷,省略此字段。
destination / dst / target:文件或目录挂载在容器中的路径。
ro / readonly:以只读方式挂载。
下面测试下:
![操作截图]
指定卷名 + 映射的容器的目录。
![操作截图]
![操作截图]
发现容器内删除,对应的卷内也就没了。
![操作截图]
使用匿名卷,效果也是一样的。
![操作截图]
指定对应的 ro,只读形式,对应映射内容就无法删除了。
![操作截图]
![操作截图]
查看容器信息可以看到对应的挂载信息。
Dockerfile 匿名卷
简单介绍下:通过 Dockerfile 的 VOLUME 可创建 docker 管理卷,dockerfile 的 VOLUME 指令在镜像中创建 Data Volume,用该镜像创建的容器会有挂载点,但是 VOLUME 指令创建的挂载点,无法指定主机对应目录,由 docker 随机生成。
管理卷之宿主机与容器之间同步
- 下面验证下当容器与宿主机绑定管理卷的时候,宿主机改变对应内容,容器会进行同步修改。
![操作截图]
创建管理卷,然后进行对应容器启动绑定。
![操作截图]
发现看到的还是这个节界面。
下面修改下宿主机对应管理卷位置映射的容器对应 html:
![操作截图]
![操作截图]
![操作截图]
![操作截图]
发现确实改变了。
因此可以得到,进行容器管理卷映射后,宿主机和容器相当于看到同一份资源,修改是同步的(容器没有使用 ro 选项)。
- 验证当开启了 ro 模式映射的时候,容器修改文件是否可以是否可以同步,然后再试试宿主机能否通过管理卷位置进行文件修改是否可以,是否可以同步?
![操作截图]
启动 ro 模式容器。
![操作截图]
ro 模式容器内部不能修改。
![操作截图]
![操作截图]
在宿主机对应存储卷位置可以进行修改。
![操作截图]
![操作截图]
发现容器内也成功被修改了。
因此,如果开了 ro 模式,对应的容器对应映射位置的目录及文件是只能读取的,但是宿主机可以根据管理卷位置进行修改。
对应的 --mount 的效果和 -v 对应的效果一样,就不演示了。
管理卷的生命周期验证
![操作截图]
进行容器与管理卷绑定。
![操作截图]
![操作截图]
停止并删除容器,发现管理卷内容保存下来了。
![操作截图]
只有删除管理卷,对应的内容才会没有。
因此,当管理卷与容器绑定后,删除容器,管理卷对应映射内容不会消失,只有删除管理卷后才会消失。
管理卷共享验证
下面创建三个容器分别绑定同一个宿主机的管理卷(ro 模式不影响):
![操作截图]
然后修改宿主机的对应映射文件:
![操作截图]
![操作截图]
发现三个容器对应的内容全部同步变化。
总结,绑定同一个宿主机的管理卷的容器们都是共享这个宿主机的管理卷内容的。
五、存储卷使用之绑定卷
这里可以使用 -v 或者 --mount 都可以创建绑定卷。
-v 创建
功能:完成卷映射。
语法:docker run -v name:directory[:options] …
参数:
- 第一个参数:宿主机目录(和管理卷不一样,但是是听宿主机的,宿主机对应目录为空,容器自动同步空,与管理卷不同;比如 nginx 就是这样,但是如 mysql 必须有自带初始化数据,此时就会听 mysql 对应目录下的内容同步到宿主机绑定目录里)。
- 第二个参数:卷映射到容器的目录。
- 第三个参数:选项,如 ro 表示 readonly。
演示下:
![操作截图]
![操作截图]
进入容器发现,被宿主机目录同步过来了,是空的,然后进行容器写,看宿主机是否能收到。
![操作截图]
发现是同步的。
--mount 创建
功能:完成目录映射。
语法:在 Shell 中使用 --mount '<key>=<value>,<key>=<value>' 格式。
关键参数:
- type:表示类型,可以是 bind、volume 或 tmpfs(默认是 volume,但是其这里必须声明是 bind)。
- source、src:宿主机目录(与管理卷不同)。
- destination、dst、target:文件或目录在容器中的挂载路径。
- ro、readonly:以只读方式挂载。
演示下:
![操作截图]
![操作截图]
进行 mount 模式绑定容器,inspect 容器后看到对应绑定信息。
![操作截图]
成功同步,容器内对应映射目录是空的。
![操作截图]
容器修改对应目录内容,宿主机成功收到。
总结下,对应的绑定卷的时候,是宿主机为主,如果宿主机对应目录没内容,就会同步到容器,发生类似覆盖等效果(变空)。
验证对应的宿主机绑定目录不存在以及对应目录下两个内容相同,以宿主机为主还是容器?
--mount 模式
![操作截图]
这里如果对应的宿主机目录不存在就会提示失败。
![操作截图]
![操作截图]
![操作截图]
下面拷贝一份改过的 index.html 文件到绑定的宿主机目录中,然后成功绑定。
![操作截图]
发现容器对应的也修改了,说明同名文件还是以宿主机对应为主。
-v 模式
![操作截图]
这里发现对应的 -v 方式,如果宿主机指定目录不存在会自己创建。
![操作截图]
这里看出来,之前的 bind 目录下有被改过的 index.html;然后新容器绑定启动后,发现也被宿主机的给同步了。
总结下,对于绑定卷创建:-v 模式如果对应的宿主目录不存在会自动生成,但是 --mount 不会,直接报错;然后两者都会进行以宿主机目录为主同步(比如宿主机和容器对应绑定目录文件有相同的)。
其次就是同样绑定卷也是多容器共享的,这里就不演示了。
六、存储卷使用之临时卷
- 临时卷 tmpfs:数据存于内存(存储在容器所运行的宿主机的内存中),在容器(不在对文件系统内)和宿主机之外。
- tmpfs 局限性:无法在容器间共享挂载;仅在 Linux 上运行 Docker 时可用。
- 可见性:tmpfs 只在容器的命名空间内有效,宿主机默认感知不到它的存在,自然也没法直接往里面写文件。
- 重点:容器停止或重启时,对应容器对应的那块内存中的数据会被操作系统自动清除
1. 创建卷 - 方式一:指定–tmpfs 创建:
功能:完成临时卷映射;
语法:run 的时候使用 --tmpfs /app。
演示下:
![操作截图]
在容器内部创建临时卷目录,对应的内容还是在内存中。
下面 inspect 看下容器详情:
![操作截图]
![操作截图]
发现对应的临时卷在容器对应位置,因为这里采取的是 --tmfs 方式创建的临时卷,故 mounts 这里看不到(只有 -v --mount 方式才能看到)。
![操作截图]
进入容器对挂载内存的目录,进去写东西,然后重启容器,发现就没了,因此,可以看出对应的容器那个目录是挂载到了内存中,与内存是同步的。
2. 创建卷 - 方式二:--mount 指定参数创建
功能:完成目录映射
语法:--mount '<key>=<value>,<key>=<value>'
关键参数:
- type:类型为 bind、volume 或 tmpfs
- destination、dst、target:挂载在容器中的路径
- tmpfs-size:tmpfs 挂载大小(字节为单位),默认无限制
- tmpfs-mode:tmpfs 的八进制文件模式,如 700 或 0770,默认为 1777 或全局可写。
演示下:
![操作截图]
进行对应的临时卷创建。
![操作截图]
同样,重启容器后映射在内存的数据就没了。
总结下:
都是进行对应的目录(必须是绝对目录,因为输入目录是从容器视角来看的)的挂载于内存中,然后容器中创建对应临时卷,内容是映射到了内存中(由容器和内存共同维护,一个变化整体变化),因此会看到如果容器断开 重启之类,那么对应的容器对应的在宿主机的那块内存就会情况,因此同步到容器对应的临时卷,对应内容也就没了。
验证创建容器中已经存在目录的临时卷情景以及填充内容后重启后效果
![操作截图]
首先把对应容器的 html 那个主页作为临时卷,发现映射到内存后就被覆盖掉成空了。
![操作截图]
![操作截图]
重新写入后,对应浏览器能访问到。
然后重启容器:
![操作截图]
内容消失,无法访问。
总结下:
对应开始绑定容器的临时卷的时候,以内存为主,如果对应容器目录有东西就被内存覆盖(空内存),之后就是两者同时进行内容操作(也就是写的时候主要还是容器,重启等就是内存进行同步了)。
![操作截图]
验证–mount 选项创建临时卷使用 tmpfs-size
![操作截图]
这里设置成对应挂载目录容量最大为 1m。
下面 inspect 查看容器信息:
![操作截图]
从容器角度可以看到对应的大小,以及挂载目录等。
![操作截图]
从宿主机视角看到对应的挂载信息(这里源目录是内存故看到是空)。
![操作截图]
最后发现,超过了对应目录最大内存限制,无法拷贝。
验证对容器内文件操作及对应容器内临时卷里内容操作是否能被宿主机
![操作截图]
启动对应的容器,并在里面执行 bash。
![操作截图]
![操作截图]
merged:容器里最终看到的'合并后'文件。
diff:该层自己新增/改/删的文件(只存当前层独有的改动)。
也就是 diff 是当前层自己改了啥,merged 是把这些改动和其他层合起来给你看的结果。
这里能看到对应的容器内文件操作(除了临时卷外)都是能被宿主机看到的。
下面看下操作临时卷情况:
![操作截图]
![操作截图]
发现此时就无法查到(因为是基于内存的操作,宿主机查硬盘,自然无法查到)。
总结下:
对于临时卷的话,是基于内存的,如果容器进行对应临时卷内容修改,是也会在内存中进行的修改,因此宿主机默认是看不到的(查磁盘),也很难看到,但是对于管理卷 绑定卷 都是同步可见的。
七、MySQL 容器基于绑定卷后销毁进行数据恢复测试
![操作截图]
进入 Docker hub 对应的 mysql 主页找到对应位置:
![操作截图]
进行基于绑定卷来启动 mysql 容器:
![操作截图]
这里对应的宿主机绑定的目录可以使用相对,因为宿主机会自动识别。
![操作截图]
inspect 可以查看到对应绑定关系。
下面进行连接 mysql,然后模拟数据:
![操作截图]
![操作截图]
![操作截图]
![操作截图]
数据成功被插入,说明这个 mysql 是有数据的。
![操作截图]
删除 mysql 这个容器,然后去宿主机对应的绑定卷位置发现是存在对应数据的。
![操作截图]
起一个新的 mysql 容器,绑定之前 mysql 的那个绑定卷。
![操作截图]
发现对应的数据复原了。
因此总结下:
一般对应数据库这种存储数据启动的容器,就可以采用这种管理卷 绑定卷的模式进行挂载,这样容器销毁,数据还在。
八、对应的卷使用的常见问题
使用场景
- volume:是 Docker 宿主机文件系统一部分,适用于无需规划具体目录的场景(如测试环境)。
- bind:完全依赖主机的目录结构和操作系统,适用于需提前规划目录的情况(如 MySQL 需大空间且其他服务不占用时,用 volume 不合适)。
- tmpfs:用于敏感文件存储,文件不存储在宿主机和容器的可写层中(如隐私信息,敏感信息)。
使用时候常见问题
- 跨主机使用:Docker 存储卷基于宿主机本地文件系统,无法直接跨主机共享,需运维搭建 NFS 等共享存储,未来应用趋向存储与数据分离,采用分布式存储(比如那些有状态的服务,需要记录那些状态变化)。
- 启动参数未知:容器启动选项多,重启易遗忘参数,需文件保存启动配置,容器编排工具可批量操作容器,如开源 K8s 及云厂商企业版编排软件。
- 复杂场景仍然需要运维:有状态集群化组件(如 MySQL 主从)部署维护依赖运维知识和经验,复杂场景难以依靠工具,仍需人力。
总结
本文全面介绍 Docker 存储卷,包括各类命令用法、不同卷模式特点及应用场景,通过实例演示操作,最后点明使用中常见问题,助于掌握 Docker 存储卷知识。
相关免费在线工具
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
- Markdown转HTML
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
- HTML转Markdown
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
- JSON 压缩
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
- JSON美化和格式化
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online