LV030-存储管理
一、为什么容器需要持久化存储
Docker 容器默认使用 Union FS(联合文件系统)作为其存储层,它允许容器在其基础镜像之上添加自己的文件系统层。这种分层结构使得容器可以快速地创建和销毁,但同时也意味着容器内的数据不是持久的,一旦容器被删除,其数据也会丢失。
默认情况下,容器内创建的所有文件都存储在可写容器层上。这意味着:
- 当该容器不再存在时,数据不会持久存在,并且如果另一个进程需要数据,则可能很难从容器中获取数据。
- 容器的可写层与运行容器的主机紧密耦合。您无法轻松地将数据移动到其他地方。
- 写入容器的可写层需要 存储驱动程序 来管理文件系统。存储驱动程序使用 Linux 内核提供联合文件系统。与使用直接写入主机文件系统的 数据卷 相比,这种额外的抽象会降低性能 。
总之,容器文件系统的本质是在镜像层上面创建的读写层,运行中的容器对任何文件的修改都存在于该读写层,当容器被删除时,容器中的读写层也会随之消失。Docker 有两个选项让容器在主机上存储文件,以便即使在容器停止后文件也能保留:卷和绑定挂载。
二、volume——数据卷
1. 什么是卷?
在 Docker 的世界里,卷(Volumes)可是实现文件共享与持久化存储的 “神器”。简单来说,卷就是一个 特殊的目录,它专门用于绕过容器的常规文件系统,在容器与宿主机之间搭建起一座稳固的数据桥梁。与容器内部普通的目录相比,卷有着本质的区别。容器内普通目录的数据通常是临时存储的,一旦容器停止或被删除,这些数据就如同泡沫般消散;而卷中的数据却能稳稳扎根于宿主机的文件系统,独立于容器的生命周期,始终保持完好无损。
想象一下,我们在容器里运行一个数据库应用,容器内的数据库文件存储在普通目录下,哪天不小心容器崩溃或者需要重新部署,辛辛苦苦录入的数据瞬间化为乌有,这场景简直是 “灾难现场”。但要是使用卷来存储数据库文件,无论容器怎么折腾,数据都安然无恙地躺在宿主机上,随时等待容器重新挂载使用。
2. 接本原理
Docker 卷的实现原理是在主机的 /var/lib/docker/volumes 目录下,根据卷的名称创建相应的目录,然后在每个卷的目录下创建 _data 目录,在容器启动时如果使用 --mount 参数,Docker 会把主机上的目录直接映射到容器的指定目录下,实现数据持久化。
其实卷的本质是文件或者目录,只是它可以绕过默认的联合文件系统,直接以文件或目录的形式存在于宿主机上。卷的概念不仅解决了数据持久化的问题,还解决了容器间共享数据的问题。使用卷可以将容器内的目录或文件持久化,当容器重启后保证数据不丢失。
3. 有什么优势?
(1)卷具有强大的数据持久化能力。正如前文所提到的,容器内应用产生的数据若存储在卷中,即便容器遭遇关停、删除等变故,数据依旧毫发无损地存于宿主机,这为那些需要长期保存数据的应用,如数据库、日志存储等,提供了坚实可靠的后盾。以 MySQL 数据库容器为例,将数据库文件存放于卷内,无论是日常的容器重启优化,还是紧急情况下的容器重建,数据都能无缝衔接,业务连续性得以保障,有效避免因数据丢失带来的巨大损失。
(2)共享便捷。多个容器可以同时挂载同一个卷,瞬间实现数据的互联互通。在一个微服务架构的电商应用里,前端容器、后端 API 容器以及订单处理容器等,可能都需要共享同一份商品配置信息、用户认证密钥等关键数据,通过卷挂载,这些容器就能像共享 “公共资源库” 一样,轻松获取所需数据,极大地简化了容器间的协作流程,提升整体运行效率。
(3)卷独立于容器生命周期这一特性,赋予了开发与运维工作极大的灵活性。开发阶段,开发人员可以随意启停、修改容器,不用担心数据丢失,随时切换不同版本的应用进行测试;运维人员在进行容器迁移、集群扩展等操作时,也无需顾虑数据迁移的繁琐与风险,只需确保卷的正确挂载,就能快速完成任务。
4. 基本命令
4.1 创建数据卷
docker volume create <volume-name>【例】
docker volume create nginx-vol4.2 列出所有卷
docker volume ls4.3 查看卷信息
docker volume inspect 命令可获取挂载路径、驱动类型等元数据。
docker volume inspect <volume-name>【例】
docker volume inspect nginx-vol4.4 挂载到容器
docker run -d --mount src=volume-name,dst=container_dir image
docker run -d -v volume-name:container_dir image【例】
docker run -d --name=nginx-test1 --mount src=nginx-vol,dst=/usr/share/nginx/html nginx
docker run -d --name=nginx-test2 -v nginx-vol:/usr/share/nginx/html nginx4.5 查看是否被使用
docker ps -a --filter volume=volume-name4.6 删除数据卷
- 删除指定数据卷
docker volume rm <volume_name>- 删除未使用的卷
docker volume prune5. 使用示例
5.1 创建一个数据卷
docker volume create test-vol # 创建一个自定义容器卷
docker volume ls # 查看所有容器卷
docker volume inspect test-vol # 查看指定容器卷详情信息【例】
➜ /workspace git:(main) ✗ docker volume create test-vol # 创建一个自定义容器卷
test-vol
➜ /workspace git:(main) ✗ docker volume ls # 查看所有容器卷
DRIVER VOLUME NAME
local test-vol
➜ /workspace git:(main) ✗
➜ /workspace git:(main) ✗ docker volume inspect test-vol # 查看指定容器卷详情信息
[
{
"CreatedAt": "2025-11-01T07:35:25Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/test-vol/_data",
"Name": "test-vol",
"Options": null,
"Scope": "local"
}
]volumes:默认位于 /var/lib/docker/volumes 目录中。/var/lib/docker/volumes/test-vol/_data 这整个路径都需要 root 用户才有权限访问,而 cnb 中,我们并不具备这个权限所以这里就没有办法访问,但是要是在 windows 主机或者 linux 主机上装了 docker 再进行操作的话就没问题了。
5.2 使用数据卷
5.2.1 挂载并创建文件
# 方式 1:--mount
# docker run -d --name my_container -v my_volume:/path/in/container my_image
docker run -it --name=my_container -p 8000:8000 --mount src=test-vol,dst=/usr/share/my-vol-data sumumm/docker-demo:1.0.0 /bin/bash
# 方式 2; -v
# docker run -d --name my_container --mount src = my_volume, dst =/path/in/container my_image
docker run -it --name=my_container -p 8000:8000 -v test-vol:/usr/share/my-vol-data sumumm/docker-demo:1.0.0 /bin/bash无论是使用 -v 还是 --mount 选项,都可以将 Docker 卷挂载到容器中。挂载后,容器就可以读写卷中的数据,实现了数据在容器之间的共享和持久化存储。我们可以使用下面的命令来查看是否有容器使用使用了 test-vol 卷:
docker ps -a --filter volume=test-vol然后我们在容器中往这个数据卷中写入文件:
cd /usr/share/my-vol-data/
echo "my-vol-data" > README.md5.2.2 宿主机访问数据卷
但是我在宿主机中访问的时候报错了,好像没有这个目录以及文件:

