核心是验证数据是否真正落到持久位置:第一步查容器内目录是否真实挂载(如ls -ld /var/lib/mysql),第二步识别匿名卷陷阱(用docker volume ls --filter dangling=true自查),第三步检查绑定挂载权限与uid/gid匹配。
排查 docker 容器重启后数据丢失,核心不是查 mysql 或 redis 日志,而是验证“数据到底有没有真正落到持久位置”。90% 的问题出在挂载没生效、挂载错路径、或用了匿名卷。下面分三步直击关键点。
第一步:确认容器内数据目录是否真实挂载
别只看启动命令写了 -v,要进容器里验证:
- 执行 docker exec -it 容器名 ls -ld /var/lib/mysql(MySQL)或 /var/lib/postgresql/data(PostgreSQL)等官方默认路径——如果显示
drwxr-xr-x 1 root root,说明是空挂载点;正常应为drwx------ 1 mysql mysql或类似属主属组 - 再运行 docker exec -it 容器名 find /var/lib/mysql -maxdepth 1 -type d | wc -l:返回值大于 1 才表示目录里有子目录(如 ibdata1、mysql/ 等),返回 1 就是空的,挂载失败或卷为空
- 用 docker inspect 容器名 查
Mounts字段,重点核对:-
Destination 是否等于服务要求的路径(如 MySQL 必须是
/var/lib/mysql,少一个字符都不行) -
Source 是命名卷(如
/var/lib/docker/volumes/mysql-data/_data)还是宿主机绝对路径(如/opt/mysql-data)——若显示随机哈希名,就是匿名卷
-
Destination 是否等于服务要求的路径(如 MySQL 必须是
第二步:识别是不是“假持久化”:匿名卷陷阱
匿名卷是 Docker 自动创建的幽灵卷,每次 docker run 都新建一个,旧数据永远无法复用:
- 错误写法:
docker run -v /var/lib/mysql mysql:8.0→ 没给卷命名,Docker 自建匿名卷 - 正确写法:
docker run -v mysql-data:/var/lib/mysql mysql:8.0→ 卷名mysql-data可查、可备份、可复用 - 自查命令:
docker volume ls --filter dangling=true,如果输出一堆哈希名,说明长期误用,历史数据已散落各处
第三步:检查权限与初始化行为
即使挂载路径对了,权限不对也会让服务退回到临时可写层:
- 绑定挂载(
-v /host/path:/var/lib/mysql)时,宿主机目录必须适配容器内用户 UID/GID。例如 MySQL 官方镜像用mysql用户(UID=999),需执行:sudo chown -R 999:999 /host/path && sudo chmod -R 700 /host/path - RabbitMQ 类服务还需固定
hostname,否则数据目录名随容器 ID 变更,导致找不到旧数据(如配置hostname: mqbroker-aaa) - 启动日志中留意
InnoDB: Unable to lock ./ibdata1(多容器争抢同一卷)、corrupt或crash recovery,这些提示文件系统损坏,常因强制 kill 或断电引起
验证是否真正持久化,最可靠方法是:写入测试数据 → 删除并重建容器(不删卷)→ 进新容器查原数据是否存在。只要这一步通了,就不是配置问题,而是操作流程问题。











