根本原因是容器可写层随生命周期销毁,必须用命名卷挂载至/var/lib/mysql并严格验证路径、权限与数据跨容器存活。匿名卷或绑定挂载易导致数据隔离或写入失败,命名卷由docker统一管理,生命周期独立,确保持久化。

根本原因不是“重启导致丢数据”,而是容器默认使用可写层(Copy-on-Write),所有写入都落在临时文件系统里,生命周期一结束就清空。真正要解决的,是把数据落到 Docker 管理的持久位置——关键在挂载方式、路径对齐、权限适配和闭环验证。
必须用命名卷,别碰匿名卷
写 -v /var/lib/mysql 或 -v $(pwd)/data:/var/lib/mysql 看似挂了,实际创建的是匿名卷或绑定挂载,每次 docker run 或 docker-compose down && up 都会生成新卷,旧数据彻底隔离。
- 提前创建命名卷:
docker volume create mysql-data - 启动时严格按
卷名:容器内路径格式挂载:docker run -v mysql-data:/var/lib/mysql ... - 验证是否生效:
docker volume inspect mysql-data查 Mountpoint;docker inspect 容器名 | jq '.[0].Mounts'确认 Destination 是/var/lib/mysql,Source 指向该命名卷
路径必须100%对准官方数据目录
MySQL 固定用 /var/lib/mysql,PostgreSQL 是 /var/lib/postgresql/data,Neo4j 是 /data——镜像写死,改不了。挂载错一个字符,数据就掉进可写层,重启即丢。
- 错误示例:
-v pgdata:/var/lib/postgresql(漏了/data) - 正确写法:
-v pgdata:/var/lib/postgresql/data - 进容器检查:
docker exec -it 容器名 ls -ld /var/lib/mysql,若显示drwx------ 1 mysql mysql且有文件(如ibdata1),说明挂载成功并已写入
权限问题常被忽略,尤其绑定挂载时
命名卷由 Docker 自动处理权限,安全省心;但若用 -v /host/path:/var/lib/mysql 这类绑定挂载,宿主机目录属主不匹配,MySQL 进程(UID=999)直接写失败,退回到临时层。
- 查容器内用户 ID:
docker exec 容器名 id -u mysql(通常为 999) - 修复权限:
sudo chown -R 999:999 /host/path - 生产环境强烈建议优先用命名卷,避免权限、跨平台兼容性、迁移失效等一连串坑
三步验证,确认数据真落地
别只看命令写了没,要验证数据是否跨容器存活。
- 启动容器后建库插数据:
docker exec 容器名 mysql -uroot -p -e "CREATE DATABASE test; INSERT INTO test.t VALUES(1);" - 停删重建容器(不删卷):
docker stop 容器名 && docker rm 容器名 && docker run -d --name 容器名 -v mysql-data:/var/lib/mysql ... - 进新容器查数据:
docker exec 容器名 mysql -uroot -p -e "SHOW DATABASES; SELECT * FROM test.t;",能查到即为成功











