Docker 容器数据持久化的正确姿势:卷、绑定挂载与实战对比
约 1 分钟· 672 字 92 次阅读
刚用 Docker 的人几乎都会踩同一个坑:容器删了,数据库和文件全没了。这篇讲清楚 Docker 数据持久化的两把钥匙——卷(volumes)和绑定挂载(bind mounts),以及生产环境怎么选。
为什么容器会丢数据
Docker 容器由「可写层」承载文件。容器删除时,可写层一并销毁。任何没写进挂载点的数据,都会随容器消失。
docker run -d --name test -e MYSQL_ROOT_PASSWORD=x mysql:8
docker rm -f test # 数据没了
两种持久化方式
1. 卷(Volumes)
由 Docker 管理,存在 /var/lib/docker/volumes/:
docker volume create blog-data
docker run -d -v blog-data:/app/data mysql:8
- ✅ 推荐优先用:备份简单、跨平台一致、
docker volume命令可管理 - ❌ 位置隐蔽,想直接编辑文件麻烦
2. 绑定挂载(Bind Mounts)
直接把宿主目录挂进容器:
docker run -d -v /opt/www/site:/app blog
- ✅ 目录可见可编辑,适合放代码和配置
- ❌ 依赖宿主路径,权限容易出问题(容器用户 vs 宿主用户)
实战:1Panel 部署博客的选型
最近把博客部署到 1Panel 管理的轻量服务器,数据持久化方案是这样定的:
docker run -d --name blog \
-v /opt/1panel/www/xlmg:/app \ # 绑定挂载:代码 + 内容 + 数据一体
-p 127.0.0.1:8080:3000 \
node:22-alpine
为什么用绑定挂载而不是卷?
- 代码要频繁更新——绑定挂载后,宿主机直接替换文件,容器重启即生效;
- 数据要和代码同目录——
content/(文章)和data/(留言)都在项目内,一个挂载点全搞定; - 1Panel 面板方便管理——面板里直接看文件、改配置。
但有个新坑:部署解压会覆盖内容。每次更新代码用 tar 解压时,content/ 里的文章可能被本地版本冲掉。解决方案是解压时排除数据目录:
tar -xzf release.tar.gz --strip-components=1 \
--exclude='content' --exclude='data'
权限问题怎么排查
绑定挂载最常见的报错是 EACCES(权限不足)。排查思路:
# 看容器用户
docker exec blog id
# 看宿主目录权限
ls -la /opt/www/site
# 权限不匹配时,要么改目录属主,要么让容器以 root 跑
chown -R 1000:1000 /opt/www/site
小结
| 场景 | 推荐 |
|---|---|
| 数据库、缓存等纯数据 | 卷(Volumes) |
| 代码 + 配置 + 数据混合 | 绑定挂载(Bind Mounts) |
| 容器重建后要保留数据 | 必须挂载,否则必丢 |
核心原则:容器是"无状态"的——一切需要保留的东西,都放到挂载点里。想清楚"删掉容器我会失去什么",就知道该挂载什么了。