一、 Docker 持久化

容器的“临时性”本质

Docker 容器基于 联合文件系统(Union File System) 运行:

  • 底层是只读的镜像层(Image Layers)
  • 顶层是一个可写的容器层(Container Layer),用于保存运行时产生的数据

关键问题:当容器被删除(docker rm)或重建时,其可写层会完全丢失。这意味着:

  • 数据库文件消失
  • 用户上传的图片/附件丢失
  • 日志、配置变更无法保留

结论:容器内部存储 ≠ 持久存储。


二、Docker 持久化的三种方式

Docker 提供三种机制实现持久化,如下所示:

方式描述适用场景
1. 数据卷(Volumes)Docker 管理的专用目录,生命周期独立于容器生产环境、数据库、通用持久化
2. 绑定挂载(Bind Mounts)将宿主机任意目录/文件挂载到容器内配置热更新、代码调试
3. tmpfs 挂载将数据存入宿主机内存(仅 Linux)临时敏感数据(如密钥缓存)

三、数据卷(Volumes)

1. 数据卷

  • 由 Docker 引擎创建和管理的特殊目录
  • 默认存储在宿主机:/var/lib/docker/volumes/<volume_name>/_data
  • 不依赖容器生命周期:即使所有使用该卷的容器都被删除,卷依然存在

2. 核心优势

  • 跨容器共享:多个容器可同时挂载同一卷
  • 易于备份与迁移:可通过临时容器打包卷内容
  • 支持远程存储驱动:如 NFS、Ceph、AWS EBS(通过 -d 指定驱动)
  • 权限自动处理:避免 SELinux 或权限问题(相比 Bind Mount)

3. 基本操作命令

# 创建命名卷
docker volume create my-data

# 查看卷列表
docker volume ls

# 查看卷详细信息(含宿主机路径)
docker volume inspect my-data

# 在运行容器时挂载卷
docker run -d \
  --name web \
  -v my-data:/usr/share/nginx/html \
  nginx

删除未使用的卷(谨慎!)
17docker volume prune

4. 实战示例:持久化 MySQL 数据

# 1. 创建数据卷
docker volume create mysql-db

# 2. 启动 MySQL 并挂载卷到默认数据目录
docker run -d \
  --name mysql \
  -e MYSQL_ROOT_PASSWORD=123456 \
  -v mysql-db:/var/lib/mysql \
  mysql:8

# 3. 创建测试数据库
docker exec mysql mysql -uroot -p123456 -e "CREATE DATABASE test;"

# 4. 删除并重建容器(数据仍在!)
docker rm -f mysql
docker run -d --name mysql2 -e MYSQL_ROOT_PASSWORD=123456 -v mysql-db:/var/lib/mysql mysql:8

# 5. 验证数据存在
docker exec mysql2 mysql -uroot -p123456 -e "SHOW DATABASES;"  # 包含 test

四、绑定挂载(Bind Mounts)——开发利器

1. 绑定挂载

  • 将宿主机上的任意文件或目录直接挂载到容器内的指定路径
  • 路径由用户指定,例如:/home/user/app:/app

2. 使用方式

# 挂载当前目录到容器 /app
docker run -v $(pwd):/app -it ubuntu ls /app

# 挂载单个配置文件
docker run -v /host/nginx.conf:/etc/nginx/nginx.conf nginx

3. 适用场景

  • 开发阶段:代码修改后容器内立即生效(热重载)
  • 配置管理:动态更新 Nginx/Apache 配置
  • 不推荐用于生产:依赖宿主机路径,可移植性差

4. 注意事项

  • 宿主机路径必须绝对路径
  • 若目标路径在容器中不存在,Docker 会自动创建为目录(即使你本意是挂载文件!)
  • 权限问题常见(尤其在 SELinux 环境下),可加 :Z:z 选项(仅限 Linux)

五、持久化最佳实践

场景推荐方案说明
数据库(MySQL/PostgreSQL/Redis)命名卷(Volume)保证数据安全、支持备份
Web 应用上传目录Volume用户头像、附件等需长期保存
日志收集Volume + 日志驱动(如 fluentd)避免日志撑爆容器磁盘
开发调试Bind Mount实现代码实时同步
敏感配置(密码、证书)Docker Secrets(Swarm)或 ConfigMap(K8s)不应存入卷或镜像

安全建议

  • 不要将卷挂载到 / 或关键系统目录
  • 避免多个容器并发写入同一文件(需应用层加锁)
  • 定期备份重要卷(通过临时容器 tar 打包)

六、常见误区澄清

误区正确理解
“只要不删容器,数据就安全”容器可能因崩溃、升级、迁移被重建,仍会丢数据
“用 docker commit 可以保存数据”commit 只保存镜像层,不包含 Volume 数据
“Bind Mount 比 Volume 更灵活”灵活性带来的是可移植性和安全性的牺牲
“Volume 存在宿主机上不安全”Volume 路径受 Docker 管理,默认权限合理,比随意 Bind Mount 更安全

七、总结

Docker 持久化的核心思想是:将状态(State)与计算(Compute)分离。

  • 数据卷(Volume) 是生产环境的标准答案
  • 绑定挂载(Bind Mount) 是开发阶段的高效工具
  • 不要依赖容器内部存储保存任何重要数据

通过合理使用持久化机制,你可以构建出:

  • 高可用的应用(容器宕机重建不影响数据)
  • 易维护的系统(数据可备份、可迁移)
  • 云原生友好的架构(符合 12-Factor App 原则)

记住:“容器是牲口,不是宠物;数据是资产,必须外置。”

docker镜像制作

epel-aliyun.repo

CentOS-aliyun-lhr.repo

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

架构(符合 12-Factor App 原则)

记住:“容器是牲口,不是宠物;数据是资产,必须外置。”

docker镜像制作

epel-aliyun.repo

CentOS-aliyun-lhr.repo

[外链图片转存中…(img-gj6UjesU-1764158516438)]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

更多推荐