Docker 存储:数据卷与绑定挂载
当你运行一个 Docker 容器时,容器内部的文件系统是临时的——一旦容器被删除,里面的所有数据都会消失。但很多应用(比如数据库、日志服务)必须持久保存数据。Docker 提供了两种主要方式来解决这个问题:数据卷(volumes)和绑定挂载(bind mounts)。它们都能让容器访问宿主机上的文件或目录,但使用场景和管理方式完全不同。
理解核心区别
数据卷是由 Docker 管理的存储单元,通常位于宿主机的 /var/lib/docker/volumes/ 目录下,但你不需要知道具体路径。Docker 会自动创建、命名和清理它。
绑定挂载则是直接将宿主机上你指定的任意目录或文件挂载到容器中。Docker 不管理这个路径,完全由你控制。
| 特性 | 数据卷(Volume) | 绑定挂载(Bind Mount) |
|---|---|---|
| 创建方式 | docker volume create 或运行容器时自动创建 |
手动指定宿主机路径 |
| 路径可见性 | 对用户隐藏(Docker 内部管理) | 完全可见且可自定义 |
| 可移植性 | 高(适合跨环境迁移) | 低(依赖宿主机具体路径) |
| 安全性 | 更高(避免意外覆盖系统文件) | 较低(可能误改宿主机关键文件) |
| 适用场景 | 数据库、配置文件、通用持久化 | 开发调试、共享代码、访问特定主机文件 |
使用数据卷(Volume)
数据卷是官方推荐的持久化存储方式,尤其适合生产环境。
1. 创建并命名一个数据卷
执行以下命令创建名为 my-db-data 的数据卷:
docker volume create my-db-data
2. 将数据卷挂载到容器
启动一个 MySQL 容器,并把 my-db-data 挂载到容器内的 /var/lib/mysql(MySQL 默认数据目录):
docker run -d \
--name mysql-container \
-e MYSQL_ROOT_PASSWORD=123456 \
-v my-db-data:/var/lib/mysql \
mysql:8.0
这里的 -v my-db-data:/var/lib/mysql 表示:将名为 my-db-data 的数据卷挂载到容器的 /var/lib/mysql 路径。
3. 查看数据卷信息
运行以下命令查看所有数据卷:
docker volume ls
查看某个数据卷的详细信息(包括在宿主机上的实际位置):
docker volume inspect my-db-data
输出中会包含 "Mountpoint" 字段,例如:"/var/lib/docker/volumes/my-db-data/_data"。这是数据实际存放的位置,但你不应手动修改它。
4. 删除数据卷
当容器不再需要该数据时,先删除容器,再删除数据卷:
docker rm -f mysql-container
docker volume rm my-db-data
注意:即使容器被删,数据卷默认不会自动删除,防止误删重要数据。
使用绑定挂载(Bind Mount)
绑定挂载适合开发场景,比如你正在写代码,希望容器能实时看到本地文件的修改。
1. 准备宿主机目录
创建一个本地目录用于测试:
mkdir -p /home/user/my-app
echo "Hello from host!" > /home/user/my-app/index.html
2. 启动容器并挂载该目录
运行一个 Nginx 容器,将本地 /home/user/my-app 目录挂载到容器的网页根目录 /usr/share/nginx/html:
docker run -d \
--name web-server \
-p 8080:80 \
-v /home/user/my-app:/usr/share/nginx/html \
nginx:alpine
现在访问 http://localhost:8080,你会看到 “Hello from host!”。
3. 实时修改验证
编辑宿主机上的文件:
echo "Updated content!" > /home/user/my-app/index.html
刷新浏览器,内容立即更新——因为容器直接读取的是你本地的文件。
4. 注意路径格式(Windows/macOS 用户)
- Linux:路径如
/home/user/app - macOS:路径如
/Users/yourname/app - Windows(PowerShell):使用绝对路径,如
C:\Users\yourname\app,但在命令中需写成/c/Users/yourname/app或使用双引号包裹:"C:\Users\yourname\app"
例如在 Windows PowerShell 中:
docker run -v "C:\my-app:/usr/share/nginx/html" nginx
如何选择?
-
选数据卷,如果你:
- 需要持久化数据库、缓存等应用数据
- 希望 Docker 自动管理存储生命周期
- 在多容器间共享数据(通过
--volumes-from) - 部署到不同机器时不想关心宿主机路径
-
选绑定挂载,如果你:
- 正在开发,需要实时同步代码变更
- 必须访问宿主机上的特定配置文件(如
/etc/hosts) - 要挂载设备文件(如
/dev/video0) - 明确知道路径且能保证所有部署环境一致
常见错误与避坑指南
-
路径不存在导致容器启动失败
绑定挂载时,如果宿主机路径不存在,Docker 不会报错,而是自动创建一个空目录。这可能导致你以为挂载成功,实则数据没生效。
解决:确保宿主机路径已存在,且权限正确。 -
Windows 路径权限问题
Docker Desktop 默认只允许挂载用户目录(如C:\Users)。若尝试挂载C:\Program Files,会失败。
解决:将项目放在用户目录下,或在 Docker Desktop 设置中添加额外的共享目录。 -
混淆卷名与路径
-v myvol:/app是数据卷,-v /host/path:/app是绑定挂载。前者myvol是名字,后者/host/path是绝对路径。
记住:开头是/或.的就是绑定挂载,否则是数据卷。 -
不要用绑定挂载替代数据卷做备份
虽然你可以直接复制/var/lib/docker/volumes/xxx/_data,但这不是官方支持的方式。
正确做法:使用docker run --rm -v myvol:/data -v $(pwd):/backup alpine tar czf /backup/data.tar.gz -C /data .进行备份。
高级技巧:匿名卷与只读挂载
匿名卷(Anonymous Volume)
在 Dockerfile 中声明卷,但不指定名字:
VOLUME ["/var/log/app"]
运行容器时,Docker 会自动创建一个随机命名的卷。适合临时日志存储,但难以追踪。
只读挂载
防止容器修改宿主机文件:
docker run -v /host/config:/app/config:ro nginx
末尾的 :ro 表示 read-only。容器内对 /app/config 的任何写操作都会失败。
停止容器后,数据是否保留,取决于你用的是哪种挂载方式。理解这一点,你就掌握了 Docker 持久化的核心逻辑。

暂无评论,快来抢沙发吧!