当前位置: 首页 > news >正文

【深析】 Docker Desktop 中的容器文件系统:OverlayFS vs Containerd Snapshots

引言

在使用 Docker Desktop 运行容器时,开发者经常会遇到各种复杂的文件系统路径。特别是当我们通过-v参数挂载本地目录时,Docker 会创建一系列复杂的存储结构。

本文将通过一个具体的 LocalAI 容器案例,深入解析 Docker Desktop 中两个不同存储路径的区别和原理。

先说结论

简单说,这两个路径是Docker在后台“干活”留下的不同痕迹。

第一个是Containerd运行时管理的,相当于容器的“原始底稿”,就是你挂载卷之前容器里自带的/build目录内容。

第二个是Docker自己管理的,相当于运行时的“工作现场”,包含了卷挂载后的状态。

但其实这两个路径你都不用管,因为你的数据实际上在Windows的D:/localai-data/里。容器里的/build只是映射过来的窗口,你在Windows那边改了文件,容器里就能看到。

所以记住:你的模型和配置都在D盘那个文件夹,Docker内部那些复杂路径不用操心。

案例背景

我运行了以下命令启动一个 LocalAI 容器:

dockerrun -d --name local-ai --gpus all -p8080:8080\-v D:/localai-data/models:/build/models\-v D:/localai-data/config:/build/config\localai/localai:latest-gpu-nvidia-cuda-12

然后发现在 WSL 中有两个看起来相似但不同的路径:

  1. Containerd 快照路径:

    \\wsl.localhost\docker-desktop\mnt\docker-desktop-disk\data\desktop-containerd\daemon\io.containerd.snapshotter.v1.overlayfs\snapshots\284\fs\build
  2. Docker OverlayFS 路径:

    \\wsl.localhost\docker-desktop\mnt\docker-desktop-disk\data\docker\rootfs\overlayfs\f0e048f2205532a006623a8e02fef1534a391646e84047a51ffb5f560a616967\build

技术架构深度解析

1. Docker Desktop 的存储架构

Docker Desktop 在 Windows 上使用 WSL 2 运行时,采用了多层存储架构:

Windows 主机 ├── WSL 2 │ ├── Docker Desktop VM │ │ ├── Containerd 运行时 │ │ └── Docker 守护进程 │ └── 用户 WSL 发行版 └── Windows 文件系统

2. Containerd 快照路径解析

路径:
\\wsl.localhost\docker-desktop\mnt\docker-desktop-disk\data\desktop-containerd\daemon\io.containerd.snapshotter.v1.overlayfs\snapshots\284\fs\build

这是 Containerd 的 OverlayFS 快照层

结构分解:

  • desktop-containerd/daemon/- Containerd 守护进程数据目录
  • io.containerd.snapshotter.v1.overlayfs/- OverlayFS 快照管理器
  • snapshots/284/- 第 284 号快照(随机ID)
  • fs/- 容器的根文件系统
  • build/- 容器内的 /build 目录

特点:

  1. Containerd 管理:由 Containerd 容器运行时直接管理
  2. 快照机制:使用 OverlayFS 的快照(snapshot)功能
  3. 原始容器视图:展示容器挂载卷之前的原始文件系统状态
  4. 可写层基础:是容器可写层(upperdir)的基础

验证命令:

# 查看容器在 Containerd 中的信息dockerrun --rm -v /var/run/docker.sock:/var/run/docker.sock\redcoolbeans/dockercontainerspy containerd-list# 在容器内查看 OverlayFS 挂载dockerexeclocal-aimount|grepoverlay

3. Docker OverlayFS 路径解析

路径:
\\wsl.localhost\docker-desktop\mnt\docker-desktop-disk\data\docker\rootfs\overlayfs\f0e048f2205532a006623a8e02fef1534a391646e84047a51ffb5f560a616967\build

这是 Docker 的 OverlayFS 存储驱动层

结构分解:

  • docker/rootfs/overlayfs/- Docker 的 OverlayFS 存储驱动目录
  • f0e048f220...- 64 位随机哈希,标识特定容器层
  • build/- 容器内的 /build 目录

特点:

  1. Docker 管理:由 Docker 守护进程管理
  2. 存储驱动:使用 Docker 的 OverlayFS 存储驱动
  3. 联合挂载:可能包含多个镜像层的联合视图
  4. 运行时状态:包含卷挂载后的文件系统状态

