存储与数据持久化
7.1 三种存储方式
| 方式 | 说明 | 持久性 | 性能 |
|---|
| Volume | Docker 管理的存储 | 容器删除后保留 | 好 |
| Bind Mount | 挂载宿主机目录 | 取决于宿主机 | 最好 |
| tmpfs | 内存临时存储 | 容器删除后丢失 | 最快 |
7.2 Volume 详解
创建与管理
# 创建命名卷
docker volume create mydata
# 列出所有卷
docker volume ls
# 卷详情
docker volume inspect mydata
# 查看存储位置
docker volume inspect mydata --format '{{.Mountpoint}}'
# 默认:/var/lib/docker/volumes/mydata/_data
# 删除卷
docker volume rm mydata
# 清理未使用卷
docker volume prune
使用 Volume
# 命名卷
docker run -d -v mydata:/var/lib/mysql --name db mysql
# 匿名卷(自动生成随机名)
docker run -d -v /var/lib/mysql --name db mysql
# 使用 --mount(更明确)
docker run -d \
--mount type=volume,source=mydata,target=/var/lib/mysql \
--name db mysql
# 多容器共享同一卷
docker run -d -v shared:/data --name writer \
alpine sh -c "while true; do date >> /data/log.txt; sleep 5; done"
docker run -it -v shared:/data --name reader \
alpine tail -f /data/log.txt
Volume 备份与恢复
# 备份 Volume 到宿主机
docker run --rm \
-v mydata:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/mydata-backup.tar.gz -C /source .
# 从备份恢复
docker run --rm \
-v mydata:/target \
-v $(pwd):/backup \
alpine tar xzf /backup/mydata-backup.tar.gz -C /target
# 迁移 Volume(从旧服务器到新服务器)
# 旧服务器
docker run --rm -v mydata:/data -v $(pwd):/backup \
alpine tar czf /backup/mydata.tar.gz -C /data .
# 传输文件到新服务器
scp mydata.tar.gz newserver:/path/
# 新服务器
docker volume create mydata
docker run --rm -v mydata:/data -v $(pwd):/backup \
alpine tar xzf /backup/mydata.tar.gz -C /data
7.3 Bind Mount 详解
基本用法
# 挂载当前目录
docker run -d -v $(pwd)/app:/app node:alpine node /app/server.js
# 使用 --mount
docker run -d \
--mount type=bind,source=$(pwd)/app,target=/app \
node:alpine node /app/server.js
# 只读挂载
docker run -d \
--mount type=bind,source=$(pwd)/config,target=/etc/nginx/nginx.conf,readonly \
nginx
# 开发环境常用:挂载代码目录 + 命令覆盖
docker run -it --rm \
-v $(pwd):/app \
-w /app \
node:alpine sh
权限问题
# 容器内用户 UID/GID 与宿主机不匹配
# 容器内 root (0:0) 写入的文件,宿主机可能显示为 root
# 解决:指定 UID/GID
docker run --user $(id -u):$(id -g) -v $(pwd):/app node:alpine
# 或在 Dockerfile 中创建匹配的用户
# RUN useradd -u 1000 appuser
# USER appuser
开发 vs 生产
# 开发环境:Bind Mount(代码实时同步)
docker run -it --rm -v $(pwd):/app -w /app node:alpine npm run dev
# 生产环境:COPY 到镜像中(不依赖宿主机)
# COPY . /app
# CMD ["node", "server.js"]
# 或使用 Volume 存储配置文件
7.4 tmpfs(内存存储)
# 临时文件存储在内存中
docker run -d \
--tmpfs /tmp:size=100m \
--tmpfs /var/log:size=50m \
alpine
# 使用 --mount
docker run -d \
--mount type=tmpfs,target=/tmp,tmpfs-size=100m \
alpine
# 适用场景:敏感数据、临时缓存、高频 I/O
7.5 数据持久化最佳实践
数据库容器
# MySQL + 持久化
docker run -d \
-e MYSQL_ROOT_PASSWORD=secret \
-v mysql_data:/var/lib/mysql \
-p 3306:3306 \
--restart unless-stopped \
mysql:8
# PostgreSQL + 持久化 + 初始化脚本
docker run -d \
-e POSTGRES_PASSWORD=secret \
-v pg_data:/var/lib/postgresql/data \
-v $(pwd)/init.sql:/docker-entrypoint-initdb.d/init.sql:ro \
-p 5432:5432 \
postgres:16-alpine
配置管理
# 配置文件用 Bind Mount(修改后重启容器生效)
docker run -d \
-v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \
-v $(pwd)/html:/usr/share/nginx/html:ro \
-p 80:80 \
nginx
# 敏感配置用 Docker Secret(Swarm 模式)
docker secret create db_password password.txt
docker service create --secret db_password mysql
存储驱动与性能
# 查看当前存储驱动
docker info | grep "Storage Driver"
# 推荐使用 overlay2
# /etc/docker/daemon.json
# {
# "storage-driver": "overlay2"
# }
# 重启 Docker 使配置生效
sudo systemctl restart docker
7.6 卷标签与过滤
# 创建带标签的卷
docker volume create --label env=dev --label project=myapp mydata
# 按标签过滤卷
docker volume ls --filter label=env=dev
docker volume ls --filter label=project=myapp
# 删除特定标签的卷
docker volume prune --filter label=env=dev
7.7 Docker Compose 中的存储
# docker-compose.yml
version: '3.8'
services:
db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: secret
volumes:
- mysql_data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
ports:
- "3306:3306"
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
command: redis-server --appendonly yes
nginx:
image: nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- static_files:/usr/share/nginx/html
ports:
- "80:80"
volumes:
mysql_data:
redis_data:
static_files:
# Compose 卷操作
docker-compose up -d
# 查看 Compose 创建的卷
docker volume ls --filter label=com.docker.compose.project=myapp
# 删除项目所有卷
docker-compose down -v
7.8 数据迁移策略
从主机迁移到容器
# 方法一:先复制到 Volume,再挂载
docker run --rm \
-v mydata:/data \
-v /host/path:/host-data \
alpine cp -r /host-data/* /data/
# 方法二:使用 tar 管道
tar czf - -C /host/path . | docker run --rm -i \
-v mydata:/data \
alpine tar xzf - -C /data
容器间数据迁移
# 将容器 A 的数据复制到容器 B
docker cp container_a:/app/data/. /tmp/transfer/
docker cp /tmp/transfer/. container_b:/app/data/
# 使用共享卷方式
docker run --rm \
-v source_data:/source:ro \
-v target_data:/target \
alpine sh -c "cp -r /source/* /target/"
7.9 常见问题排查
权限与所有权
# 查看容器内文件所有权
docker exec <container> ls -la /data
# 修复权限问题
docker run --rm \
-v mydata:/data \
alpine chown -R 1000:1000 /data
# 使用 --user 运行容器避免权限问题
docker run --user 1000:1000 -v mydata:/data alpine ls -la /data
磁盘空间管理
# 查看 Docker 磁盘使用详情
docker system df
# 查看各卷占用空间
docker system df -v
# 清理已停止容器的卷
docker volume prune
# 清理所有未使用资源
docker system prune --all --volumes
# 查看容器内大文件占用
docker exec <container> du -sh /* | sort -rh | head -10