
Docker Storage
- 10 installs
- 2 repo stars
- Updated July 29, 2026
- full-statck-skills/docker-skills
Persist Docker container data using volumes, bind mounts, or tmpfs, with backup/restore and database persistence for PostgreSQL, MySQL, and Redis.
About
Guides Docker storage and data persistence across volumes, bind mounts, and tmpfs. A developer uses it to persist container data or set up database storage.
- Volume vs bind mount vs tmpfs comparison and use-case selection
- Volume lifecycle, backup/restore, and database persistence for PostgreSQL/MySQL/Redis
Docker Storage by the numbers
- 10 all-time installs (skills.sh)
- Ranked #1,007 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Jul 30, 2026 (Skillselion catalog sync)
npx skills add https://github.com/full-statck-skills/docker-skills --skill docker-storageAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 10 |
|---|---|
| repo stars | ★ 2 |
| Last updated | July 29, 2026 |
| Repository | full-statck-skills/docker-skills ↗ |
What it does
Persist Docker container data using volumes, bind mounts, or tmpfs, with backup/restore and database persistence for PostgreSQL, MySQL, and Redis.
Files
Docker Storage — 存储与数据持久化
Comprehensive guidance for managing persistent data in Docker.
When to Use
ALWAYS use this skill when the user mentions:
- "docker volume", "数据卷", "数据持久化"
- "bind mount", "tmpfs"
- "容器数据怎么保存", "数据不丢失"
- "数据库容器怎么持久化"
- "备份恢复", "存储驱动"
Storage Type Comparison
| Type | Persistence | Performance | Use Case |
|---|---|---|---|
| Volume | ✅ (managed by Docker) | High (native) | Production databases, shared data |
| Bind Mount | ✅ (host filesystem) | High | Development (live code sync), config files |
| Tmpfs | ❌ (memory only) | Highest | Secrets, temp files, sensitive data |
Visual Comparison
Volume: Bind Mount: Tmpfs:
Container Container Container
│ │ │
Docker-managed /host/path Memory only
/var/lib/docker/volumes/ ↕ (no disk)
↕ Container sees: ↕
Container sees: /container/path Container sees:
/data = host files /tmp (in RAM)Volume Management
# Create & inspect
docker volume create mydata
docker volume ls
docker volume inspect mydata
# Use in container
docker run -v mydata:/var/lib/mysql mysql:8
docker run --mount source=mydata,target=/var/lib/mysql mysql:8 # explicit syntax (recommended)
# Cleanup
docker volume prune # Remove unused volumes
docker volume rm mydata # Remove specific volumeNamed vs Anonymous Volumes
-v mydata:/data → Named volume (mydata) — survives container removal ✅
-v /data → Anonymous volume — hard to identify later ❌Bind Mount
# Read-write bind mount
docker run -v $(pwd)/app:/app nginx
# Read-only (protect host files)
docker run -v $(pwd)/config:/etc/nginx:ro nginx
# Explicit syntax
docker run --mount type=bind,source=$(pwd)/app,target=/app nginxTmpfs (Memory)
# Ephemeral data, never touches disk
docker run --tmpfs /tmp:rw,noexec,nosuid,size=64m nginx
docker run --mount type=tmpfs,destination=/tmp,tmpfs-size=64m nginxDatabase Persistence Patterns
PostgreSQL
docker volume create pgdata
docker run -d \
--name postgres \
-e POSTGRES_PASSWORD=secret \
-v pgdata:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:16-alpineMySQL
docker volume create mysqldata
docker run -d \
--name mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-v mysqldata:/var/lib/mysql \
-v $(pwd)/my.cnf:/etc/mysql/conf.d/my.cnf:ro \
-p 3306:3306 \
mysql:8.4Redis (Persistence)
docker volume create redisdata
docker run -d \
--name redis \
-v redisdata:/data \
-p 6379:6379 \
redis:7-alpine redis-server --appendonly yesBackup & Restore
# Backup (using a temporary container)
docker run --rm \
-v mysqldata:/source \
-v $(pwd):/backup \
alpine tar czf /backup/mysqldata-backup.tar.gz -C /source .
# Restore
docker run --rm \
-v mysqldata:/target \
-v $(pwd):/backup \
alpine tar xzf /backup/mysqldata-backup.tar.gz -C /targetStorage Drivers
| Driver | Status | Notes |
|---|---|---|
| overlay2 | ✅ Default | Best for most use cases; copy-on-write |
| devicemapper | Deprecated | - |
| aufs | Deprecated | - |
| btrfs/zfs | Niche | Use if filesystem matches |
docker info | grep "Storage Driver" # Check currentWorkflow — 推荐配置流程
Step 1: 确定存储类型: 持久化数据 → Volume;开发热加载 → Bind Mount;临时缓存 → tmpfs Step 2: 创建 Volume: docker volume create db_data Step 3: 挂载到容器: docker run -v db_data:/var/lib/mysql mysql Step 4: 验证: docker volume inspect db_data + docker exec mysql ls /var/lib/mysql Step 5: 备份: docker run --rm -v db_data:/source -v $(pwd):/backup alpine tar czf /backup/db.tar.gz -C /source .
Gotchas — Common Pitfalls
- Anonymous volumes accumulate: Every
-v /data(no name) creates a new anonymous volume. → Recovery:docker volume prunecleans all unused; use named volumes:-v mydata:/data. - Bind mount paths: Must be absolute. → Recovery:
-v $(pwd)/app:/appfor docker run;-v ./app:/appworks in Compose only. - Permission issues with bind mounts: Container UID != host UID → permission denied. → Recovery:
--user $(id -u):$(id -g)orRUN chown 1000:1000 /datain Dockerfile entrypoint. - Data loss on container removal: Without
-v, data is lost when container is removed.--rmflag even worse. → Recovery: Always use named volumes:docker run -v db_data:/var/lib/mysql. - macOS bind mount performance: Bind mounts on Docker Desktop Mac are slow. → Recovery: Use
:cachedor:delegatedmount options, or named volumes for better I/O.
Boundary — 能力边界(适用与不适用场景)
| 分类 | 场景 | 说明 |
|---|---|---|
| ✅ 能做 | 数据持久化配置(Volume/Bind Mount/tmpfs) | 三类存储的创建、挂载、管理 |
| ✅ 能做 | 备份与恢复 | tar + --volumes-from 备份恢复 |
| ✅ 能做 | 存储驱动选型 | overlay2/btrfs/zfs 对比 |
| ⚠️ 需条件 | NFS/云存储 Volume 驱动 | 需安装对应驱动插件 |
| ⚠️ 需条件 | macOS 下 Bind Mount 性能 | 使用 :cached/:delegated 或命名 Volume |
| ❌ 超范围 | K8s PersistentVolume/PVC | 使用 docker-production + K8s 文档 |
| ❌ 超范围 | 分布式文件系统(Ceph/GlusterFS) | 系统管理员范畴 |
| ❌ 超范围 | 数据库性能优化 | DBA 专业领域 |
When NOT to Use This Skill
| ❌ Skip | ✅ Use Instead |
|---|---|
| Running containers (no data concerns) | docker-run |
| Multi-container orchestration | docker-compose |
| Kubernetes Storage (PV/PVC) | K8s documentation |
| Docker basics | docker-basics |
Security & Stability
- Use
:rofor config files that containers should not modify. - Never bind mount Docker socket (
/var/run/docker.sock) without understanding the security implications. - Backup volumes regularly, especially database volumes.
- No executable scripts bundled. Guidance only.
📚 官方文档参考
| 文档 | 地址 |
|---|---|
| Docker 存储 | https://docs.docker.com/storage/ |
| Volumes | https://docs.docker.com/storage/volumes/ |
| Bind Mounts | https://docs.docker.com/storage/bind-mounts/ |
| tmpfs | https://docs.docker.com/storage/tmpfs/ |
| 存储驱动 | https://docs.docker.com/storage/storagedriver/ |
| docker volume 命令 | https://docs.docker.com/reference/cli/docker/volume/ |
🧭 Docker Skills Journey
📍 You are here: `docker-storage` — 数据持久化
← Previous: docker-run / docker-networking → Next: docker-compose / docker-security
FAQ
Q1: 如何快速上手此技能? A: 参考上方的快速开始章节,按步骤操作即可。
Q2: 遇到版本不兼容问题怎么办? A: 检查依赖版本,使用 lock 文件锁定,参考常见陷阱章节。
Q3: 如何在生产环境使用? A: 参考最佳实践章节,确保配置正确,做好监控和日志。
Q4: 性能如何优化? A: 参考性能优化相关文档,使用缓存、索引等手段。
Q5: 如何贡献或反馈问题? A: 在 GitHub 仓库提交 Issue 或 Pull Request。
Q6: 是否支持中文? A: 支持中文文档和中文注释,详见国内适配章节。
Using volumes to persist MySQL data
# 1. Create a named volume
docker volume create mysql-data
# 2. Run MySQL with the volume mounted
docker run -d --name mysql \
-e MYSQL_ROOT_PASSWORD=secret123 \
-v mysql-data:/var/lib/mysql \
-p 3306:3306 \
mysql:8.4
# 3. Verify data persists
docker exec mysql mysql -uroot -psecret123 -e "CREATE DATABASE testdb;"
docker stop mysql
docker rm mysql
docker run -d --name mysql-new -v mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=secret123 -p 3306:3306 mysql:8.4
docker exec mysql-new mysql -uroot -psecret123 -e "SHOW DATABASES;"
# testdb still exists! ✅Backup and restore a Docker volume
# === BACKUP ===
# Create a temporary alpine container that mounts:
# - the source volume at /source
# - the current directory at /backup
docker run --rm \
-v mysql-data:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/mysql-data-$(date +%Y%m%d).tar.gz -C /source .
# === RESTORE ===
# 1. Create a new (or ensure existing) volume
docker volume create mysql-data-restored
# 2. Restore from backup
docker run --rm \
-v mysql-data-restored:/target \
-v $(pwd):/backup \
alpine tar xzf /backup/mysql-data-20250101.tar.gz -C /target
# 3. Verify: start a container using the restored volume
docker run --rm -v mysql-data-restored:/var/lib/mysql alpine ls /var/lib/mysqlAutomate with a backup script
#!/bin/bash
# backup-volume.sh — Backup a Docker volume to a timestamped tar.gz
VOLUME=${1:?Usage: $0 <volume-name>}
BACKUP_DIR=${2:-./backups}
mkdir -p "$BACKUP_DIR"
docker run --rm \
-v "$VOLUME":/source:ro \
-v "$(cd "$BACKUP_DIR" && pwd)":/backup \
alpine tar czf "/backup/${VOLUME}-$(date +%Y%m%d-%H%M%S).tar.gz" -C /source .
echo "Backed up $VOLUME to $BACKUP_DIR"Volume types: when to use what
| Scenario | Type | Command |
|---|---|---|
| Database storage (PostgreSQL/MySQL) | Named Volume | -v pgdata:/var/lib/postgresql/data |
| Config files (nginx.conf) | Bind Mount (ro) | -v ./nginx.conf:/etc/nginx/nginx.conf:ro |
| Dev code sync (hot reload) | Bind Mount | -v $(pwd)/app:/app |
| Temp/sensitive data (never disk) | Tmpfs | --tmpfs /tmp:rw,size=64m |
| Logs (host access needed) | Bind Mount | -v ./logs:/var/log/app |
| Shared data across containers | Named Volume | -v shared:/shared |
Decision Flow
Does the data need to outlive the container?
├── NO → Tmpfs (RAM only, never touches disk)
└── YES → Does Docker need to manage it?
├── YES → Named Volume (production data, managed lifecycle)
└── NO → Bind Mount (your filesystem path)
└── Is it mutable?
├── NO → Read-only bind mount (:ro)
└── YES → Read-write bind mountVolume 管理全命令
基本操作
docker volume create myvolume
docker volume ls
docker volume inspect myvolume
docker volume rm myvolume
docker volume prune # 删除所有未使用的 volume挂载到容器
# 命名卷
docker run -d -v myvolume:/data alpine
# bind mount(绝对路径)
docker run -d -v /host/path:/container/path:ro alpine
# bind mount(相对路径,需 --mount)
docker run -d --mount type=bind,src=./data,target=/data alpine
# tmpfs
docker run -d --tmpfs /tmp:rw,size=128M alpine备份与恢复
# 备份
docker run --rm \
-v db_data:/source \
-v $(pwd):/backup \
alpine tar czf /backup/db_data_backup.tar.gz -C /source .
# 恢复
docker run --rm \
-v db_data:/target \
-v $(pwd):/backup \
alpine tar xzf /backup/db_data_backup.tar.gz -C /target迁移 Volume
# 从旧主机导出
docker run --rm -v old_data:/data alpine tar czf - -C /data . > data.tar.gz
# 传输到新主机
scp data.tar.gz new-host:
# 在新主机导入
docker volume create new_data
docker run --rm -v new_data:/data -v $(pwd):/backup alpine \
tar xzf /backup/data.tar.gz -C /data查看 Volume 占用
docker system df -v # 含 volume 详情
docker volume ls -q | xargs docker volume inspect --format '{{.Name}}: {{.Mountpoint}}'NFS Volume 驱动
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,nolock,rw \
--opt device=:/exports/data \
nfs_data
存储驱动对比与选型
驱动总览
| 驱动 | 后端文件系统 | 写时复制 | 推荐度 |
|---|---|---|---|
| overlay2 | overlay | ✅ | ⭐⭐⭐⭐⭐ |
| fuse-overlayfs | overlay(非特权) | ✅ | ⭐⭐⭐ |
| btrfs | btrfs | ✅ | ⭐⭐ |
| zfs | zfs | ✅ | ⭐⭐ |
| devicemapper | thin provisioning | ✅ | ⭐(已弃用) |
| vfs | 无 | ❌ | ⭐(仅测试) |
| aufs | aufs | ✅ | ⭐(已弃用) |
推荐:overlay2
# 检查当前驱动
docker info | grep "Storage Driver"
# Storage Driver: overlay2
# 检查 overlay 支持
lsmod | grep overlay
grep overlay /proc/filesystems决策树
使用 Linux 4.x+?
├── 是 → overlay2(默认、推荐)
│
└── 否 → 升级内核。
使用 btrfs/zfs 作为宿主机文件系统?
├── btrfs → btrfs 驱动(快照优势)
└── zfs → zfs 驱动(快照+压缩优势)
Rootless 模式?
└── fuse-overlayfs(非特权 overlay)性能对比(定性)
| 指标 | overlay2 | btrfs | zfs |
|---|---|---|---|
| 读写速度 | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
| 磁盘利用率 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 快照/克隆 | - | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 稳定性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
磁盘空间管理
docker system df # 汇总
docker system df -v # 详细
docker system prune -a # 清理(慎用!删除所有未运行镜像和未使用卷)
docker image prune # 清理 dangling 镜像
docker volume prune # 清理未使用卷