Docker 数据卷与绑定挂载:应用数据放 volume,主机文件用 bind

举报
yd_238478957 发表于 2026/11/10 09:26:43 2026/11/10
【摘要】 前几篇分别讲了用 nginx 托管静态页时的端口映射与文件挂载、练习后的清理、-p 左侧绑定地址,以及镜像标签与 digest。本篇只复查一件事:容器里「要长期留住」的数据,该用 volume(数据卷) 还是 bind mount(绑定挂载)。下列命令均为本机说明示例,请按自己的环境判断是否执行;示例输出为示意,字段以你本机 docker 实际打印为准。容器默认把新文件写在可写层上。容器删掉...

前几篇分别讲了用 nginx 托管静态页时的端口映射与文件挂载、练习后的清理、-p 左侧绑定地址,以及镜像标签与 digest。本篇只复查一件事:容器里「要长期留住」的数据,该用 volume(数据卷) 还是 bind mount(绑定挂载)。下列命令均为本机说明示例,请按自己的环境判断是否执行;示例输出为示意,字段以你本机 docker 实际打印为准。

容器默认把新文件写在可写层上。容器删掉后,这一层一起没了,数据很难单独取出来。官方文档把「把数据放到容器可写层之外」的常用方式分成 volume 与 bind mount(还有 tmpfs 等,本篇不展开)。从容器里面看,两种挂载都只是某个路径;差别在于谁管这份数据、要不要依赖主机目录结构。

1. Volume:交给 Docker 管的持久数据

Volume 由 Docker 创建并管理,数据落在 Docker 主机的存储目录里,但官方明确:不要直接在主机上翻 volume 目录做读写——那是未支持、未定义的行为,可能把数据弄坏。日常用 docker volume 和挂载进容器来操作即可。

官方把 volume 列为「容器生成并使用的数据」的首选持久化方式:不依赖主机目录树和操作系统差异;便于备份与迁移;可用 CLI / API 管理;可在多个容器间更安全地共享;空 volume 挂到容器里已有内容的路径时,默认会把该路径内容复制进 volume(可用 volume-nocopy 关掉)。

# 显式创建命名卷(也可在 docker run 时让 Docker 自动创建)
docker volume create demo-app-data

# 推荐用 --mount,语义更明确
docker run -d --name demo-vol \
  --mount type=volume,src=demo-app-data,dst=/data \
  nginx:stable-alpine

# 等价的 -v 写法(命名卷)
# docker run -d --name demo-vol -v demo-app-data:/data nginx:stable-alpine

容器删了,命名 volume 不会跟着自动删。确认不再需要后再:

docker container stop demo-vol
docker container rm demo-vol
docker volume rm demo-app-data
# 清理大量未使用卷时可用:docker volume prune

匿名 volume(-v /data 这种不写名字)也会在主机上留下随机名;若启动时用了 --rm,与该容器关联的匿名 volume 会在容器退出时被清掉,命名 volume 则不会。需要跨容器复用同一份数据时,优先用命名 volume,不要依赖匿名卷的随机 ID。

2. Bind mount:把主机上的具体路径挂进容器

Bind mount 把主机上已有路径直接挂进容器。适合:本机改源码、构建产物要立刻进容器;把主机上的配置文件共享给容器;在容器里生成文件并希望直接落在主机目录里。Docker 默认把主机的 /etc/resolv.conf 挂进容器做 DNS,就是这类用法。

# 在当前目录准备一个主机侧目录再挂载(路径请换成你自己的)
mkdir -p "$(pwd)/host-static"

docker run -d --name demo-bind \
  --mount type=bind,src="$(pwd)/host-static",dst=/usr/share/nginx/html \
  nginx:stable-alpine

# 只读挂载:容器不能改主机上的这份文件
# docker run -d --name demo-bind-ro \
#   --mount type=bind,src="$(pwd)/host-static",dst=/usr/share/nginx/html,readonly \
#   nginx:stable-alpine

--mount 与 -v 有一点行为差要记住:用 -v 做 bind 时,若主机源路径还不存在,Docker 常会自动建成目录;用 --mount type=bind 时,源路径不存在默认会报错(除非显式加 bind-create-src)。因此写脚本时更推荐 --mount,少一次「不知不觉新建空目录」的意外。

Bind mount 默认可写,容器进程可以改、删主机文件,有安全影响;配置、证书等只读场景请加 readonly / :ro。另外,bind 挂的是 Docker daemon 所在主机 的路径,不是远程客户端本机路径;换一台没有相同目录结构的主机,带着 bind 的容器往往跑不起来。

3. 怎么选:一句话规则

场景 更合适的选择
数据库文件、上传目录、应用自己产生且要跨容器重建保留的数据 命名 volume
本机源码热更新、把主机配置/证书喂给容器、要在文件管理器里直接编辑同一份文件 bind mount
容器删了还想留数据,且不想绑死主机路径 volume
必须同时从「主机进程」和「容器」访问同一路径 bind mount

经验法则(与官方 Learn 材料一致):应用拥有的数据用 volume;你在主机上编辑、拥有的文件用 bind。 两种都可以加只读选项。挂载到容器里非空目录时,原目录内容会被挂载「挡住」——和 Linux 把 U 盘挂到 /mnt 后看不到原文件类似;容器里没有简单的「先卸载再露出原内容」的操作,通常只能重建容器、去掉该挂载。空 volume 挂到有内容的路径时会预填充;bind 则不会把镜像里原路径的内容拷到主机,只是遮住。

用 docker inspect <容器名> 看 Mounts:Type 为 volume 或 bind,可核对 Source / Destination 和是否只读(示意):

"Mounts": [
  {
    "Type": "volume",
    "Name": "demo-app-data",
    "Destination": "/data",
    "RW": true
  }
]

4. 常见误区

  • 把重要数据只写在容器可写层:容器一删数据就没了;要持久化请显式挂 volume 或 bind。
  • 在生产里用 bind 挂数据库目录「图省事」:路径绑死主机,迁移和权限都更脆;官方更推荐 volume 做应用持久数据。
  • 以为删容器等于删 volume:命名 volume 要单独 docker volume rm / prune。
  • 用 -v 绑路径时源目录不存在:可能默默新建空目录,掩盖了「路径写错」;--mount 默认失败更安全。
  • 直接改 /var/lib/docker/volumes/...:官方标为不支持;备份请用挂载进临时容器再 tar 等方式(见 volumes 文档的 backup 示例)。

小结

Volume 是 Docker 管理的持久存储,适合应用自己的数据;bind mount 是主机路径的直接投影,适合开发时共享源码和配置。先问「这份数据归应用还是归我在主机上改」,再选挂载类型,并养成用 --mount、命名 volume、只读选项和「删容器后单独处理 volume」的习惯。练习完记得 stop / rm 自己的演示容器,不需要的命名卷再 volume rm,避免本机堆匿名残留。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。