验证命令:

# 查看容器的存储驱动信息dockerinspect local-ai --format='{{.GraphDriver}}'# 查看具体的存储驱动数据dockerinspect local-ai --format='{{json .GraphDriver.Data}}'

关键区别对比

特性Containerd 快照路径Docker OverlayFS 路径
管理者Containerd 运行时Docker 守护进程
用途容器基础镜像快照容器运行时的存储层
数据内容挂载卷前的原始数据可能包含运行时修改
持久性基础层,通常只读包含可写层
生命周期与镜像层关联与容器实例关联

实际操作验证

1. 查看容器存储详情

# 获取容器 IDdockerps-qf"name=local-ai"# 查看容器详情dockerinspect local-ai|grep-A10-B5"GraphDriver"# 输出示例:# "GraphDriver": {# "Data": {# "LowerDir": "/var/lib/docker/overlay2/xxx/diff:/var/lib/docker/overlay2/yyy/diff",# "MergedDir": "/var/lib/docker/overlay2/zzz/merged",# "UpperDir": "/var/lib/docker/overlay2/zzz/diff",# "WorkDir": "/var/lib/docker/overlay2/zzz/work"# },# "Name": "overlay2"# }

2. 在容器内验证挂载

# 进入容器dockerexec-it local-aish# 查看 /build 目录结构ls-la /build/# 应该看到 models 和 config 目录# 查看挂载信息mount|grep/build# 输出应显示从 Windows 主机挂载的目录

3. 查看卷映射

# 查看容器的卷挂载dockerinspect local-ai --format='{{json .Mounts}}'# 输出应显示:# [# {# "Type": "bind",# "Source": "/mnt/d/localai-data/models",# "Destination": "/build/models",# "Mode": "",# "RW": true,# "Propagation": "rprivate"# },# {# "Type": "bind",# "Source": "/mnt/d/localai-data/config",# "Destination": "/build/config",# "Mode": "",# "RW": true,# "Propagation": "rprivate"# }# ]

为什么有两个相似的 /build 目录?

1. 挂载覆盖机制

当使用-v参数挂载卷时,Docker 使用了 Linux 的挂载覆盖机制:

容器 /build 原始目录

卷挂载点

Windows D:/localai-data/models

Windows D:/localai-data/config

容器运行时视图 /build

2. 两个路径的实际关系

  1. Containerd 路径

    • 包含容器镜像中原始的/build目录内容
    • 在卷挂载前存在
    • 卷挂载后,这个目录被隐藏(masked)
  2. Docker OverlayFS 路径

    • 是运行时视图的一部分
    • 可能包含容器修改的元数据
    • 实际的卷挂载在这个视图之上

3. 验证实验

# 1. 停止容器dockerstop local-ai# 2. 查看 Containerd 路径# 此时应该能看到原始的 /build 目录内容# 3. 启动容器dockerstart local-ai# 4. 再次查看 Containerd 路径# 由于卷已挂载,原始 /build 目录被隐藏

实际影响和注意事项

开发者需要知道的

  1. 数据存储位置

    • 你的模型文件实际存储在D:/localai-data/models/
    • Docker 容器内的路径只是映射视图
  2. 性能考虑

    • Windows → WSL → Docker 的三层转换有一定性能开销
    • 大量小文件操作时尤其明显
  3. 备份策略

    • 备份D:/localai-data/目录即可
    • 不需要备份 Docker 内部的路径
  4. 权限问题

    • Windows 和 Linux 文件权限系统不同
    • 可能需要配置 WSL 的权限映射

优化建议

  1. 使用 Docker 卷替代绑定挂载:

    dockervolume create localai-modelsdockervolume create localai-configdockerrun -d --name local-ai\-v localai-models:/build/models\-v localai-config:/build/config\localai/localai:latest-gpu-nvidia-cuda-12
  2. 性能优化配置

    // 在 Docker Desktop 设置中添加{"wslEngineEnabled":true,"wslEngineOptimization":"performance"}
  3. 监控存储使用

    # 查看容器存储使用dockersystemdf# 查看详细存储信息dockersystemdf-v

高级调试技巧

1. 查看 OverlayFS 层次结构

# 在 WSL 中wsl -d docker-desktop# 查找容器相关层find/var/lib/docker/overlay2 -name"lower"-type f|xargsgrep-l"local-ai"# 查看层关联cat/var/lib/docker/image/overlay2/layerdb/mounts/*/mount-id