这里其实已经告诉我们了,没有权限,因为这是 cnb 的云原生开发环境,所以我们没有 root 用户权限。后来我去 VMware 中的安装的 Ubuntu 系统也尝试了一下:

加上 sudo 权限后就可以了。
5.2.3 其他容器访问
其实我们还可以再创建一个容器,挂载这个卷,就可以看到这个文件和内容了:
docker run -it --name=my_container2 -v test-vol:/usr/share/my-vol-data sumumm/docker-demo:1.0.0 /bin/bash
三、Bind Mount 挂载
1. 简介
BindMount 直接将主机目录直接挂载到容器,适合开发调试场景,可直接修改主机文件并实时生效。
2. 基本命令
# 方法 1:-v 参数(推荐)
docker run -v host_dir:container_dir image
# 方法 2:--mount 参数
docker run --mount type=bind,src=host_dir,dst=container_dir image【例】
# 方法 1:-v 参数(推荐)
docker run -it -v /workspace:/usr/share/workspace sumumm/docker-demo:1.0.0 /bin/bash
# 方法 2:--mount 参数
docker run -it --mount type=bind,src=/workspace,dst=/usr/share/workspace sumumm/docker-demo:1.0.0 /bin/bash3. 使用示例
3.1 挂载目录
docker run -it --mount type=bind,src=/workspace,dst=/usr/share/workspace sumumm/docker-demo:1.0.0 /bin/bash3.2 效果测试
原来 settings.json 文件内容如下:
root@4ac5e5124ed5:/usr/share/workspace# cat settings.json
{
"workbench.colorTheme": "One Dark Pro",
"workbench.iconTheme": "material-icon-theme",
"terminal.integrated.suggest.enabled": true
}我们在宿主机把最后一个选项改为 false:

