百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

Docker存储驱动OverLay2介绍(docker evicted)

wptr33 2025-07-06 17:18 2 浏览

1 overlay2分层介绍

OverlayFS 是一个联合文件系统。

对内核的需求

  • Linux 内核 4.0 或更高版本
  • 或使用3.10.0-514 或更高版本内核的 RHEL 或 CentOS。

更改存储驱动程序会导致本地系统上现有的容器和镜像无法访问。在更改存储驱动程序之前,需要使用 docker save保存已构建的所有镜像,或将其推送到 Docker Hub 或私有镜像仓库,这样以后就无需重新创建它们。

通过docker info可以查看目前docker使用的存储驱动

2 overlay2工作原理

OverlayFS(叠加文件系统)将Linux主机上的两个目录进行分层,并将其呈现为一个统一的目录。这些目录被称为"层"(layers),而统一过程则称为"联合挂载"(union mount)。OverlayFS将下层目录称为"lowerdir",即镜像内的只读层,上层目录称为"upperdir",即创建容器后的可读可写层。最终通过名为"merged"(合并层)的独立目录展示统一后的视图。

在merged目录可以看到容器内所有层的文件信息

下面通过一个表格简述各层之间的关系

层级

作用

特点

lowerdir

只读层(基础层)

通常是镜像或系统的基础文件,所有修改不会影响这一层。对应的是docker镜像层

upperdir

可写层(容器层)

存储对lowerdir的修改(新增、删除、更改文件),所有的变动都保存在这里。对应容器的新增文件。

merged

统一视图层(只读层+可写层)

动态合并lowerdir和upperdir,用户看到的是最终的同一文件系统。对应容器内的根目录

workdir

临时工作目录

workdir 是一个必需的临时工作目录,供 OverlayFS 内部使用,主要用于处理文件操作时的原子性和一致性。当你在容器内创建、修改或删除文件时,OverlayFS 会先在 workdir 中暂存中间状态,确保操作完成后再同步到 upperdir(可写层)。

启动容器后,可以通过mount命令查看到容器的overlay2挂载信息

其中lowerdir共有三个目录,对应镜像中的不同层

查看容器对应的数据目录

docker inspect 9c9b5fdb76e2 --format '
UpperDir:  {{.GraphDriver.Data.UpperDir}}
LowerDir:  {{.GraphDriver.Data.LowerDir}}
MergedDir: {{.GraphDriver.Data.MergedDir}}
WorkDir:   {{.GraphDriver.Data.WorkDir}}'

3 overlay2层数限制

Overlay2存储驱动原生支持最多128个下层OverlayFS镜像层。该特性为Docker层相关操作(如docker build构建镜像和docker commit提交变更)提供了更优异的性能表现,同时能有效减少底层文件系统的inode占用。

(1) 128 层的来源

  • OverlayFS 内核实现中,lowerdir 参数最多支持 128 个路径(以 : 分隔)。
  • 每个 Docker 镜像层(RUN、COPY 等指令生成的层)对应一个 OverlayFS 的 lowerdir。

(2) 层合并示例

假设一个镜像有 3 个层:

FROM ubuntu            # 层1
RUN apt update         # 层2
COPY app /app          # 层3

挂载时:

lowerdir=层3:层2:层1  # 从顶层到底层依次排列

(3) 超出 128 层的处理

  • 若镜像层数超过 128,Docker 会自动合并部分层(通过 flatten 操作),但会牺牲部分效率。
  • 最佳实践:通过多阶段构建或合并指令(如 &&)减少层数。

4 磁盘上的容器和镜像层

下图展示了Docker镜像与容器的分层结构。镜像层作为lowerdir(下层目录),容器层作为upperdir(上层目录)。当镜像存在多个分层时,系统会使用多个lowerdir目录。最终通过名为merged(合并层)的目录呈现统一视图,该目录实质上就是容器的挂载点(容器内的根目录)。

