深色模式
容器存储 volume 与数据持久化
摘要:容器文件系统随容器删除而消失,数据必须落到 volume。本文对比 bind mount 与 named volume 的用法与取舍,演示数据卷的创建、共享、备份迁移,以及最常见的权限问题处理。
适用环境
- Linux 主机 + Docker Engine
- 示例镜像:
mysql:8、busybox - 数据盘建议独立于系统盘(如
/data)
操作步骤
一、三种挂载方式对比
| 方式 | 命令形式 | 数据位置 | 适用 |
|---|---|---|---|
| named volume | -v mydata:/var/lib/mysql | /var/lib/docker/volumes/ 由 Docker 管理 | 生产首选 |
| bind mount | -v /data/mysql:/var/lib/mysql | 宿主任意路径 | 需直接编辑文件、挂配置 |
| tmpfs | --tmpfs /tmp | 内存 | 敏感临时数据 |
二、named volume 基本操作
bash
docker volume create app-data
docker volume ls
docker volume inspect app-data # 看 Mountpoint 真实路径
docker run -d --name db \
-v app-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=ExamplePass123 \
mysql:81
2
3
4
5
6
7
2
3
4
5
6
7
即使 docker rm -f db,app-data 里的数据依然在,新容器再挂上就能读回。
三、bind mount 挂载配置文件
bash
mkdir -p /data/nginx/conf
docker run -d --name web \
-v /data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-p 8080:80 nginx:alpine1
2
3
4
2
3
4
:ro 表示只读挂载,防止容器内进程篡改宿主配置。
注意
bind mount 会覆盖容器内的目标路径。若容器内该目录原有初始化文件(如 /etc/nginx/conf.d),挂载后会变空,导致服务起不来。建议先 docker cp 一份出来作为初始内容。
四、多容器共享数据卷
bash
docker run -d --name writer -v app-data:/data busybox sh -c 'echo hi > /data/a.txt; sleep 3600'
docker run --rm -v app-data:/data busybox cat /data/a.txt1
2
2
五、备份与迁移
备份(用临时容器打包):
bash
docker run --rm \
-v app-data:/source:ro \
-v /data/backup:/backup \
busybox tar czf /backup/app-data-$(date +%F).tar.gz -C /source .1
2
3
4
2
3
4
恢复到一个新卷:
bash
docker volume create app-data-new
docker run --rm \
-v app-data-new:/target \
-v /data/backup:/backup:ro \
busybox tar xzf /backup/app-data-2026-10-09.tar.gz -C /target1
2
3
4
5
2
3
4
5
六、权限问题处理
容器内进程以非 root 运行时常遇到 Permission denied:
bash
# 查看镜像声明的运行 UID
docker inspect mysql:8 --format '{{.Config.User}}'
# 修正宿主目录属主(以 MySQL 的 999 为例)
sudo chown -R 999:999 /data/mysql1
2
3
4
2
3
4
危险
不要用 chmod -R 777 解决权限问题。这会把数据暴露给宿主机上任何进程,属于严重安全隐患。正确做法是 chown 到容器实际运行的 UID。
七、清理无用卷
bash
docker volume ls -f dangling=true
docker volume prune1
2
2
验证
- [ ]
docker volume inspect app-data能看到数据文件确实落在 Mountpoint - [ ] 删除并重建容器后,数据仍在
- [ ] 备份的 tar.gz 能正常解压出内容
常见坑
- 容器删了数据也没了:误用了容器自身可写层而非 volume,务必在
docker run时显式挂载。 - 挂载后目录变空导致服务启动失败:bind mount 覆盖了原有初始化文件,见上文注意事项。
- SELinux 环境报 Permission denied:AlmaLinux/Rocky 开启 SELinux 时需在挂载后加
:z或:Z后缀重标上下文,如-v /data/mysql:/var/lib/mysql:z。 - 磁盘悄悄被占满:
docker volume prune只清无用卷,已用卷需人工评估后删除。