本节摘要:持久化的两种形态——引擎管理的标准仓库(数据卷)与直接搬上船的宿主机目录(绑定挂载)。本节用实验验证卷的生命周期独立于容器,并给出选型规则:业务数据选卷,开发挂目录用绑定。
3.1 节有个实验:容器里写的文件随 rm 烟消云散。当时埋的伏笔现在兑现——凡是需要比容器活得久的数据,都要放进外挂仓库。外挂仓库有两种形态,机制与适用场景都不同,本节一次讲透。

卷是引擎管理的一块独立存储,有名字、有生命周期、与容器完全解耦。全套操作走一遍:
# 建仓:显式建一个卷 docker volume create webdata # webdata # 盘点与查仓:列出全部卷,查看某个卷的物理位置 docker volume ls # DRIVER VOLUME NAME # local webdata docker volume inspect webdata --format "物理位置: {{.Mountpoint}}" # 物理位置: /var/lib/docker/volumes/webdata/_data # 起吊时挂仓:把卷接到箱内的数据目录 docker run -d --name vol-demo -v webdata:/usr/share/nginx/html nginx:1.25-alpine
做核心实验:验证卷里的数据比容器命长。
# 往卷里写点东西(借容器之手) docker exec vol-demo sh -c "echo 存进仓库的货物 > /usr/share/nginx/html/goods.txt" # 拆箱 docker rm -f vol-demo # vol-demo # 原地重建一只新箱子,挂同一个卷 docker run -d --name vol-demo2 -v webdata:/usr/share/nginx/html nginx:1.25-alpine # 新箱子读到了旧箱子的货 docker exec vol-demo2 cat /usr/share/nginx/html/goods.txt # 存进仓库的货物
数据穿过容器的生死线完好无损——这就是"容器是牲口,数据是家产"。卷还有两个隐含福利值得点名:空仓首挂自动填充(卷为空时,镜像里挂载点已有的文件会被复制进卷——数据库镜像的默认数据目录正是靠这个初始化的);命名规范(团队约定卷名按"应用-用途"命名,如 order-db-data,运营成本大降)。
绑定挂载把宿主机的确切目录原样接进箱子。开发场景的头号用途是热载:本地改代码,箱内立即可见,省掉反复构建:
# 把宿主机当前目录挂进箱子的网页目录:改一个文件,刷新页面立即生效 docker run -d --name bind-demo -p 8082:80 \ -v "$(pwd)/site:/usr/share/nginx/html" \ nginx:1.25-alpine # 宿主机上改文件 echo "<h1>热载验证</h1>" > site/index.html # 不进箱子、不重建,直接验证生效 curl -s http://localhost:8082 # <h1>热载验证</h1>
绑定挂载的取舍也要摆上台面:它把箱子的可移植性打了对折——挂载路径绑定宿主机目录结构,换台机器未必成立;权限与用户映射问题(容器内外 UID 不一致)在 Linux 上是高频坑。所以规则是:业务数据用卷,开发热载与点对点配置注入用绑定。
其实挂载家族还有第三位成员——tmpfs 挂载:把一块内存当目录挂给容器,写得快、看得见、不落盘,箱子一停就蒸发。敏感临时文件(会话密钥、一次性凭证)与高频临时读写(压测时的缓存目录)是它的主场:
# 三种挂载同台对比(一只箱子全用上) docker run -d --name mounts-demo \ -v appdata:/var/lib/app \ # 具名卷:业务数据 -v "$(pwd)/config:/app/config:ro" \ # 绑定挂载:配置只读注入 --tmpfs /app/tmp:size=64m \ # tmpfs:内存临时区,限 64MB myapp:0.1 # 注意 :ro 后缀:配置目录以只读挂载,箱内进程改不了配置——锁箱纪律的一环 # 只读卷同理:备份、审计类场景给挂载加 :ro,物理上杜绝误写
挂载之外还有一条轻量补给线——docker cp,适合"一次性搬运"而非持续通路:
# 从宿主机搬一件货进箱子(临时塞一份调试配置) docker cp ./app.conf vol-demo2:/etc/app/app.conf # 从箱子搬一件货出来(排障取证:把崩溃现场文件捞出来慢慢看) docker cp vol-demo2:/var/log/app/error.log ./ # 拷贝过程不打断容器,箱子照常在航
它与挂载的分界一句话:cp 是搬一次,挂载是一直通着。临时进料、取证出料用 cp;持续读写的数据通路必须挂载。这条线画不清,就会出"用 cp 传数据库文件"的危险操作——数据文件在写入中途被拷走,得到的多半是损坏副本,这类文件只能走 5.4 节的规范备份流程。
顺带认识一个会偷偷堆积垃圾的形态:匿名卷。挂载时只写箱内路径不写卷名,引擎会生成一串随机名卷。它同样比容器命长,但没人叫得出名字,容器删了它还在,日积月累就成了 dangling 清单里的主力。规范很简单:要持久化就给卷起名,不打算持久化就别挂卷。
仓库多了也要运营。三个高频动作:查占用、清闲置、旧仓核销:
# 查看卷的磁盘占用(du 视角由引擎统计) docker system df -v | head -20 # 清理没有任何容器引用的闲置卷(先看清清单,删除不可逆) docker volume ls -f dangling=true docker volume prune # 确认后输出:Total reclaimed space: 2.6GB
⚠️ 唯一要刻在值班手册封面的警告:volume prune 与 rm 卷之前,确认里面没有唯一份数据——卷不随容器删除,但可以被手工删除,数据库卷误删是真实发生过的重大事故。
仓库会用了,接下来是仓库的运营学:备份、迁移与一套能上生产的持久化纪律。