当镜像层与容器层存在相同文件时,容器层(upperdir/上层目录)的文件将优先生效,并遮蔽镜像层中的同名文件。

overlay2驱动在创建容器时,会将代表镜像顶层的目录与新建的容器目录进行联合挂载。镜像各层作为overlay的lowerdir(下层目录)处于只读状态,而新建的容器目录则作为upperdir(上层目录)可写入。

5 在overlay2下容器读写机制

5.1 读取文件

场景一:文件仅存在于镜像层(lowerdir)

当容器尝试读取某个文件时,若该文件不存在于容器层(upperdir),系统会直接从镜像层(lowerdir)读取。此操作产生的性能开销极低。

场景二:文件仅存在于容器层(upperdir)

当容器读取的文件仅存在于容器层(upperdir)而镜像层(lowerdir)中不存在时,系统将直接从容器层读取文件内容。

场景三:文件同时存在于容器层和镜像层

若文件同时存在于容器层(upperdir)和镜像层(lowerdir),系统会优先读取容器层中的文件版本。容器层中的文件始终会遮蔽(override)镜像层中的同名文件。

5.2 修改文件或目录

5.2.1 首次写入文件时处理逻辑

当容器首次对某个已存在的文件执行写操作时(该文件尚未存在于容器层/upperdir),overlay2驱动将执行copy_up操作,把文件从镜像层(lowerdir)完整复制到容器层(upperdir),后续所有修改将作用于容器层中的文件副本。

需特别注意:

  • OverlayFS基于文件层面而非块级别运作,即使仅修改大文件的一小部分,copy_up操作仍会复制整个文件,这可能显著影响容器写入性能
  • copy_up操作仅在该文件首次被修改时触发,后续写入直接作用于容器层中的副本文件
  • 多层镜像结构可能导致文件检索性能下降,尤其当镜像层数较多时

(1) 文件检索的底层机制

当容器访问一个文件(如 /usr/bin/python3)时,OverlayFS 会按以下顺序查找:

  • 从顶层开始向下搜索upperdir(容器可写层)→ 第一层 lowerdir → 第二层 lowerdir → ... → 最底层 lowerdir
  • 首次匹配即返回一旦在某层找到文件,立即终止搜索(类似 PATH 环境变量的查找逻辑)

(2) 性能下降的核心原因

  • 查找路径的线性增长
    • 单层镜像:只需检查 upperdir + 1 个 lowerdir
    • 100 层镜像:最坏情况需检查 upperdir + 100 个 lowerdir
    • 时间复杂度:O(n)(n 为镜像层数)
  • 缓存失效问题
    • Page Cache 局限性:内核缓存(Page Cache)主要优化已访问文件的重复读取,但对首次查找路径无加速效果。
    • 负面案例:若频繁访问不同层级的文件(如容器启动时加载分散在各层的 .so 库),会导致大量目录项(dentry)缓存未命中。

5.2.2 文件与目录的删除逻辑

(1) 文件删除

容器内删除文件时,会在容器层(upperdir)创建空白文件(whiteout file)。镜像层(lowerdir)中的原始文件仍保留(因其只读属性),但空白文件会阻止容器访问该文件

(2) 目录删除

容器内删除目录时,会在容器层生成不透明目录(opaque directory)。其作用机制与空白文件类似,即使该目录仍存在于镜像层,容器也无法访问

5.2.3 目录重命名的限制条件

仅当源路径和目标路径均位于容器顶层(upperdir)时,才能成功调用rename(2)进行目录重命名。否则系统将返回EXDEV错误("跨设备链接不允许")。应用程序需设计相应的异常处理机制,通常需回退到"复制+解除链接"的替代方案。

  • 首次写入采用copy_on_write机制,保持镜像层不可变性
  • 空白文件实现原理:通过字符设备c 0 0标记实现删除效果
  • EXDEV错误源于OverlayFS的存储架构特性,需应用层特殊处理


