数据卷(Volumes)
嘿!长安来了!今天咱们聊聊Docker的数据持久化——数据卷!这个很重要,不然你的数据容器一删就没了😱
🤔 为什么需要数据卷?
问题场景
# 运行一个MySQL容器
docker run -d --name mysql mysql:8.0
# 使用了一段时间,存了很多数据...
# 不小心删除容器
docker rm -f mysql
# 💥 完蛋!数据全没了!
容器本来就是临时的,删了就没了。但数据不能丢啊!
解决方案:数据卷
# 使用数据卷
docker run -d \
--name mysql \
-v mysql-data:/var/lib/mysql \
mysql:8.0
# 删除容器
docker rm -f mysql
# 数据还在!重新运行
docker run -d \
--name mysql \
-v mysql-data:/var/lib/mysql \
mysql:8.0
# ✅ 数据完好无损!
📦 数据卷的三种类型
Docker有三种数据持久化方式:
1. Volume(数据卷)- 推荐!
docker run -v volume-name:/path/in/container my-image
特点:
- 由Docker管理,存储在
/var/lib/docker/volumes/ - 最安全,最推荐
- 可以在多个容器间共享
- 可以用Docker命令管理
2. Bind Mount(绑定挂载)
docker run -v /path/on/host:/path/in/container my-image
特点:
- 直接挂载宿主机目录
- 路径必须是绝对路径
- 宿主机和容器都可以修改文件
- 适合开发环境
3. tmpfs Mount(临时文件系统)
docker run --tmpfs /path/in/container my-image
特点:
- 存储在内存中
- 容器停止后数据消失
- 适合存储敏感临时数据
三种方式对比
| 特性 | Volume | Bind Mount | tmpfs |
|---|---|---|---|
| 数据位置 | Docker管理 | 宿主机任意位置 | 内存 |
| 性能 | 高 | 一般 | 最高 |
| 持久化 | ✅ | ✅ | ❌ |
| 易用性 | 高 | 一般 | 高 |
| 推荐场景 | 生产环境 | 开发环境 | 临时数据 |
💡 长安建议:生产环境用Volume,开发环境用Bind Mount
📚 Volume(数据卷)详解
创建数据卷
# 创建数据卷
docker volume create my-volume
# 查看所有数据卷
docker volume ls
# 查看数据卷详情
docker volume inspect my-volume
输出:
[
{
"CreatedAt": "2024-12-01T10:00:00Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-volume/_data",
"Name": "my-volume",
"Options": {},
"Scope": "local"
}
]
使用数据卷
# 使用已存在的数据卷
docker run -d \
--name web \
-v my-volume:/data \
nginx
# 自动创建数据卷(如果不存在)
docker run -d \
--name web \
-v new-volume:/data \
nginx
删除数据卷
# 删除指定数据卷
docker volume rm my-volume
# 删除所有未使用的数据卷
docker volume prune
# 强制删除
docker volume rm -f my-volume
🔗 Bind Mount(绑定挂载)详解
基本用法
# 挂载目录
docker run -v /path/on/host:/path/in/container my-image
# 只读挂载
docker run -v /path/on/host:/path/in/container:ro my-image
# 使用$(pwd)挂载当前目录
docker run -v $(pwd):/app my-image
实战案例:开发环境
# 挂载代码目录,修改代码立即生效
docker run -d \
--name dev-web \
-p 8080:80 \
-v $(pwd)/html:/usr/share/nginx/html \
nginx
# 修改本地文件
echo "Hello from 长安!" > html/index.html
# 刷新浏览器,立即看到变化!
太方便了! 适合开发调试。
🎯 实战案例
案例1:MySQL数据持久化
# 创建数据卷
docker volume create mysql-data
# 运行MySQL
docker run -d \
--name mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-v mysql-data:/var/lib/mysql \
-p 3306:3306 \
mysql:8.0
# 创建数据库和表
docker exec -it mysql mysql -uroot -p123456 -e "
CREATE DATABASE testdb;
USE testdb;
CREATE TABLE users (id INT, name VARCHAR(50));
INSERT INTO users VALUES (1, '长安');
"
# 删除容器
docker rm -f mysql
# 重新运行(使用同一个数据卷)
docker run -d \
--name mysql-new \
-e MYSQL_ROOT_PASSWORD=123456 \
-v mysql-data:/var/lib/mysql \
-p 3306:3306 \
mysql:8.0
# 验证数据还在
docker exec -it mysql-new mysql -uroot -p123456 -e "
USE testdb;
SELECT * FROM users;
"
# 输出:
# +------+--------+
# | id | name |
# +------+--------+
# | 1 | 长安 |
# +------+--------+
# ✅ 数据完好!
案例2:Nginx配置和日志
# 创建数据卷
docker volume create nginx-conf
docker volume create nginx-logs
# 运行nginx
docker run -d \
--name web \
-p 80:80 \
-v nginx-conf:/etc/nginx \
-v nginx-logs:/var/log/nginx \
nginx
# 查看配置
docker exec web cat /etc/nginx/nginx.conf
# 查看访问日志
docker exec web tail -f /var/log/nginx/access.log
案例3:多容器共享数据
# 创建共享数据卷
docker volume create shared-data
# 容器1:写数据
docker run --rm \
-v shared-data:/data \
alpine \
sh -c "echo '长安在此' > /data/message.txt"
# 容器2:读数据
docker run --rm \
-v shared-data:/data \
alpine \
cat /data/message.txt
# 输出:长安在此
案例4:备份和恢复
备份数据卷:
# 备份mysql-data数据卷
docker run --rm \
-v mysql-data:/data \
-v $(pwd):/backup \
alpine \
tar -czf /backup/mysql-backup.tar.gz -C /data .
# 生成文件:mysql-backup.tar.gz
恢复数据卷:
# 创建新数据卷
docker volume create mysql-data-restored
# 恢复数据
docker run --rm \
-v mysql-data-restored:/data \
-v $(pwd):/backup \
alpine \
sh -c "cd /data && tar -xzf /backup/mysql-backup.tar.gz"
# 使用恢复的数据卷
docker run -d \
--name mysql-restored \
-v mysql-data-restored:/var/lib/mysql \
mysql:8.0
🎨 Dockerfile中的VOLUME
在Dockerfile中声明数据卷
FROM nginx
VOLUME /var/log/nginx
VOLUME /usr/share/nginx/html
效果:
docker run -d --name web nginx
docker inspect web | grep -A 10 Mounts
会看到自动创建了匿名数据卷。
匿名数据卷
# 不指定名字,Docker会自动生成
docker run -d -v /data nginx
# 查看
docker volume ls
# 输出类似:
# DRIVER VOLUME NAME
# local abc123def456...
问题:名字不友好,难以管理
💡 长安建议:总是使用命名数据卷!
💡 数据卷最佳实践
1. 使用命名数据卷
# ✅ 好
docker run -v mysql-data:/var/lib/mysql mysql
# ❌ 不好(匿名数据卷)
docker run -v /var/lib/mysql mysql
2. 数据卷命名规范
# 项目名-服务-data
myapp-mysql-data
myapp-redis-data
myapp-nginx-logs
# 清晰明了!
3. 定期备份
# 写个备份脚本
#!/bin/bash
DATE=$(date +%Y%m%d)
docker run --rm \
-v mysql-data:/data \
-v /backup:/backup \
alpine \
tar -czf /backup/mysql-$DATE.tar.gz -C /data .
4. 不要在数据卷中存储代码
# ❌ 不好
-v myapp-code:/app
# ✅ 好(代码应该打包在镜像里)
COPY . /app
数据卷是存数据的,不是存代码的!
5. 使用只读挂载(当适用时)
# 配置文件只读
docker run -v $(pwd)/config.json:/app/config.json:ro nginx
6. 清理未使用的数据卷
# 查看占用空间
docker system df -v
# 清理
docker volume prune
🔍 数据卷位置
Linux
/var/lib/docker/volumes/
查看:
sudo ls /var/lib/docker/volumes/
sudo ls /var/lib/docker/volumes/mysql-data/_data
Mac/Windows(Docker Desktop)
数据卷在虚拟机里,不能直接访问。
查看内容:
# 方法1:通过容器访问
docker run --rm -v mysql-data:/data alpine ls /data
# 方法2:进入Docker Desktop的虚拟机
docker run --rm -it --privileged --pid=host alpine \
nsenter -t 1 -m -u -n -i sh
# 然后
cd /var/lib/docker/volumes
📊 常用命令速查
# 数据卷管理
docker volume create <name> # 创建数据卷
docker volume ls # 列出数据卷
docker volume inspect <name> # 查看详情
docker volume rm <name> # 删除数据卷
docker volume prune # 清理未使用的数据卷
# 使用数据卷
docker run -v volume:/path # 命名数据卷
docker run -v /host:/container # 绑定挂载
docker run -v /host:/container:ro # 只读挂载
# 查看容器的数据卷
docker inspect <container> | grep -A 10 Mounts
# 备份数据卷
docker run --rm -v volume:/data -v $(pwd):/backup alpine \
tar -czf /backup/backup.tar.gz -C /data .
# 恢复数据卷
docker run --rm -v volume:/data -v $(pwd):/backup alpine \
sh -c "cd /data && tar -xzf /backup/backup.tar.gz"
💡 小结
今天长安教你搞定数据持久化:
核心概念
- 为什么需要:容器数据不持久
- 三种方式:Volume、Bind Mount、tmpfs
- 推荐用法:生产用Volume,开发用Bind Mount
- 命名规范:项目名-服务-用途
重要命令
docker volume create # 创建
docker volume ls # 列出
docker volume rm # 删除
docker volume prune # 清理
docker run -v # 使用数据卷
最佳实践
- 总是使用命名数据卷
- 定期备份重要数据
- 不要在数据卷中存储代码
- 适当使用只读挂载
- 定期清理未使用的数据卷
🚀 下一步
数据持久化搞定了!但容器之间怎么通信?下一章长安教你 Docker网络!
💬 长安的血泪教训:
有一次,我没用数据卷,直接在容器里跑了一个月的MySQL。
然后不小心执行了
docker rm -f mysql...一个月的数据,瞬间没了😭
老板问我数据呢?我说...容器删了...
那天我差点被开除。
从那以后,我发誓:重要数据一定用数据卷!
你们可千万别学我,记住了吗?💪
