基础 掌握Docker数据持久化的三种方式,理解卷与绑定挂载的区别与应用场景
容器文件系统是临时的——容器删除后所有数据丢失。这是容器的核心设计理念(不可变基础设施),但应用数据必须持久化:
Volume由Docker管理,存储在 /var/lib/docker/volumes/ 下,是推荐的持久化方式:
# 创建命名卷
docker volume create my-data
# my-data
# 使用卷运行容器
docker run -d --name db1 \
-v my-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
mysql:8.0-oracle
# 查看卷信息
docker volume inspect my-data
# [{
# "CreatedAt": "2024-01-15T10:30:00Z",
# "Driver": "local",
# "Mountpoint": "/var/lib/docker/volumes/my-data/_data",
# "Name": "my-data",
# "Scope": "local"
# }]
# 列出所有卷
docker volume ls
# 多容器共享同一卷
docker run -d --name writer \
-v shared-data:/app/data \
alpine:latest \
sh -c "echo 'Hello from writer' > /app/data/message && sleep 3600"
docker run --rm \
-v shared-data:/app/data \
alpine:latest \
cat /app/data/message
# Hello from writer ✅ 数据卷共享验证通过
# 只读挂载
docker run -d --name reader \
-v shared-data:/app/data:ro \
alpine:latest sh -c "sleep 3600"
docker exec reader sh -c "echo 'test' > /app/data/test"
# sh: can't create /app/data/test: Read-only file system ✅
# --mount 更明确,推荐在生产环境使用
docker run -d --name mount-demo \
--mount type=volume,source=my-data,target=/app/data \
nginx:alpine
# bind mount 用 --mount
docker run -d --name bind-demo \
--mount type=bind,source=/tmp/html,target=/usr/share/nginx/html \
nginx:alpine
# tmpfs 用 --mount
docker run -d --name tmpfs-demo \
--mount type=tmpfs,target=/app/cache,tmpfs-size=100000000 \
nginx:alpine
将主机指定目录直接挂载到容器,适合开发环境代码热更新:
# 创建主机目录
mkdir -p /tmp/docker-html
# 绑定挂载——开发代码热更新
echo "<h1>Hello from host</h1>" > /tmp/docker-html/index.html
docker run -d --name dev-web \
-v /tmp/docker-html:/usr/share/nginx/html:ro \
-p 8085:80 \
nginx:alpine
curl http://localhost:8085
# <h1>Hello from host</h1> ✅ 绑定挂载验证通过
# 修改主机文件,容器立即看到变化
echo "<h1>Updated!</h1>" > /tmp/docker-html/index.html
curl http://localhost:8085
# <h1>Updated!</h1> ✅ 热更新验证通过
:ro 只读挂载或确保挂载路径正确。容器内以root运行时尤其危险。
tmpfs存储在内存中,容器停止后数据消失,适合敏感临时数据:
# tmpfs挂载
docker run -d --name tmp-test \
--tmpfs /app/cache:size=100m,mode=1777 \
alpine:latest \
sh -c "dd if=/dev/zero of=/app/cache/test bs=1M count=50 && sleep 3600"
docker exec tmp-test df -h /app/cache
# Filesystem Size Used Available Use% Mounted on
# tmpfs 100M 50M 50M 50% /app/cache ✅
# 容器停止后tmpfs数据消失
docker stop tmp-test && docker start tmp-test
docker exec tmp-test ls /app/cache/
# (空目录) ✅ tmpfs数据不持久
| 特性 | Volume | Bind Mount | tmpfs |
|---|---|---|---|
| 存储位置 | /var/lib/docker/volumes/ | 主机任意目录 | 内存 |
| 管理方式 | Docker CLI管理 | 手动管理 | 自动清理 |
| 可移植性 | ✅ 好 | ❌ 依赖主机路径 | N/A |
| 性能 | 良好 | 优秀(直接主机IO) | 最优(内存) |
| 适合场景 | 生产数据持久化 | 开发环境代码挂载 | 临时/敏感数据 |
| 备份 | docker volume备份 | 直接备份主机目录 | 无需 |
| 多容器共享 | ✅ 支持 | ✅ 支持 | ❌ 不支持 |
| 驱动插件 | ✅ 支持NFS等 | ❌ 仅本地 | ❌ 仅本地 |
# 1. 创建数据卷
docker volume create pg-data
# 2. 启动PostgreSQL
docker run -d --name my-postgres \
-v pg-data:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=secret \
-p 5432:5432 \
postgres:16-alpine
# 3. 写入数据
docker exec my-postgres psql -U postgres -c \
"CREATE TABLE users (id SERIAL, name TEXT); INSERT INTO users (name) VALUES ('Alice'), ('Bob');"
docker exec my-postgres psql -U postgres -c "SELECT * FROM users;"
# id | name
# ----+-------
# 1 | Alice
# 2 | Bob ✅ 数据写入成功
# 4. 删除容器
docker rm -f my-postgres
# 5. 用同一卷重新创建——数据还在
docker run -d --name my-postgres2 \
-v pg-data:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=secret \
postgres:16-alpine
docker exec my-postgres2 psql -U postgres -c "SELECT * FROM users;"
# 数据持久化验证通过 ✅
# 6. 备份卷到tar文件
docker run --rm \
-v pg-data:/source:ro \
-v /tmp:/backup \
alpine:latest \
tar czf /backup/pg-backup.tar.gz -C /source .
# 7. 恢复卷
docker volume create pg-data-restored
docker run --rm \
-v pg-data-restored:/target \
-v /tmp:/backup \
alpine:latest \
tar xzf /backup/pg-backup.tar.gz -C /target
# 8. 清理
docker rm -f my-postgres2
docker volume rm pg-data pg-data-restored
# 创建NFS卷
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/data/shared \
nfs-volume
# 使用NFS卷(多主机共享)
docker run -d --name shared-app \
-v nfs-volume:/app/data \
nginx:alpine
# 带标签创建卷
docker volume create \
--label env=production \
--label app=database \
prod-db-data
# 按标签过滤
docker volume ls --filter label=env=production
docker volume prune 误删卷命名卷在无容器引用时也会被清理。重要数据定期备份。
| 要点 | 说明 | 最佳实践 |
|---|---|---|
| 资源规划 | 根据业务负载合理分配CPU/内存 | 先压测再上线,设置requests和limits |
| 监控告警 | 设置关键指标阈值和告警规则 | Prometheus + AlertManager,5分钟P99延迟告警 |
| 备份策略 | 定期备份关键数据和配置 | 自动化备份脚本 + 异地存储 + 定期恢复演练 |
| 灰度发布 | 新版本逐步放量降低风险 | 金丝雀发布5%→20%→50%→100% |
| 回滚预案 | 部署前确认回滚方案和步骤 | 保留前一版本镜像,数据库迁移向前兼容 |
| 文档更新 | 配置变更必须同步更新文档 | GitOps管理配置,变更即文档 |
| 安全基线 | 遵循CIS Docker Benchmark | 非root运行、只读FS、最小能力 |
| 日志规范 | 结构化日志,统一格式 | JSON格式日志,包含traceId |
# 容器生命周期
docker create/start/stop/restart/rm/pause/unpause
docker logs/top/stats/inspect/exec diff
# 镜像构建
docker build/pull/push/tag/rmi/images/history
docker save/load/import/manifest
# 网络与存储
docker network create/ls/inspect/connect/disconnect/rm/prune
docker volume create/ls/inspect/rm/prune
# Docker Compose
docker compose up/down/ps/logs/build/exec
docker compose config/stop/start/scale/top/cp
# 系统维护
docker system df/prune/info
docker builder prune
docker container/prune/image prune
# K8s常用命令
kubectl get/describe/logs/exec/apply/delete
kubectl rollout status/undo/history
kubectl scale/autoscale/set