Docker数据卷持久化,容器数据持久存储方案
容器删除后数据跟着消失,是新手用Docker部署数据库或网站时最常踩的坑。
Docker数据卷持久化就是解决这个问题的标准方案:把容器内需要保留的目录映射到宿主机磁盘,容器重建后数据依然存在。
下面按准备、操作、避坑、验证的顺序,用MySQL容器做完整演示,零基础也能照着执行。
先理解两种持久化方式
Docker官方推荐的数据持久化方式主要有两种:绑定挂载(bind mount)和命名卷(named volume)。
- 绑定挂载:把宿主机上你指定的目录,例如
/data/mysql,挂载到容器内的数据目录。路径完全由你控制,适合需要直接查看、备份或迁移数据的场景。 - 命名卷:由Docker管理,存储在
/var/lib/docker/volumes/下,你只需要给卷起个名字。适合不想关心宿主机路径、追求跨平台一致性的场景。
判断标准:需要直接操作宿主机文件就选绑定挂载,追求开箱即用就选命名卷。 两者都能实现容器数据持久存储,不存在谁绝对更好。
动手前的环境和检查项
开始前确认三件事:
- 已安装Docker,执行
docker version能看到Client和Server信息。 - 宿主机有足够磁盘空间,用
df -h查看目标分区剩余容量。 - 明确要持久化的容器内路径。以MySQL 8为例,数据目录通常是
/var/lib/mysql,配置文件在/etc/mysql/conf.d。
如果不确定容器内路径,可以先启动一个临时容器进去看:
docker run -it --rm mysql:8 bash
# 进入后执行 ls /var/lib/mysql 确认目录
用绑定挂载部署一个可持久化的MySQL
下面这套命令是本文核心,建议逐行执行。
创建宿主机目录:
mkdir -p /data/mysql/data /data/mysql/conf
启动容器,把两个目录分别挂载进去:
docker run -d \
--name mysql-persist \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=YourStrongPass123 \
-v /data/mysql/data:/var/lib/mysql \
-v /data/mysql/conf:/etc/mysql/conf.d \
mysql:8
关键参数说明:
-v /data/mysql/data:/var/lib/mysql:冒号左边是宿主机路径,右边是容器内路径,顺序不能反。-e MYSQL_ROOT_PASSWORD:首次启动会初始化数据库,这个密码只在数据目录为空时生效。--name mysql-persist:固定容器名,方便后续操作。
执行后确认容器状态:
docker ps --filter name=mysql-persist
看到状态为 Up 即启动成功。
验证数据是否真正持久化
光看容器运行不够,要实际验证数据能留存。
第一步,进入容器创建测试数据:
docker exec -it mysql-persist mysql -uroot -p
输入密码后执行:
CREATE DATABASE persist_test;
USE persist_test;
CREATE TABLE t1(id INT PRIMARY KEY, note VARCHAR(50));
INSERT INTO t1 VALUES (1, 'hello-volume');
EXIT;
第二步,删除容器再重建,模拟真实故障场景:
docker rm -f mysql-persist
docker run -d --name mysql-persist -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=YourStrongPass123 \
-v /data/mysql/data:/var/lib/mysql \
mysql:8
第三步,重新查询数据:
docker exec -it mysql-persist mysql -uroot -p -e "SELECT * FROM persist_test.t1;"
如果还能查到 hello-volume 这条记录,说明Docker数据卷持久化已经生效。容器可以随时删除重建,数据保存在宿主机目录里。
容易踩坑的几个地方
权限问题导致容器起不来。 MySQL容器内进程以mysql用户运行,如果宿主机目录权限过严,会报 Permission denied。
可先临时放宽:
chown -R 999:999 /data/mysql/data
999是MySQL镜像内mysql用户的常见UID,具体以镜像实际配置为准。
挂载路径写反。 宿主机路径在前、容器路径在后。
写反可能把宿主机目录覆盖成空目录,甚至影响系统文件。
初始化密码不生效。 如果宿主机目录里已有旧数据,MYSQL_ROOT_PASSWORD 不会重新设置。
要重置只能清空数据目录,操作前务必备份。
直接删容器不等于删数据。 docker rm 只删除容器层,绑定挂载的宿主机目录和命名卷默认会保留。
清理命名卷要用 docker volume rm,且确认不再需要。
备份与迁移建议
持久化之后,备份逻辑就简单了。
绑定挂载场景下,直接打包宿主机目录即可:
tar -czf /backup/mysql-$(date +%F).tar.gz /data/mysql/data
迁移到另一台服务器时,把压缩包传过去解压到相同路径,再用同样的 -v 参数启动容器,数据即可接续使用。
命名卷场景可以用 docker run --rm -v 卷名:/from -v $(pwd):/to alpine tar czf /to/backup.tar.gz -C /from . 导出。
无论用哪种方式,都建议定期做一次“删除容器再重建”的演练。能通过重建验证的数据持久化方案,才算真正可靠。
常见疑问
命名卷和绑定挂载到底选哪个?
需要自己用工具直接读写数据文件、做异地备份,选绑定挂载;
只想让容器数据不丢、不关心文件放哪,选命名卷。
生产环境两者都常见,关键是团队要统一约定,避免同一服务混用两种方式。
容器删除后数据还在,但为什么新容器读不到?
先检查 -v 参数是否和原来完全一致,路径大小写、末尾斜杠都可能有影响。
其次确认宿主机目录没有被其他程序改动权限或清空。
数据卷会占用大量磁盘吗?
会。
镜像层和卷数据分开计算,docker system df 可以查看卷占用。
长期运行建议监控宿主机磁盘,并定期清理无用卷。