虽然目录的 rename(2) 系统调用本身受 EXDEV 限制,但 OverlayFS 在用户态模拟了跨层重命名:先通过 copy_up 将整个目录树复制到 upperdir。然后在 upperdir 内部执行原子性重命名


6 参考资料

  • [1] https://docs.docker.com/engine/storage/drivers/overlayfs-driver/

相关推荐

F103C8T6移植FATFS文件系统 版本R0.15

STM32F103C8T6芯片在W25Q64上移植FATFS(版本R0.15)实现过程:1、首先完成USART初始化和调试,用于传输信息到串口调试软件。2、完成SPI相关参数配置及调试,用于单片机和存...

stm32使用MPU6050或ADXL345控制的车辆减速灯

本实验例程采用MPU6050六轴运动处理组件...

STM32F103串口输出prtinf覆盖(stm32printf函数的串口输出)

采用正点原子的板子,有如下坑,记录如下:(1)main中应用头文件#include"stdio.h"(2)采用hal进行fputc和fgetc覆盖,如下intfputc(intc...

STM32 学习8 USART串口通讯与printf重定向

一、串口通信介绍STM32F103ZET6包含多个UART、USART串口。...

教你如何使用SEGGER RTT优雅的实现日志系统

今天开始了BMS系统的软件代码部分的搭建,计划是分成三层:硬件驱动,AFE层和系统应用层。第一步肯定是先把底层的IIC通信调通,CG861xx的IIC通信和TI的BQ769X0...

终极调试利器,各种Link通吃(link4a调制方式)

今天继续更新一期KEIL调试方法。事实上,关于调试方法,鱼鹰写了一个系列,汇总文为《佛祖保佑,永无BUG,永不修改|KEIL调试系列总结篇》,对于KEIL方法感兴趣的可以看看。这个调试...

在 STM32 中使用 printf() 函数,别漏掉这几行代码!

问:在STM32上轻松使用printf函数除了点亮LED外,向串行控制台发送打印信息可能是调试嵌入式项目时最简单、最直接且最常用的技术。虽然大多数平台都拥有可以在UART总线上传输数据的API,但它们...

高性能异步io机制:io_uring(异步io select)

io_uring是linux内核5.10引入的异步io接口。相比起用户态的DPDK、SPDK,io_uring作为内核的一部分,通过mmap的方式实现用户和内核共享内存,并基于m...

精品博文ARM中打印函数print 的几种实现方法

1利用C库函数printf步骤:1)首先需要包含头文件stdio.h。2)然后定义文件句柄。实际上就是一个int型变量封装在结构体中。struct__FILE{inthandle;};3)定...

C语言char的详解(c语言(char))

在C语言中,char是一种基础数据类型,用于表示字符或小整数值。对char的理解和处理非常重要,尤其是在字符串操作、文件读写或其他需要直接控制内存的应用场景中。下面从基本定义、存储方式、常见用法...

C语言之文件操作(c语言文件操作实验总结)

文件操作是C语言中非常重要的功能,用于读取和写入文件中的数据。C语言提供了一组标准库函数(如fopen、fclose、fread、fwrite等)来实现文件操作。以下是针对C语言初学者的详细讲解。...

STM32-ADC如何把采集的数据转换为小数

编辑一、代码原理解析这段代码围绕“STM32中ADC数据采集、整数与小数计算及串口输出”展开,核心是数据类型的使用(unsignedint/signedint/float)、ADC数...

循环队列原理及在单片机串口通讯中的应用(二)

前言书接上回,前文主要介绍了环形队列的实现原理以及C语言实现及测试过程,本文将回归到嵌入式平台的应用中,话不多说,淦,上干货!...

STM32编程中printf函数重定向背后的原理

  在C语言中,printf是一个非常好用的函数,尤其是在程序调试阶段,我们可以通printf打印变量的值来帮助查错。在学习C语言的时候我们的开发环境和运行环境都是PC机,printf函数打印到PC机...

MySQL 避坑指南之隐式数据类型转换

...