Docker 存储架构与数据管理详解

Docker 分层存储结构

容器分层架构

Docker 容器采用分层结构设计,如图所示:

┌─────────────────┐
│   容器层 (可读写)   │ ← 容器运行时层
├─────────────────┤
│   镜像层 (只读)     │ ← 依赖的基础镜像层
│   镜像层 (只读)     │
│   镜像层 (只读)     │
└─────────────────┘

分层结构特点:

  • 容器层:最上层,可读可写
  • 镜像层:下层,只读不可修改
  • 写时复制 (Copy-on-Write):核心机制

写时复制机制详解

  1. 容器新生成的数据直接存储在可读可写的容器层(可写层)。
  2. 修改容器中已有数据时,会先从镜像层复制数据到容器层,修改后的数据仅保存在容器层,镜像层数据保持不变。
  3. 若多个镜像层存在同名文件,容器中仅显示最上层镜像层的文件内容。

写时复制流程:

  1. 创建新文件 → 直接写入容器层
  2. 修改现有文件 → 从镜像层复制到容器层后修改
  3. 删除文件 → 在容器层创建删除标记
  4. 多层同名文件 → 只显示最上层内容

联合挂载技术

OverlayFS 存储驱动

Docker 镜像的分层设计极大提升了镜像构建、容器创建、共享和分发的效率。每个镜像层(layer)存储在 /var/lib/docker/volume/<storage-driver>/ 目录,其中 storage-driver 支持多种类型(如 AUFS、OverlayFS、VFS、Brtfs 等)。

# 查看 Docker 存储驱动
[root@hrz3 ~]# docker info | grep "Storage Driver"
Storage Driver: overlay2

支持的存储驱动:

  • AUFS:Ubuntu 系统默认
  • OverlayFS:CentOS 7.1+ 默认
  • VFS、Btrfs:其他文件系统

OverlayFS 工作原理

┌─────────────────┐
│   merged        │ ← 向用户呈现的统一视图
├─────────────────┤
│   upper         │ ← 容器层(可写)
├─────────────────┤
│   lower         │ ← 镜像层(只读)
└─────────────────┘

技术特点:

  • 建立在现有文件系统之上(ext4、xfs)
  • 不直接管理磁盘空间
  • 通过目录合并呈现统一视图
  • overlay2overlay 更高效

环境要求:

  • Docker 版本 17.06.02+
  • 宿主机文件系统:ext4 或 xfs

数据卷(Data Volume)机制

数据持久化需求

默认存储的问题:

  • 容器停止后数据丢失
  • 数据难以从容器中提取
  • 不支持多容器数据共享

Volume 解决方案:

  • 绕过联合文件系统
  • 以正常文件/目录形式存在
  • 支持数据持久化

Volume 类型对比

特性 Bind Mounts Docker Managed Volume
数据流向 宿主机 → 容器 容器 → 宿主机
数据位置 宿主机指定路径 /var/lib/docker/volumes/
移植性
管理方式 手动管理 Docker 自动管理

Bind Mounts 绑定挂载

基本使用示例

# 1. 创建宿主机目录和测试文件
[root@hrz3 ~]# mkdir html   
[root@hrz3 ~]# echo "Hello world" > html/index.html

# 2. 创建容器并绑定挂载目录
[root@hrz3 ~]# docker run --name mynginx -itd -p 80:80 -v /root/html:/usr/share/nginx/html nginx:latest
4118d7894ac4a6bebeeefbd708218fcd29d8c67764959bb5a6505a0213b5d9da

# 3. 验证数据访问
[root@hrz3 ~]# curl http://192.168.100.30:80
Hello world

数据实时同步

# 修改宿主机文件,容器内实时同步
[root@hrz3 ~]# echo "Hello luoqi! " > html/index.html 
[root@hrz3 ~]# curl http://192.168.100.30:80          
Hello luoqi!

数据持久化验证

# 删除容器,宿主机数据保留
[root@hrz3 ~]# docker rm -f mynginx 
mynginx
[root@hrz3 ~]# cat html/index.html 
Hello luoqi! 

只读权限控制

# 创建只读挂载,增强安全性
[root@hrz3 ~]# docker run --name mynginx -itd -p 80:80 -v /root/html/index.html:/usr/share/nginx/html/index.html:ro nginx:latest
9cc13099b8c45bc49d7f96d62ec1428b0fa7599e2ae6b2b72613d1697c6321af

# 容器内尝试修改(失败)
[root@hrz3 ~]# docker exec -it mynginx /bin/bash
root@9cc13099b8c4:/# cd /usr/share/nginx/html/
root@9cc13099b8c4:/usr/share/nginx/html# echo Hello World! > index.html
bash: index.html: Read-only file system

Bind Mounts 局限性:

  • 依赖宿主机特定路径
  • 容器移植性差
  • 需要预先准备数据

Docker Managed Volume 管理卷

自动卷管理

# 让 Docker 自动管理数据卷
[root@hrz3 ~]# docker run --name mynginx2 -itd -p 80:80 -v /usr/share/nginx/html nginx:latest

查看卷信息

# 查看容器挂载详情
[root@hrz3 ~]# docker inspect mynginx2 
...
"Mounts": [
    {
        "Type": "volume",
        "Name": "111dd931a67c1e612a7a0d83d6e6cef27392a173ff3ec0534c505089987e90d3",
        "Source": "/var/lib/docker/volumes/111dd931a67c1e612a7a0d83d6e6cef27392a173ff3ec0534c505089987e90d3/_data",
        "Destination": "/usr/share/nginx/html",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }
],
...

