Docker 中的持久化存储(如数据库数据)该怎么管理?
用 Docker volume 管理持久数据:docker volume create 创建,docker run -v 卷名:/容器路径 挂载,复用卷可跨容器生命周期保留数据,但需避免误删并备份;有状态服务也可使用合适的绑定挂载,数据库打包备份需先正常停止所有写入者。
标准做法:用命名卷(named volume)——docker volume create mydata 创建,docker run -v mydata:/var/lib/mysql 挂载到容器的数据目录。卷数据存在宿主机由 Docker 管理的目录里,复用持久卷时可跨容器生命周期保留数据,但仍受显式删除、宿主故障和升级兼容性影响;有状态数据应使用持久卷或合适的绑定挂载并备份。
基本用法
# 创建卷
docker volume create mysqldata
# 先在当前会话安全设置 MYSQL_ROOT_PASSWORD,再挂载使用
docker run -d --name mysql \
-v mysqldata:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD \
mysql:8
# 查看与定位
docker volume ls
docker volume inspect mysqldata # 看宿主机上的实际路径
不写 docker volume create 直接在 -v 名字:/路径 里用新名字,Docker 会自动创建命名卷。
三种挂载方式对比
| 方式 | 写法 | 适用 |
|---|---|---|
| 命名卷 | -v mysqldata:/var/lib/mysql |
数据库等应用数据,首选 |
| 绑定挂载 | -v /host/dir:/container/dir |
要直接看到/编辑宿主机文件(配置、代码热更) |
| tmpfs | --tmpfs /run |
临时数据,不持久化;可能进入 swap,敏感数据需额外控制 |
备份与迁移
用临时容器打包卷内容:
# 先正常停止所有写入者,再做冷备;确认数据库正常退出而非超时被强杀
docker stop mysql
docker run --rm -v mysqldata:/data:ro -v "$(pwd)":/backup \
alpine tar -czf /backup/mysqldata.tar.gz -C /data .
# 恢复到一个全新的空卷,完成验证后再启用
# 先确认 mysqldata-restored 尚不存在,避免复用已有卷
docker volume create mysqldata-restored
docker run --rm -v mysqldata-restored:/data -v "$(pwd)":/backup:ro \
alpine sh -c "cd /data && tar -xzf /backup/mysqldata.tar.gz"
数据库类数据建议用其自身工具备份(mysqldump/pg_dump),卷打包只适合停机冷备。
清理
docker volume ls -f dangling=true # 看无主卷
docker volume prune # 当前默认清理未使用匿名卷;-a 才包括命名卷,按版本核对
常见问题(FAQ)
Q:容器删了卷还在吗?
A:通常保留,但 volume rm、prune、compose down -v 等可删除卷;匿名卷还受容器 --rm/-v 影响。卷位于 daemon 侧,Desktop 通常在虚拟机内,远程卷驱动则由对应存储负责。
Q:卷能挂给多个容器吗?
A:可以,多个容器共享同一卷;但数据库类应用多数不支持多实例同时写同一数据目录,共享前确认应用语义。
Q:compose 里怎么定义卷?
A:顶层 volumes: 声明,服务里 - 卷名:/路径 引用;compose 会自动加项目名前缀。