首页 / 资讯中心 / 文章详情

Java 项目部署之 Docker工具快速入门: Docker 数据卷命令与挂载实操

Java 项目部署之 Docker工具快速入门: Docker 数据卷命令与挂载实操 ★ FEATURED ARTICLE
概述容器里改个 nginx 首页要docker exec进去、还没有 vim容器一删改的东西全没。数据卷volume就是解决这两件事的把容器内目录接到宿主机文件系统上让数据活得比容器久。纲要为什么需要数据卷容器内数据与容器耦合带来的三个问题不便于修改要进容器、没编辑器数据不可复用新容器得把操作重做一遍升级维护困难删容器 删数据数据卷是什么虚拟目录 → 指向宿主机/var/lib/docker/volumes/卷名/_data数据卷命令create/ls/inspect/prune/rm挂载写法-v 卷名:容器内路径实操创建html卷 → 挂到 nginx 的/usr/share/nginx/html→ 宿主机改文件 → 容器生效 → 删容器重建数据仍在两个高频坑Docker Desktop 上 Mountpoint 不在宿主机真实文件系统里prune会删「未使用」而不是「无用」容器与数据耦合的三个问题先说清楚数据卷要解决的到底是什么。一个 nginx 容器跑起来静态页面在/usr/share/nginx/html配置在/etc/nginx这些目录长在容器的可写层里跟着容器走。由此带来三个麻烦问题具体表现不便于修改要docker exec -it mn bash进容器容器里往往没有 vimsed改文件还容易踩转义数据不可复用在容器里改了一堆配置新建容器时这些修改不会继承只能重做一遍升级维护困难nginx 要升版本就得删旧容器重建容器一删里面改过的页面和配置跟着一起没三个问题的根源是同一个数据被封在容器内部。解法就是把它挪出来。数据卷是什么数据卷volume是一个虚拟目录指向宿主机文件系统中的一个真实目录。这句话里的「虚拟」是关键——卷本身只是一层命名真正存东西的是宿主机上的一个文件夹。在 Linux 上Docker 把所有卷的真实目录统一放在/var/lib/docker/volumes/下卷名html→/var/lib/docker/volumes/html/_data卷名conf→/var/lib/docker/volumes/conf/_data注意那个_data子目录卷目录和真正的数据目录差一层新手cd的时候经常漏掉。容器挂载卷之后三者关系是这样容器Docker 管理的卷宿主机文件系统映射映射-v html:/usr/share/nginx/html-v html:/usr/share/nginx/html-v conf:/etc/nginx-v conf:/etc/nginx/var/lib/docker/volumes/html/_data/var/lib/docker/volumes/conf/_data数据卷 html数据卷 confnginx-1/usr/share/nginx/html/etc/nginxnginx-2/usr/share/nginx/html/etc/nginx图里能直接读出数据卷带来的三个好处改数据不必进容器在宿主机_data里用任何编辑器改文件容器内立刻可见双向实时。多容器共享两个容器挂同一个卷配置、静态资源就复用了不用重复劳动。删容器不删数据容器删掉卷和它指向的宿主机目录都还在新版本容器重新挂上就能接着用旧数据。数据卷命令速查docker是一级命令volume是它下面的二级子命令create、ls、inspect这些才是具体动作结构和docker image、docker container一致。dockervolume[COMMAND]五个常用子命令命令作用常用参数docker volume create创建一个数据卷-d local指定驱动默认 local--label打标签docker volume ls列出所有数据卷-q只输出卷名-f danglingtrue过滤未使用的卷docker volume inspect查看卷详情重点是Mountpoint-f {{.Mountpoint}}直接取挂载点路径docker volume prune删除所有未使用的数据卷-f跳过确认--filter按 label 过滤docker volume rm删除指定的数据卷后面可跟多个卷名create创建一个卷# 创建名为 html 的数据卷dockervolume create html# 带驱动和标签创建local 驱动可省略 -d默认就是它dockervolume create--driverlocal--labelprojecttanhua html-datacreate只在卷不存在时创建同名卷已存在会直接返回卷名不会报错也不会清空原有数据。这点在脚本里可以放心重复执行。ls列出所有卷dockervolumelsDRIVER VOLUME NAME local html local 1a9f0c8b3d2e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a第二行那串 64 位十六进制是匿名卷——镜像里声明了VOLUME比如 mysql 镜像声明了/var/lib/mysql但你docker run时没给它起名Docker 就自动生成。查磁盘占用异常、或者prune删多了往往就是这些匿名卷在背锅。只想要卷名给脚本用dockervolumels-qinspect查看卷挂载到宿主机哪个目录dockervolume inspect html[{CreatedAt:2026-09-29T10:12:3308:00,Driver:local,Labels:null,Mountpoint:/var/lib/docker/volumes/html/_data,Name:html,Options:null,Scope:local}]唯一要盯的就是Mountpoint。写脚本时不需要肉眼抠 JSON用 Go 模板直接取dockervolume inspect html-f{{.Mountpoint}}# /var/lib/docker/volumes/html/_data也可以一次查多个卷docker volume inspect html conf。prune删掉未被引用的卷dockervolume pruneWARNING! This will remove all local volumes not used by at least one container. Are you sure you want to continue? [y/N] y Deleted Volumes: html Total reclaimed space: 12.4kB这里是新手最容易误解的一条prune 删的是「当前没有任何容器引用」的卷不是「所有卷」也不是「没用的卷」。一个卷里可能放着 20G 的 MySQL 数据只要它所属的那个容器被停掉哪怕只是docker stop它就已经「未使用」了prune 会照删不误。反过来也一样正在被容器引用的卷prune 不会碰它要删得先停容器或者直接rm。安全一点的做法是先看看会被删掉哪些再决定# 只看将被 prune 删除的卷不真删dockervolumels-fdanglingtruerm删除指定卷# 删一个dockervolumermhtml# 一次删多个dockervolumermhtml conf卷还被容器挂着时会报这个错Error response from daemon: remove html: volume is in use - [8f3d1c9a7b2e...]先停并删除引用它的容器或者使用docker rm -v见下文「坑」一节。实操给 nginx 挂载数据卷完整走一遍建卷 → 挂载 → 宿主机改文件 → 容器生效 → 删容器重建 → 数据还在。准备素材课程资料目录里跟这次实操有关的部分day03-Docker/资料/ ├── cloud-demo/ │ ├── docker-compose.yml # mysql 用目录挂载$PWD/mysql/data:/var/lib/mysql │ └── mysql/ │ ├── conf/ │ │ └── hmy.cnf # datadir/var/lib/mysql、character_set_serverutf8 │ └── data/ # 真实落盘数据ibdata1、ib_logfile0、cloud_order、cloud_user ├── mysql.tar ├── nginx.conf └── hmy.cnf那个mysql/data/就是「数据与容器解耦」最直观的例子——它是从容器里拷出来的真实数据目录重新起一个 mysql 容器挂上去库表原样恢复。创建卷并挂载# ① 创建数据卷dockervolume create html# ② 确认创建成功dockervolumels# ③ 看它落在宿主机哪个目录dockervolume inspect html-f{{.Mountpoint}}# /var/lib/docker/volumes/html/_data# ④ 创建 nginx 容器把 html 卷挂到容器的静态资源目录dockerrm-fmn2/dev/null# 清掉上一篇残留的同名容器dockerrun--namemn-vhtml:/usr/share/nginx/html-p80:80-dnginx-v的格式是-v 卷名:容器内路径。卷不存在时 Docker 会自动创建但显式create一遍更好——你能先确认名字没写错也不会因为手滑拼错卷名而悄悄多出一个匿名卷。讲义里那段示例有个小问题照抄会踩坑# 讲义原文少了 -d且行尾多了续行符dockerrun\--namemn\-vhtml:/root/html\-p8080:80 nginx\没有-d就是前台运行终端一关容器就停结尾那个\会把命令挂住等你继续输入表现为「回车没反应」。写成一行、补上-d才是能跑的版本。在宿主机改文件容器内立刻生效# 进入卷的真实目录cd/var/lib/docker/volumes/html/_data# 直接改首页宿主机上有 vim容器里没有catindex.htmlEOF !DOCTYPE html html headmeta charsetutf-8titlevolume demo/title/head bodyh1hello from host filesystem/h1/body /html EOF# 不用重启容器直接访问curlhttp://localhost反向也成立——在容器里写文件宿主机目录里马上能看到dockerexecmnsh-cecho written in container /usr/share/nginx/html/probe.txtcat/var/lib/docker/volumes/html/_data/probe.txt# written in container删掉容器数据还在# 删容器dockerrm-fmn# 卷和它的目录都还在dockervolumelsls/var/lib/docker/volumes/html/_data# index.html probe.txt# 起一个新容器重新挂同一个卷dockerrun--namemn2-vhtml:/usr/share/nginx/html-p80:80-dnginxcurlhttp://localhost# 还是刚才那个页面这一步就是「升级维护不丢数据」的完整闭环容器是消耗品卷才是资产。容器 mn / mn2卷 htmlDocker 守护进程宿主机容器 mn / mn2卷 htmlDocker 守护进程宿主机卷与 _data 目录保留docker volume create html创建 /var/lib/docker/volumes/html/_datadocker run -v html:/usr/share/nginx/html绑定到容器目录写入 index.html落到 _data 目录vi index.html 修改容器内立即生效无需重启docker rm -f mndocker run -v html:/usr/share/nginx/html新容器读到旧数据实操中容易踩的坑坑一Mountpoint 在 macOS / Windows 上根本不存在docker volume inspect显示的/var/lib/docker/volumes/html/_data是Docker 守护进程所在环境的路径。Linux 上守护进程就在本机这个路径能直接cd进去。macOS 和 Windows 上用的是 Docker Desktop它在后台起了一个 Linux 虚拟机早期是 HyperKit / Hyper-V新版本是 Apple 的 vmnet containerd守护进程跑在虚拟机里。所以你在 Mac 终端执行cd/var/lib/docker/volumes/html/_data# cd: no such file or directory: /var/lib/docker/volumes/html/_data这是新手最常踩的坑而且报错信息完全不会提示「你在虚拟机外面」。几种绕过去的办法# 办法一起一个临时容器把卷挂进去看/改内容dockerrun--rm-it-vhtml:/data alpinesh# 进入后cd /data ls# 办法二用 cp 在容器和本机之间搬运文件dockerrun--rm-vhtml:/data-v$(pwd):/backup alpine\sh-ccd /data tar cf /backup/html.tar .# 办法三开发机推荐直接用目录挂载路径自己说了算dockerrm-fmn2/dev/null# 清掉上一篇残留的同名容器dockerrun--namemn-v$(pwd)/html:/usr/share/nginx/html-p80:80-dnginx第三种在开发机上最省事代价是目录得自己管理而且要注意 Docker Desktop 的 File Sharing 白名单Settings → Resources → File Sharing没加进白名单的目录挂上去会是空的。坑二prune 与 -v 的误删风险两个容易出事的操作# 危险容器只是停了卷就成了「未使用」里面的数据会被删dockerstop mysql-proddockervolume prune-f# 危险rm -v 会连容器的匿名卷一起删掉dockerrm-vmysql-proddocker-compose down -v同理它会删掉 compose 文件里声明的命名卷生产库数据就是这么没的。排查与防护建议删之前先docker volume ls -f danglingtrue看清单别盲删。重要的卷打 label 区分prune 时用--filter排除docker volume prune --filter label!keep不支持这样反向过滤时就别用 prune改用显式rm。生产环境的数据卷备份放在卷之外别指望卷自身提供安全性——卷只是让数据不随容器消失不是备份。顺带一提卷挂载 vs 目录直接挂载对比项卷挂载-v 卷名:容器目录目录挂载-v 宿主机目录:容器目录目录谁管Docker 管统一在/var/lib/docker/volumes/你自己管路径随意找起来深要inspect才知道在哪一眼就能找到跨平台路径由 Docker 处理行为一致依赖宿主机路径Windows 盘符、Docker Desktop 白名单都要处理初始化容器目录原有内容会被复制到新卷宿主机目录为空时容器内原有内容会被覆盖为空适合场景数据库数据、需要长期保存的状态配置文件、源码、本地开发热重载最后一行那个「覆盖」也是个坑把空目录挂到/etc/nginx上容器里的 nginx.conf 就没了容器起不来。想保留容器内原有文件就用卷挂载或者先把文件拷到宿主机目录里。官方文档docker volume createdocker volume lsdocker volume inspectdocker volume rmdocker volume pruneManage data in Dockervolumes / bind mounts 官方说明总结数据卷是「虚拟目录 → 宿主机真实目录」的一层映射Linux 上落在/var/lib/docker/volumes/卷名/_data注意_data这一层。它解决的是同一个根源问题容器内数据被封死。改起来麻烦、无法复用、删容器即丢数据都是这个根源的三个表现。五条命令记牢分工create建、ls看、inspect定位重点看Mountpoint、prune清未被引用、rm删指定。prune的「未使用」指的是「当前没有容器引用」跟「没用」是两回事停掉的容器卷照样会被删。Docker Desktop 上 Mountpoint 在虚拟机里宿主机cd不进去开发机直接用目录挂载更省事。挂空目录会覆盖容器内原有文件配置类目录要么用卷要么先把文件拷出来。
阅读完成 · 觉得有帮助?
咨询建站