# 查看卷中实际数据
[root@hrz3 ~]# cd /var/lib/docker/volumes/111dd931a67c1e612a7a0d83d6e6cef27392a173ff3ec0534c505089987e90d3/_data/
[root@hrz3 _data]# ls
50x.html  index.html

数据同步验证

# 修改卷数据,容器内实时同步
[root@hrz3 _data]# echo Hello World > /var/lib/docker/volumes/111dd931a67c1e612a7a0d83d6e6cef27392a173ff3ec0534c505089987e90d3/_data/index.html 
[root@hrz3 _data]# curl 192.168.100.30
Hello World

手动卷管理

# 创建命名卷
[root@hrz3 ~]# docker volume create myvol
[root@hrz3 ~]# docker volume ls 
DRIVER    VOLUME NAME
local     myvol

# 使用命名卷创建容器
[root@hrz3 ~]# docker run --name mynginx3 -itd -p 8080:80 -v myvol:/usr/share/nginx/html nginx:latest

容器间数据共享方案

方案一:多容器挂载同一 Volume

# 创建三个 Nginx 容器共享同一数据源
[root@hrz3 ~]# docker run --name apache1 -itd -p 8081:80 -v /root/html:/usr/share/nginx/html nginx:latest 
36c48b6f31852d04bae1c73af75b37946bb968bbc430e15109c6ddcac81c7e4a
[root@hrz3 ~]# docker run --name apache2 -itd -p 8082:80 -v /root/html:/usr/share/nginx/html nginx:latest  
fe85b12aee3e03c5ab460a5be855339740002cda509ea04fa3e05baf99e11130
[root@hrz3 ~]# docker run --name apache3 -itd -p 8083:80 -v /root/html:/usr/share/nginx/html nginx:latest   
9bd97444240d23a5e26ec71ab43b4328706716fa2e9a42b4e79b7f2db56d5c43

# 验证数据一致性
[root@hrz3 ~]# curl 192.168.100.30:8081
Hello luoqi! 
[root@hrz3 ~]# curl 192.168.100.30:8082
Hello luoqi! 
[root@hrz3 ~]# curl 192.168.100.30:8083
Hello luoqi! 

方案二:Volume Container 卷容器

创建专门的数据卷容器,提供统一的数据管理。

# 1. 创建数据卷容器(不运行)
[root@hrz3 ~]# docker create --name mydata -v /root/html:/usr/share/nginx/html busybox

# 2. 其他容器共享数据卷
[root@hrz3 ~]# docker run --name mynginx1 -itd -p 8081:80 --volumes-from mydata nginx
[root@hrz3 ~]# docker run --name mynginx2 -itd -p 8082:80 --volumes-from mydata nginx
[root@hrz3 ~]# docker run --name mynginx3 -itd -p 8083:80 --volumes-from mydata nginx

# 3. 验证数据共享
[root@hrz3 ~]# echo welcome to luoqi > /root/html/index.html 
[root@hrz3 ~]# curl 192.168.100.30:8081                      
welcome to luoqi
[root@hrz3 ~]# curl 192.168.100.30:8082                      
welcome to luoqi
[root@hrz3 ~]# curl 192.168.100.30:8083                      
welcome to luoqi

Volume Container 优势:

  • 解耦容器与宿主机路径依赖
  • 统一管理数据卷配置
  • 提高容器可移植性

方案三:Data-Packed Volume Container

将数据打包到镜像中,实现完全自包含。

创建包含数据的镜像
# Dockerfile - 构建数据打包镜像
FROM busybox:latest
ADD html /usr/share/nginx/html
VOLUME /usr/share/nginx/html
CMD ["/bin/bash"]
构建和使用过程
# 1. 准备数据文件
[root@hrz3 ~]# echo Hello World > html/index.html 

# 2. 构建包含数据的镜像
[root@hrz3 ~]# docker build -t my_hy /root  

# 3. 创建数据卷容器
[root@hrz3 ~]# docker create --name my_data my_hy

# 4. 使用数据卷容器
[root@hrz3 ~]# docker run --name mynginx1 -itd -p 8080:80 --volumes-from my_data nginx

# 5. 验证数据访问
[root@hrz3 ~]# curl http://127.0.0.1:8080       
Hello World

Data-Packed Volume Container 优势:

  • 完全自包含,不依赖外部存储
  • 极佳的移植性
  • 适合静态数据场景(配置、静态资源)

存储扩展支持

外部存储系统

Docker 支持多种外部存储系统:

  • NFS:网络文件系统
  • Ceph:分布式存储
  • iSCSI:网络存储协议
  • 云存储:AWS EBS、Azure Disk 等
# 使用外部存储插件
[root@hrz3 ~]# docker volume create --driver local \
    --opt type=nfs \
    --opt o=addr=192.168.1.1,rw \
    --opt device=:/path/to/directory \
    nfs-volume

总结与最佳实践

数据共享方法对比

方法 优点 缺点 适用场景
多容器挂载 简单直接 依赖宿主机路径 开发环境
Volume Container 解耦依赖、统一管理 仍需外部存储 生产环境
Data-Packed 完全自包含、移植性好 数据更新复杂 静态配置

核心架构要点

  1. 分层结构:容器 = 可写层 + 多个只读镜像层
  2. 写时复制:修改时从镜像层复制到容器层
  3. 联合挂载:OverlayFS 实现目录合并
  4. 数据持久化:Volume 绕过联合文件系统

存储选择策略

  • 开发调试:使用 Bind Mounts(实时同步)
  • 生产环境:使用 Docker Managed Volume(自动管理)
  • 配置分发:使用 Data-Packed Volume Container(完全自包含)
  • 多容器共享:使用 Volume Container(统一管理)

通过合理运用 Docker 存储机制,可以构建高效、可靠、可移植的容器化应用架构。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