位置与寿命
先看数据落点
挂载(mount)把外部存储接到容器路径。这个路径叫挂载点。之后访问它,就访问接入的存储。你可以回顾镜像与容器:容器可写层随容器删除而消失,挂载的数据有自己的寿命。
数据卷(volume)由 Docker 管理。这里讨论默认 local 驱动的具名卷,即有明确名字的卷。删除使用它的容器后,卷仍在;删除卷才会删除其中的数据。通常适合数据库等应用数据。[1]
绑定挂载(bind mount)直接使用你指定的主机文件或目录。宿主机编辑器和容器看到的是同一份文件,适合源码与配置。默认可写,容器里的删除也会影响主机文件。[2]
tmpfs是基于内存的临时文件系统。容器停止,数据就丢失;不同容器也不能共享同一个 tmpfs 挂载。Linux 可能把内存换出到磁盘的交换空间(swap),所以它不保证数据绝不落盘。[3]
默认 Linux 卷路径通常形如 /var/lib/docker/volumes/<卷名>/_data,配置可改变位置;用 docker volume inspect <卷名> 看实际 Mountpoint,不要直接编辑 Docker 管理目录。Docker Desktop 的引擎在 Linux 虚拟机里;bind 通过文件共享接入桌面文件。连接远程引擎时,bind 的源路径也在远端。[4] [2]
三个容器分别向图中的 /data 写了文件。停止并删除容器,再以同一具名卷、同一 bind 路径、一个新 tmpfs 启动:哪些文件还在?为什么?
具名卷和 bind 中的文件还在,因为存储独立于容器。新 tmpfs 是空的;旧 tmpfs 在停止时就已释放。这里假定没有额外删除卷或主机文件。
写法
用类型、来源、目标描述
--mount 显式写类型;src 是来源,dst 是容器内的绝对路径。-v 是 --volume 的简写,用冒号依次分隔来源、目标和选项。tmpfs 没有源路径。以下是 docker run 的参数片段,放在镜像名之前。[1] [3]
| 类型 | 显式写法 | 简写 |
|---|---|---|
| 具名卷 | --mount type=volume,src=lesson-data,dst=/data | -v lesson-data:/data |
| 绑定挂载 | --mount "type=bind,src=$PWD/demo,dst=/data" | -v "$PWD/demo:/data" |
| 只读 bind | --mount "type=bind,src=$PWD/demo,dst=/data,readonly" | -v "$PWD/demo:/data:ro" |
| tmpfs | --mount type=tmpfs,dst=/data,tmpfs-size=67108864 | --tmpfs /data:size=64m(不用 -v) |
示例面向 Linux / macOS 的 shell,$PWD 表示当前目录。lesson-data 是卷名,$PWD/demo 是主机路径。两者不能随意互换;-v demo:/data 会选择名为 demo 的卷。readonly / ro 只限制这次挂载的容器写入,不会阻止宿主机或其他可写挂载修改数据。
bind 的源路径不存在时,两种写法的默认行为不同:-v 会尝试创建一个目录,即使你原本想挂文件;--mount type=bind 默认报错。先检查路径,再启动。具名卷不存在时,两种语法都会创建卷。[2] [1]
要把已存在的主机目录接入容器,补全 --mount type=____,src=/home/me/demo,dst=/data,____,并禁止容器写入。
类型:,只读选项:
主机路径对应 type=bind;readonly(或 ro)让容器只能读。卷的来源则是卷名。
深入一点:空卷为什么可能出现镜像文件?
空卷首次挂到容器里已有内容的目录时,Docker 默认会把原有内容复制进卷。这是 volume 的初始化行为。用 --mount type=volume,src=lesson-data,dst=/data,volume-nocopy 可禁用复制。bind 和 tmpfs 没有这项复制行为。重建一个不带挂载的容器,才能再次看到镜像原目录。[1]
动手验证
换个容器再读一次
编写环境没有 Docker。以下命令按官方语法编写,给出预期现象,未提供实测终端输出;维护者补测后再更新记录。
在有 Docker Engine 的本地 Linux shell,或 Docker Desktop 的 Linux 容器模式下操作。需要能运行 Docker,并可拉取 alpine:3.21;首次运行可能先显示拉取信息。不要使用生产目录。
实验会新建一个具名卷和一个主机临时目录,并写入文件。最后的清理只删除本实验资源;所有变量和命令在同一个 shell 中执行。tmpfs 实验适用于 Linux 容器。
实验 A:具名卷跨容器保留
用时间和当前 shell 的进程号组成卷名,避免碰到旧数据。第一个容器写入后自动删除,第二个容器只读同一个卷。sh -c 让容器里的 shell 执行引号内的命令。
预期现象(未实测):第二个容器读到第一步写入的 volume survives 文本。inspect 的 Mountpoint 表示引擎管理的路径,值随环境而变。这个显式命名并创建的卷不会被 --rm 清理。
实验 B:bind 直接读主机文件
mktemp -d 创建本实验专用临时目录;cd 与 pwd -P 得到绝对路径。容器只读挂载,不会修改这份主机文件。
预期现象(未实测):容器与主机两次读取都得到 from host 文本。容器删掉后,主机文件还在。若 Docker Desktop 提示路径未共享,先允许共享该实验目录;远程引擎无法直接使用本机临时目录。
实验 C:新 tmpfs 看不到旧文件
第一个容器把文件写入自己的 tmpfs。第二个容器使用另一个新 tmpfs;test ! -e 检查文件不存在。
预期现象(未实测):第一条读取到 temporary,第二条打印 empty。它验证新容器不会继承旧 tmpfs;停止后释放的规则见官方文档。tmpfs-size 是容量上限,单位为字节;这不是为容器额外分配的内存。[3]
清理实验资源
确认读完记录后再执行。卷中的实验数据、临时目录中的文件将被删除。先检查变量仍指向本实验资源,不要换成业务卷名或业务路径。
实验 A 的第一个容器已被 --rm 删除,为什么第二个容器还能读到文件?
--rm 会在退出后删除容器;检查数据落点,而不是容器是否还在。
挂载目录中的写入去了卷,运行容器也不会把文件写回原镜像。
两个容器通过同一个卷名访问独立存储。--rm 不删除具名卷;如果改为 -v /data,省略来源而由容器创建匿名卷,则这个匿名卷会随 --rm 清理。不要把两者混为一谈。[1]
选择与边界
按数据需求选择
先问数据要不要保留,再问主机程序是否需要直接编辑。需要长期保留、交给 Docker 管理,通常选 volume;要对接主机路径,选 bind;停止即可丢弃的临时文件,可以选 tmpfs。
按题目限制,选最合适的默认方案。先点条目,再点类别;也可用 Tab 和 Enter 操作。
- 数据库文件:要跨容器重建保留,不要求主机编辑器直接访问
- 开发源码:主机编辑保存后,容器立即读到
- 中间计算文件:大小可控,停止即丢弃,不要求跨容器共享
- 已有配置文件:由主机管理员维护,容器只能读
- 用户上传文件:重建后仍要保留,无主机固定路径要求
- 可重算缓存:容量小、只服务本次运行,停止后无需保留
分类取决于需求,volume 和 bind 都能持久化。volume 也需要备份;tmpfs 仍受可用内存约束,不能只因“快”就拿来存唯一数据。配置文件的 bind 应设只读。
深入一点:挂载成功,为什么仍然 Permission denied?
挂载只接通路径,不会自动授予文件权限。UID 是用户的数字身份,GID 是组的数字身份;Linux 根据数字身份、文件所有者和权限位判断能否访问。用户名相同不代表数字相同。
先用 docker run --rm alpine:3.21 id 看容器默认身份,再看目标镜像的运行身份和主机 ls -ln。容器内的用户由镜像的 USER 或运行时 --user 决定。默认以 root 运行的进程写入可写 bind 后,文件可能归主机 root 所有。[5]
在普通本地 Linux、未启用用户映射的环境中,可用下面的未实测示例让容器按当前主机用户读目录;前提是先执行实验 B,保留 lesson_dir。需要写入时,再明确给予目录所有者写权限并去掉 readonly。不要用全目录 chmod 777 掩盖身份问题。
docker run --rm --user "$(id -u):$(id -g)" \
--mount "type=bind,src=$lesson_dir,dst=/data,readonly" \
alpine:3.21 ls -ln /data
Rootless(以非 root 身份运行引擎)和 userns-remap(用户身份映射)会改变容器 UID 与主机 UID 的对应关系,上面的数字匹配方式不一定适用。具名卷也会遇到权限问题;SELinux 的强制访问规则还可能在权限位之外拒绝访问,标签调整应仅限专用目录,按官方说明处理。[6] [2]
检索与迁移
记住三个判断
- 存哪里:volume 在 Docker 管理的存储里,bind 在指定主机路径,tmpfs 在内存文件系统里。
- 何时丢:具名卷和 bind 不随容器删除而自动消失;tmpfs 在容器停止时释放。
- 怎么写:优先用
--mount type=…,src=…,dst=…读清意图;tmpfs 省略来源。只读挂载用readonly。
主机配置文件路径拼错了,还希望容器只能读。哪种写法默认更早暴露路径错误?
-v 遇到不存在的来源会尝试创建目录;ro 只管容器写入权限。
tmpfs 创建临时文件系统,不会读取主机配置文件。
--mount type=bind 默认要求源路径已存在;拼错路径会报错。readonly 明确禁止这个容器写入。这里未启用自动创建来源的额外选项。
同事说:“换成挂载,数据就永远安全了。”请用一个持久化例子和一个丢失例子修正这句话。
参考答案:重建容器后,同名 volume 或同一路径 bind 能找回数据;tmpfs 停止即丢失。持久化也无法代替备份:删除卷、误删 bind 文件或主机磁盘损坏仍会丢失数据。
- 说明 volume / bind 的寿命独立于容器。
- 说明 tmpfs 的停止边界。
- 区分持久化与备份。
来源
核查日期:2026-11-03。以下为持续更新的 Docker 官方文档;本文使用 Docker Engine 29.x 的通用挂载语法,实验未实测。
- Volumes:寿命、具名 / 匿名卷、语法和空卷初始化。
- Bind mounts:主机路径、默认读写、源路径不存在、Desktop 与 SELinux。
- tmpfs mounts:Linux 限制、停止释放、swap 与容量参数。
- Storage:三种存储位置、可写层及卷目录访问限制。
- Running containers · User:默认用户和
--user。 - Isolate containers with a user namespace:UID 映射与 bind 权限。