sudo systemctl stop docker
sudo vi /etc/docker/daemon.json
{
"data-root": "/path/to/your/new/docker-data"
}
sudo rsync -aP /var/lib/docker/ /path/to/your/new/docker-data
sudo systemctl start docker
sudo rm -rf /var/lib/docker.old
| 对比维度 | 数据卷(Volumes) | 绑定挂载(Bind Mount) | tmpfs 内存挂载 |
|---|---|---|---|
| 持久化能力 | 完全持久化,容器删除数据保留 | 完全持久化,依赖宿主机目录 | 不持久化,容器销毁数据丢失 |
| 跨主机迁移 | 简单,不受宿主机路径约束 | 困难,强依赖宿主机指定路径 | 不支持迁移 |
| 权限管理 | Docker 自动管控,不易出错 | 需手动配置宿主机目录 UID/GID | 由内核自动管理 |
| 性能表现 | 中等 | 读写延迟最低 | 性能最高,是 SSD 的 10 倍以上 |
| 生产环境适配 | 首选方案 | 仅用于开发/特殊配置场景 | 仅用于临时敏感数据场景 |
容器内的用户(通常是 root 或 uid=1000)创建的文件,在宿主机上显示为 root 或奇怪的 UID,导致宿主机无法编辑;反过来,宿主机创建的文件,容器内进程(如 Nginx、MySQL)又没有权限读取。
# 假设宿主机用户 UID=1000, GID=1000
docker run --user 1000:1000 -v /host/data:/app/data my_image
注意: 使用id + 用户名可以查询用户名的UID和GID。
id anyfork
输出结果如下:
uid=1000(anyfork) gid=1000(anyfork) 组=1000(anyfork),10(wheel),995(docker)
当你把一个空的宿主机目录(Bind Mount)挂载到一个非空的容器目录时,容器目录里的原有文件会被“遮住”。容器看起来是空的,导致程序因找不到默认配置文件而启动失败。
docker run --rm my_image cat /app/conf/config.yaml > ./host/config.yaml
多个容器同时挂载同一个卷或宿主机目录进行写入,会导致数据错乱或文件锁冲突,数据库文件(如 SQLite、MySQL 的表空间)极易损坏。
# :ro只读挂载
docker run -v my_data:/data:ro my_reader
有人以为容器里的所有文件都在卷里,直接用 docker rm -f container 删了容器,结果发现数据没了。这是因为数据根本没放进卷里,而是写在了容器的“可写层”。
数据卷备份可通过临时容器挂载源卷和宿主机备份目录,直接打包数据实现快速迁移。利用 --rm 临时容器,同时挂载“源数据卷”和“宿主机备份目录”,然后执行 tar 打包。这个方法不仅不污染宿主机环境,而且能保证文件权限(UID/GID)被完整保留,非常适合跨机器迁移。
docker run --rm \
-v my_app_data:/source \ # 挂载源数据卷到容器的 /source
-v /host/backup:/backup \ # 挂载宿主机备份目录到容器的 /backup
alpine \
tar czf /backup/my_data_$(date +%Y%m%d).tar.gz -C /source .
docker run --rm \
-v my_new_app_data:/target \ # 挂载目标数据卷到容器的 /target
-v /host/backup:/backup \ # 挂载存放备份包的宿主机目录
alpine \
tar xzf /backup/my_data_20260708.tar.gz -C /target
虽然这个方案很经典,但有几个极易出错的细节需要特别注意:
如果你的 Docker 版本较新(20.10+)且数据卷需要频繁备份到远端,可以考虑使用 Docker Volume Plugins(如 Rclone 或 阿里云 OSS Volume 插件),它们支持直接将卷数据增量同步到云存储,不需要手动在宿主机保留 .tar 文件。