Docker数据卷
🎯 学习目标
- 深入理解Docker数据持久化机制
- 掌握volumes、bind mounts和tmpfs的使用
- 学会数据备份、恢复和迁移
- 了解数据卷的性能优化和最佳实践
📚 数据持久化概述
1. 数据存储类型
javascript
// Docker数据存储类型
const dockerStorage = {
types: {
volumes: {
description: 'Docker管理的数据卷',
location: '/var/lib/docker/volumes/',
management: 'Docker完全管理',
features: ['跨平台兼容', '备份恢复简单', '驱动程序支持'],
use_cases: ['生产环境', '数据库存储', '应用数据']
},
bind_mounts: {
description: '绑定挂载宿主机目录',
location: '宿主机文件系统任意位置',
management: '用户管理',
features: ['高性能', '直接访问', '实时同步'],
use_cases: ['开发环境', '配置文件', '日志目录']
},
tmpfs: {
description: '临时文件系统',
location: '内存中',
management: '系统管理',
features: ['高速访问', '安全性好', '重启清空'],
use_cases: ['临时数据', '缓存文件', '敏感信息']
}
},
characteristics: {
persistence: 'volumes > bind_mounts > tmpfs',
performance: 'tmpfs > bind_mounts > volumes',
security: 'volumes > tmpfs > bind_mounts',
portability: 'volumes > bind_mounts > tmpfs'
}
};
console.log('Docker存储类型:', dockerStorage);
2. 存储驱动和文件系统
bash
# 查看存储驱动信息
docker info | grep -A 10 "Storage Driver"
# 常见存储驱动
# overlay2 - 推荐的存储驱动
# aufs - 旧版Ubuntu默认
# devicemapper - CentOS/RHEL默认
# btrfs - SUSE默认
# zfs - 支持高级特性
# 查看文件系统使用情况
docker system df
docker system df -v # 详细信息
💾 Docker Volumes详解
1. 卷的基本操作
bash
# 创建数据卷
docker volume create my-volume
docker volume create --driver local my-local-volume
# 查看数据卷列表
docker volume ls
docker volume ls --filter dangling=true # 未使用的卷
# 查看卷详细信息
docker volume inspect my-volume
# 删除数据卷
docker volume rm my-volume
docker volume prune # 删除未使用的卷
# 删除所有未使用的卷
docker volume prune -f
2. 使用数据卷
bash
# 创建并使用数据卷
docker run -d --name web-server \
-v my-volume:/usr/share/nginx/html \
nginx:alpine
# 使用匿名卷
docker run -d --name app \
-v /app/data \
myapp:latest
# 使用命名卷与选项
docker run -d --name database \
-v db-data:/var/lib/postgresql/data:z \
postgres:13
# 使用多个数据卷
docker run -d --name complex-app \
-v app-data:/app/data \
-v app-logs:/app/logs \
-v app-config:/app/config:ro \
myapp:latest
3. 高级卷配置
bash
# 创建带标签的数据卷
docker volume create \
--label environment=production \
--label project=myapp \
prod-data
# 创建NFS数据卷
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/path/to/dir \
nfs-volume
# 创建CIFS/SMB数据卷
docker volume create \
--driver local \
--opt type=cifs \
--opt o=username=user,password=pass \
--opt device=//server/share \
cifs-volume
🔗 Bind Mounts详解
1. 基本绑定挂载
bash
# 绑定挂载目录
docker run -d --name web \
-v /host/path:/container/path \
nginx:alpine
# 绑定挂载文件
docker run -d --name app \
-v /host/config.yml:/app/config.yml:ro \
myapp:latest
# 使用绝对路径
docker run -d --name dev-env \
-v $(pwd):/workspace \
-w /workspace \
node:16-alpine
# 绑定挂载多个目录
docker run -d --name full-stack \
-v /host/src:/app/src \
-v /host/public:/app/public \
-v /host/config:/app/config:ro \
fullstack:latest
2. 挂载选项
bash
# 只读挂载
docker run -v /host/data:/app/data:ro nginx:alpine
# 读写挂载(默认)
docker run -v /host/data:/app/data:rw nginx:alpine
# SELinux标签
docker run -v /host/data:/app/data:z nginx:alpine # 私有标签
docker run -v /host/data:/app/data:Z nginx:alpine # 共享标签
# 绑定传播选项
docker run -v /host/data:/app/data:shared nginx:alpine # 共享传播
docker run -v /host/data:/app/data:slave nginx:alpine # 从属传播
docker run -v /host/data:/app/data:private nginx:alpine # 私有传播
# 一致性选项(macOS)
docker run -v /host/data:/app/data:cached nginx:alpine # 宿主机优先
docker run -v /host/data:/app/data:delegated nginx:alpine # 容器优先
docker run -v /host/data:/app/data:consistent nginx:alpine # 强一致性
3. 开发环境实例
bash
# Node.js开发环境
docker run -it --rm \
--name node-dev \
-v $(pwd):/app \
-v /app/node_modules \
-w /app \
-p 3000:3000 \
node:16-alpine \
npm run dev
# Python开发环境
docker run -it --rm \
--name python-dev \
-v $(pwd):/app \
-v python-packages:/usr/local/lib/python3.9/site-packages \
-w /app \
-p 8000:8000 \
python:3.9-slim \
python app.py
# 数据库开发环境
docker run -d \
--name dev-postgres \
-v $(pwd)/data:/var/lib/postgresql/data \
-v $(pwd)/init.sql:/docker-entrypoint-initdb.d/init.sql:ro \
-e POSTGRES_PASSWORD=dev123 \
-p 5432:5432 \
postgres:13
💨 tmpfs挂载
1. 临时文件系统用法
bash
# 基本tmpfs挂载
docker run -d --name app \
--tmpfs /tmp \
nginx:alpine
# 带选项的tmpfs挂载
docker run -d --name secure-app \
--tmpfs /tmp:rw,noexec,nosuid,size=1g \
myapp:latest
# 使用--mount语法
docker run -d --name app \
--mount type=tmpfs,destination=/tmp,tmpfs-size=512m \
nginx:alpine
# 多个tmpfs挂载
docker run -d --name app \
--tmpfs /tmp:size=512m \
--tmpfs /var/cache:size=256m,noexec \
myapp:latest
2. 性能敏感应用
bash
# 数据库临时文件
docker run -d --name mysql-fast \
-v mysql-data:/var/lib/mysql \
--tmpfs /tmp:size=1g \
--tmpfs /var/lib/mysql-tmp:size=2g \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:8.0
# 缓存应用
docker run -d --name redis-cache \
--tmpfs /data:size=2g,noexec \
redis:alpine redis-server --save ""
# 编译环境
docker run --rm \
-v $(pwd):/src \
--tmpfs /tmp:size=4g \
-w /src \
gcc:latest \
make -j$(nproc)
🛠️ 实际应用场景
1. 数据库数据管理
bash
# PostgreSQL数据管理
docker run -d --name postgres-prod \
-v postgres-data:/var/lib/postgresql/data \
-v postgres-logs:/var/log/postgresql \
-v $(pwd)/postgresql.conf:/etc/postgresql/postgresql.conf:ro \
-e POSTGRES_PASSWORD=secret \
-p 5432:5432 \
postgres:13
# MySQL数据管理
docker run -d --name mysql-prod \
-v mysql-data:/var/lib/mysql \
-v mysql-logs:/var/log/mysql \
-v $(pwd)/my.cnf:/etc/mysql/my.cnf:ro \
--tmpfs /tmp:size=1g \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:8.0
# MongoDB数据管理
docker run -d --name mongo-prod \
-v mongo-data:/data/db \
-v mongo-configdb:/data/configdb \
-v $(pwd)/mongod.conf:/etc/mongod.conf:ro \
-p 27017:27017 \
mongo:5.0 mongod --config /etc/mongod.conf
2. 应用数据分离
bash
# Web应用数据分离
docker network create app-network
# 数据库层
docker run -d --name database \
--network app-network \
-v db-data:/var/lib/postgresql/data \
-e POSTGRES_DB=myapp \
-e POSTGRES_USER=appuser \
-e POSTGRES_PASSWORD=secret \
postgres:13
# 文件存储层
docker run -d --name file-storage \
--network app-network \
-v uploads:/app/uploads \
-v static-files:/app/static \
file-server:latest
# 应用层
docker run -d --name app-server \
--network app-network \
-v app-logs:/app/logs \
-v app-config:/app/config:ro \
-p 3000:3000 \
myapp:latest
# 反向代理层
docker run -d --name nginx-proxy \
--network app-network \
-v nginx-logs:/var/log/nginx \
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \
-p 80:80 \
nginx:alpine
3. 开发环境完整配置
bash
#!/bin/bash
# setup-dev-environment.sh
# 创建开发网络
docker network create dev-network
# 创建开发数据卷
docker volume create dev-postgres-data
docker volume create dev-redis-data
docker volume create dev-uploads
# 启动PostgreSQL
docker run -d --name dev-postgres \
--network dev-network \
-v dev-postgres-data:/var/lib/postgresql/data \
-v $(pwd)/dev-init.sql:/docker-entrypoint-initdb.d/init.sql:ro \
-e POSTGRES_DB=devdb \
-e POSTGRES_USER=dev \
-e POSTGRES_PASSWORD=dev123 \
-p 5432:5432 \
postgres:13
# 启动Redis
docker run -d --name dev-redis \
--network dev-network \
-v dev-redis-data:/data \
-p 6379:6379 \
redis:alpine
# 启动应用(开发模式)
docker run -d --name dev-app \
--network dev-network \
-v $(pwd):/app \
-v /app/node_modules \
-v dev-uploads:/app/uploads \
-w /app \
-p 3000:3000 \
-e NODE_ENV=development \
-e DATABASE_URL=postgresql://dev:dev123@dev-postgres:5432/devdb \
-e REDIS_URL=redis://dev-redis:6379 \
node:16-alpine \
npm run dev
echo "Development environment ready!"
echo "App: http://localhost:3000"
echo "Database: postgresql://dev:dev123@localhost:5432/devdb"
echo "Redis: redis://localhost:6379"
💾 数据备份和恢复
1. 数据卷备份
bash
# 备份数据卷到tar文件
docker run --rm \
-v source-volume:/source:ro \
-v $(pwd):/backup \
alpine \
tar czf /backup/volume-backup-$(date +%Y%m%d-%H%M%S).tar.gz -C /source .
# 备份脚本
#!/bin/bash
# backup-volume.sh
VOLUME_NAME=$1
BACKUP_DIR=${2:-./backups}
if [ -z "$VOLUME_NAME" ]; then
echo "Usage: $0 <volume-name> [backup-dir]"
exit 1
fi
# 创建备份目录
mkdir -p $BACKUP_DIR
# 生成备份文件名
BACKUP_FILE="$BACKUP_DIR/${VOLUME_NAME}-$(date +%Y%m%d-%H%M%S).tar.gz"
# 执行备份
docker run --rm \
-v $VOLUME_NAME:/source:ro \
-v $(pwd)/$BACKUP_DIR:/backup \
alpine \
tar czf /backup/$(basename $BACKUP_FILE) -C /source .
echo "Backup created: $BACKUP_FILE"
2. 数据卷恢复
bash
# 从备份恢复数据卷
docker run --rm \
-v target-volume:/target \
-v $(pwd):/backup \
alpine \
tar xzf /backup/volume-backup.tar.gz -C /target
# 恢复脚本
#!/bin/bash
# restore-volume.sh
BACKUP_FILE=$1
VOLUME_NAME=$2
if [ -z "$BACKUP_FILE" ] || [ -z "$VOLUME_NAME" ]; then
echo "Usage: $0 <backup-file> <volume-name>"
exit 1
fi
# 创建新数据卷(如果不存在)
docker volume create $VOLUME_NAME
# 执行恢复
docker run --rm \
-v $VOLUME_NAME:/target \
-v $(pwd):/backup \
alpine \
tar xzf /backup/$BACKUP_FILE -C /target
echo "Volume $VOLUME_NAME restored from $BACKUP_FILE"
3. 在线备份数据库
bash
# PostgreSQL在线备份
docker exec postgres-container \
pg_dump -U username dbname > backup.sql
# 恢复PostgreSQL
docker exec -i postgres-container \
psql -U username dbname < backup.sql
# MySQL在线备份
docker exec mysql-container \
mysqldump -u root -p dbname > backup.sql
# 恢复MySQL
docker exec -i mysql-container \
mysql -u root -p dbname < backup.sql
# MongoDB备份
docker exec mongo-container \
mongodump --db dbname --out /backup
# 恢复MongoDB
docker exec mongo-container \
mongorestore /backup/dbname
📊 数据卷监控和管理
1. 数据卷监控脚本
bash
#!/bin/bash
# volume-monitor.sh
echo "Docker数据卷监控报告 - $(date)"
echo "=================================="
echo ""
echo "📊 数据卷统计:"
docker system df -v
echo ""
echo "📋 数据卷列表:"
docker volume ls --format "table {{.Name}}\t{{.Driver}}\t{{.Scope}}"
echo ""
echo "💾 数据卷详情:"
for volume in $(docker volume ls -q); do
echo "卷名: $volume"
size=$(docker run --rm -v $volume:/data alpine du -sh /data 2>/dev/null | cut -f1)
echo " 大小: ${size:-未知}"
containers=$(docker ps -a --filter volume=$volume --format "{{.Names}}" | tr '\n' ' ')
echo " 使用容器: ${containers:-无}"
created=$(docker volume inspect $volume --format "{{.CreatedAt}}" 2>/dev/null)
echo " 创建时间: ${created:-未知}"
echo ""
done
echo "⚠️ 未使用的数据卷:"
unused=$(docker volume ls --filter dangling=true -q)
if [ ! -z "$unused" ]; then
echo "$unused"
echo "使用 'docker volume prune' 清理"
else
echo "✅ 无未使用的数据卷"
fi
echo ""
echo "🔍 存储驱动信息:"
docker info | grep -A 5 "Storage Driver"
2. 自动清理脚本
bash
#!/bin/bash
# cleanup-volumes.sh
echo "🧹 Docker数据卷清理工具"
echo "========================"
# 显示当前使用情况
echo "清理前状态:"
docker system df
echo ""
echo "🔍 查找未使用的数据卷..."
unused_volumes=$(docker volume ls --filter dangling=true -q)
if [ -z "$unused_volumes" ]; then
echo "✅ 没有发现未使用的数据卷"
else
echo "发现以下未使用的数据卷:"
for volume in $unused_volumes; do
size=$(docker run --rm -v $volume:/data alpine du -sh /data 2>/dev/null | cut -f1)
echo " - $volume (${size:-未知大小})"
done
echo ""
read -p "是否删除这些数据卷? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
docker volume prune -f
echo "✅ 未使用的数据卷已清理"
else
echo "❌ 已取消清理操作"
fi
fi
echo ""
echo "清理后状态:"
docker system df
🚀 性能优化
1. 存储性能优化
bash
# 选择合适的存储驱动
# /etc/docker/daemon.json
{
"storage-driver": "overlay2",
"storage-opts": [
"overlay2.override_kernel_check=true"
]
}
# 优化数据卷性能
docker run -d --name high-perf-db \
-v fast-storage:/var/lib/postgresql/data \
--mount type=tmpfs,destination=/tmp,tmpfs-size=2g \
--shm-size=1g \
postgres:13
# 使用本地SSD存储
docker volume create \
--driver local \
--opt type=none \
--opt o=bind \
--opt device=/mnt/ssd/docker-volumes/db-data \
ssd-volume
2. I/O性能调优
bash
# 调整容器I/O权重
docker run -d --name io-intensive \
-v data-volume:/app/data \
--blkio-weight 500 \
--device-read-bps /dev/sda:50mb \
--device-write-bps /dev/sda:50mb \
myapp:latest
# 使用直接I/O
docker run -d --name database \
-v db-data:/var/lib/mysql \
--mount type=volume,source=db-logs,target=/var/log/mysql,volume-opt=o=direct \
mysql:8.0
# 禁用同步写入(提高性能但降低安全性)
docker run -d --name fast-db \
-v db-data:/var/lib/postgresql/data \
-e POSTGRES_INITDB_ARGS="--data-checksums" \
postgres:13 \
-c fsync=off \
-c synchronous_commit=off
📋 最佳实践
1. 数据卷使用原则
bash
# ✅ 推荐做法
# 1. 生产环境使用命名卷
docker run -d -v app-data:/app/data myapp:latest
# 2. 开发环境使用绑定挂载
docker run -d -v $(pwd):/app myapp:dev
# 3. 临时数据使用tmpfs
docker run -d --tmpfs /tmp myapp:latest
# 4. 分离数据和应用
docker run -d \
-v app-data:/app/data \
-v app-logs:/app/logs \
-v app-config:/app/config:ro \
myapp:latest
# 5. 设置合适的权限
docker run -d \
-v app-data:/app/data:rw \
-v app-config:/app/config:ro \
--user 1000:1000 \
myapp:latest
2. 安全最佳实践
bash
# 只读挂载配置文件
docker run -d \
-v /host/config:/app/config:ro \
myapp:latest
# 使用非特权用户
docker run -d \
-v app-data:/app/data \
--user nobody:nogroup \
myapp:latest
# 限制挂载范围
docker run -d \
-v /host/app-data:/app/data:Z \
--security-opt label=type:container_file_t \
myapp:latest
3. 备份策略
bash
# 定期自动备份
#!/bin/bash
# cron-backup.sh (添加到crontab)
VOLUMES="app-data app-logs db-data"
BACKUP_DIR="/backup/docker-volumes"
RETENTION_DAYS=30
for volume in $VOLUMES; do
# 创建备份
backup_file="$BACKUP_DIR/${volume}-$(date +%Y%m%d-%H%M%S).tar.gz"
docker run --rm \
-v $volume:/source:ro \
-v $BACKUP_DIR:/backup \
alpine \
tar czf /backup/$(basename $backup_file) -C /source .
# 清理旧备份
find $BACKUP_DIR -name "${volume}-*.tar.gz" -mtime +$RETENTION_DAYS -delete
done
📝 下一步
现在您已经掌握了Docker数据管理,接下来学习:
- Docker Compose - 学习多容器编排
- Docker多阶段构建 - 掌握高级构建技巧
🎯 本章要点
- ✅ 理解Docker三种数据存储类型的特点
- ✅ 掌握数据卷的创建、使用和管理
- ✅ 学会数据备份、恢复和迁移策略
- ✅ 了解存储性能优化技巧
- ✅ 掌握数据管理的安全最佳实践
继续深入学习Docker多容器编排!🐳