Docker 数据卷持久化原理
Docker 数据卷持久化原理
一、为什么容器数据会丢失
容器的文件系统是分层的可写层,容器删除后可写层一并销毁。如果把数据库文件、上传的图片直接写在容器内部,一旦容器重启、重建或删除,数据就没了。持久化就是把数据存到容器之外的宿主机或独立存储,让容器变成可随时替换的无状态单元,这是 Docker 生产部署的核心要求。
二、三种持久化方式对比
Docker 提供三种方式把宿主机目录映射进容器,适用场景不同:
1. bind mount(绑定挂载)
直接把宿主机指定目录挂进容器,路径完全由用户控制:
docker run -d \
-v /host/data:/var/lib/mysql \
mysql:8.0
适合把已有配置、上传目录直接暴露到宿主机,缺点是强依赖宿主机目录结构,跨机器迁移麻烦。
2. named volume(命名数据卷)
由 Docker 管理目录,不用关心宿主机具体路径:
docker volume create mysql_data
docker run -d -v mysql_data:/var/lib/mysql mysql:8.0
数据卷由 Docker daemon 管理,可被多个容器共享,备份迁移方便,是数据库首选。
3. tmpfs mount(内存挂载)
数据只存内存,不写磁盘,容器停止即消失,适合临时缓存、敏感密钥,不用于持久化。
三、挂载原理
bind mount 和 volume 在 Linux 底层都通过 mount namespace 实现:容器看到的 /var/lib/mysql 实际指向宿主机对应目录,写入时落到宿主机磁盘,绕过容器分层文件系统。多个容器挂载同一个数据卷时,读写同一份数据,实现共享。
四、docker-compose 写法
多容器项目在 compose 文件里声明数据卷:
version: "3"
services:
db:
image: mysql:8.0
volumes:
- db_data:/var/lib/mysql
- ./my.cnf:/etc/mysql/conf.d/my.cnf:ro
volumes:
db_data:
db_data 是命名卷,./my.cnf 是只读绑定挂载配置文件。
五、备份与迁移
命名卷备份:
docker run --rm -v mysql_data:/src -v $(pwd):/backup \
alpine tar czf /backup/db.tar.gz -C /src .
用临时容器把数据卷打包,再在新机器解包恢复,实现跨主机迁移。
六、常见误区
- 把数据库文件放在容器内,删容器丢数据;
- bind mount 权限不匹配,容器内用户读不到文件;
- 多个容器同时写同一卷不加锁,造成数据竞争;
- 只读配置文件没加
:ro,容器误写宿主机文件; - 忘记定期备份数据卷,磁盘损坏无法恢复。
七、总结
持久化让容器与数据解耦:数据库、上传目录用命名卷,配置文件用只读绑定挂载,临时数据用 tmpfs。理解挂载底层是宿主机目录映射,配合 compose 声明和 tar 备份迁移,就能保证容器重建不丢数据,实现真正的弹性伸缩。