2. 使用 dive 工具可视化

# 安装 divedockerrun --rm -it\-v /var/run/docker.sock:/var/run/docker.sock\wagoodman/dive:latest localai/localai:latest-gpu-nvidia-cuda-12

3. 文件系统事件监控

# 在容器运行时监控文件访问dockerrun --rm -it\--pid=container:local-ai\--cap-add SYS_PTRACE\alpinesh-c"apk add strace && strace -p 1 -e trace=file"

常见问题解答

Q1: 为什么我的文件修改在容器内看不到?
A: 检查 Windows 到 WSL 的文件系统同步,可能需要重启 Docker Desktop 或 WSL。

Q2: 如何清理这些临时文件?
A: 使用docker system prune -a清理,但注意这会删除所有未使用的资源。

Q3: 这两个目录哪个是"真实"的?
A: 都不是"真实"的数据存储位置。你的真实数据在 Windows 的 D:/localai-data/ 目录中。

Q4: 如何提高文件访问性能?
A: 考虑将数据放在 Linux 文件系统中,或使用 Docker 卷而非绑定挂载。

总结

通过深入分析这两个路径,我们可以理解 Docker Desktop 的复杂存储架构:

  1. 分层管理:Docker 使用多层存储(镜像层、容器层、挂载层)
  2. 运行时抽象:Containerd 和 Docker 守护进程协同工作
  3. 挂载覆盖:绑定挂载会覆盖容器内的原始目录
  4. 性能优化:理解架构有助于优化存储性能

对于大多数开发者,关键要点是:

  • 理解你的数据实际存储位置
  • 使用适当的挂载方式
  • 定期清理不再使用的存储资源
  • 监控存储使用情况

掌握这些底层知识,可以帮助你更有效地使用 Docker,并能在出现问题时快速定位和解决存储相关问题。

http://www.jsqmd.com/news/168529/

相关文章:

  • 利用Miniconda-Python3.11镜像提升AI开发效率|Jupyter远程访问配置说明
  • Keil C51与传感器接口编程:实战项目示例
  • 7-1 WPS JS宏 Object对象创建的几种方法
  • 如何在Linux上使用Miniconda-Python3.11快速安装PyTorch GPU版本
  • STM32下载失败?排查JLink驱动设置的关键步骤
  • Conda环境命名规范:提高Miniconda-Python3.11项目的可维护性
  • Miniconda-Python3.10镜像支持电子病历自然语言处理
  • 基于Python的智慧大学生资助补助系统的设计与实现vue
  • Keil新建工程步骤通俗解释:适合初学者
  • 敏捷咨询机构案例分析:以标杆实践赋能企业数智化转型
  • Conda clean清理缓存:释放Miniconda-Python3.11占用的磁盘空间
  • GitHub Pages静态站点生成:用Miniconda-Python3.11运行MkDocs
  • 基于python的食力派网上订餐系统vue
  • ESP32连接阿里云MQTT:基于WiFi的通信层完整指南
  • Miniconda-Python3.10镜像支持AR/VR内容生成的预处理
  • Java SpringBoot+Vue3+MyBatis 乡村养老服务管理系统系统源码|前后端分离+MySQL数据库
  • 使用Miniconda创建独立Python环境,高效管理CUDA与PyTorch版本
  • 6-13 WPS JS宏 Map实例2--拆分记录到表格
  • 【毕业设计】SpringBoot+Vue+MySQL 箱包存储系统平台源码+数据库+论文+部署文档
  • ClickHouse 为大数据领域的实时决策提供支持
  • STM32CubeMX安装步骤深度剖析:安装失败原因分析
  • 基于Python高校学生选课成绩分析系统的设计与实现
  • Miniconda-Python3.10镜像在碳排放追踪系统中的技术支撑
  • fastjson (1概述)
  • STM32程序在Keil5中的单步调试技巧
  • LTspice批量运行仿真脚本实践:高级用户指南
  • Miniconda镜像内置pip与Conda双工具,灵活安装各类AI框架
  • CubeMX配置FreeRTOS完整示例解析
  • Python安装模块找不到?正确激活Miniconda-Python3.11环境是关键
  • 清华源配置教程:将Miniconda-Python3.11的pip安装速度提升5倍