然后再在容器内查看文件内容:
root@4ac5e5124ed5:/usr/share/workspace# cat settings.json
{
"workbench.colorTheme": "One Dark Pro",
"workbench.iconTheme": "material-icon-theme",
"terminal.integrated.suggest.enabled": false
}我们在容器中创建一个文件并添加内容:

会发现宿主机中也同步产生了文件。
四、总结
前面已经提到了,Docker 提供了三种主要的数据管理方式:
(1)默认存储:容器内的数据随容器删除而丢失
(2)Volumes(卷):由 Docker 管理的持久化存储空间,完全独立于容器的生命周期
(3)Bind Mounts(绑定挂载):将主机上的目录或文件直接挂载到容器中
让我们通过一个 Nginx Web 服务器的例子来理解这三种方式的区别。我们将在每种方式下执行相同的操作:创建一个 HTML 文件,然后测试数据的持久性。
1. 场景一:默认存储(非持久化)
在这个场景中,我们直接在容器内创建文件,看看数据会发生什么:
# 运行一个 nginx 容器
docker run -d --name web-default -p 8000:80 nginx
# 在容器中创建一个测试页面
docker exec -it web-default sh -c \
'echo "<h1>Hello from Default Storage</h1>" > /usr/share/nginx/html/index.html'
# 访问页面验证内容
curl http://localhost:8000
# 删除容器
docker rm -f web-default
# 用同样的配置重新运行容器
docker run -d --name web-default -p 8000:80 nginx
# 再次访问页面,会看到默认的 Nginx 欢迎页面,之前的内容已经丢失
curl http://localhost:80002. 场景二:使用 Bind Mount
在这个场景中,我们将主机上的目录直接挂载到容器中:
# 创建本地目录
mkdir nginx-content
# 运行 Nginx 容器并挂载本地目录
docker run -d --name web-bind \
-p 8081:80 \
-v $(pwd)/nginx-content:/usr/share/nginx/html nginx
# 在容器中创建一个测试页面
docker exec -it web-bind sh -c \
'echo "<h1>Hello from Bind Mount Storage</h1>" > /usr/share/nginx/html/index.html'
# 访问页面验证内容
curl http://localhost:8081
# 删除容器
docker rm -f web-bind
# 用同样的配置重新运行容器
docker run -d --name web-bind-2 -p 8081:80 \
-v $(pwd)/nginx-content:/usr/share/nginx/html nginx
# 再次访问页面,内容仍然存在
curl http://localhost:80813. 场景三:使用 Volume
在这个场景中,我们使用 Docker 管理的卷来存储数据:
# 创建一个 Docker volume
docker volume create nginx_data
# 运行 Nginx 容器并挂载卷
docker run -d --name web-volume -p 8082:80 -v nginx_data:/usr/share/nginx/html nginx
# 在容器中创建一个测试页面
docker exec -it web-volume sh -c 'echo "<h1>Hello from Volume Storage</h1>" > /usr/share/nginx/html/index.html'
# 访问页面验证内容
curl http://localhost:8082
# 删除容器
docker rm -f web-volume
# 用同样的配置重新运行容器
docker run -d --name web-volume-2 -p 8082:80 \
-v nginx_data:/usr/share/nginx/html nginx
# 再次访问页面,内容仍然存在
curl http://localhost:8082
# 查看卷的详细信息
docker volume inspect nginx_data
# 查看卷列表
docker volume ls
# 删除卷
docker volume rm nginx_data4. 三种方式的对比
| 存储类型 | 描述 |
|---|---|
| 默认存储 | - 数据随容器删除而丢失 - 适合存储临时数据 - 容器间数据隔离 - 无需额外配置 |
| Bind Mount | - 数据持久化,存储在主机指定位置 - 可以直接在主机上修改文件,并实时生效 - 将主机目录直接挂载到容器,适合开发调试场景,在开发环境中方便调试和修改 - 依赖主机文件系统结构 |
| Volume | - 数据持久化,独立于容器生命周期 - Docker 统一管理,方便备份和迁移 - 可以在多个容器间共享 - 数据存储在 Docker 管理区域,安全性好 |
5. 清理操作
完成上面的实验后,可以进行清理:
# 清理容器
docker rm -f web-default web-volume web-volume-2 web-bind web-bind-2
# 清理卷
docker volume rm nginx_data
# 清理本地目录
rm -rf nginx-content参考资料:
还在为 Docker 宿主机与容器文件共享发愁?看这一篇就够了!_docker 共享文件夹-CSDN 博客