Docker存储驱动OverLay2介绍(docker evicted)
wptr33 2025-07-06 17:18 4 浏览
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/
相关推荐
- 抢先体验Windows 10 20H2新功能,该怎样操作呢?
-
Win10系统通常会在一年当中进行两次重大更新,分别于上下半年分别推出。上半年的更新主要针对功能的变化,而下半年则是提升系统稳定性。最近Win10下半年最重要的更新Windows1020H2已经开...
- 教程:如何关闭Win10/Win8.1/Win7管理共享
-
教程:如何关闭Win10/Win8.1/Win7管理共享出处:IT之家原创(晨风)默认情况下,Windows会创建一些隐藏的共享文件夹,这些文件夹在名称的末尾都有美元“$”标志。当用户在文件资源管理...
- Win11学院:如何强制让Windows 11设备蓝屏
-
IT之家12月15日消息,在Win11系统中蓝屏(BSoD)也称为“停止错误”(StopError)和“错误检查”(BugCheck),通常情况下只有在遇到关键问题的时候才会出现。显然...
- 微软承认Windows 10新BUG:错误显示没有网络连接
-
来源:cnBeta.COM在7月补丁星期二活动中,微软发布的累积更新已经修复Windows10系统中的大量BUG。不过近日,微软承认了存在于Windows10May2020(20H...
- 一课译词:双标(双标英文怎么写)
-
PhotobyMarkusSpiskeonUnsplash“双标[shuāngbiāo]”,网络流行语,完整说法是“双重标准”,翻译为“doublestandard”。“双标”是指“对同...
- 知识科普:USB端口如何禁用和解锁?
-
2015-07-3005:32:00作者:赵为民经常有人会说,我要保护我的笔记本电脑的USB端口,在未经授权的情况下不能够访问。是否有专业的软件可以将USB端口锁死,然后在需要的时候解锁呢?是的,...
- 小迈科技 X Hologres:高可用的百亿级广告实时数仓建设
-
通过本文,我们将会介绍小迈科技如何通过Hologres搭建高可用的实时数仓。一、业务介绍...
- Modbus-RTU通信(modbus rtu rtu over tcp)
-
通常情况下我们做Modbus通信的时候,都会先用测试软件进行测试,等通信测试通过之后,我们才会进行移植,我这边主要讲的是移植到PLC上,我现在这边还没有开始做PLC程序,那先把前期的用测试软件如何测...
- 警惕!利用Github进行水坑攻击安全风险通告
-
2022年5月19日,亚信安全CERT监测发现Github账户为rkxxz的用户发布了CVE-2022-26809和CVE-2022-24500的项目,项目内容介绍为:CVE-2022-26809...
- 手机越用越慢?小编教你如何用黑狱冰箱调教它!
-
看完智趣狗昨天推送的《看完秒懂!这就是Android手机越用越卡的原因!》一文后,我们不难知晓手机越用越慢多是体量更大的APP,以及APP之间相互唤醒而导致资源过度消耗引起的。所以,想让手机恢复高效率...
- 秒杀系统—3.第二版升级优化的技术文档一
-
大纲1.秒杀系统的服务细分和服务定位...
- Redis命令介绍(二十五)HSET & HSETNX
-
HSET将上送的键值对保存在key中存储的哈希表中。如果key不存在则创建一个新的哈希表。如果key已存在,则覆盖。在4.0版本后,HSET支持同时上送多键值对。...
- IDEA用上这十大插件就很舒服(intellij idea插件推荐)
-
本文翻译自国外论坛medium,原文地址:https://medium.com/@xjpp22/top-10-plugins-for-intellij-idea-you-dont-want-to-m...
-
- 常用 Git 命令清单(git常用命令速查表)
-
下面是整理的常用Git命令清单。几个专用名词的译名如下。...
-
2025-07-07 23:38 wptr33
- GitHub|清晰理解本地目录、暂存区、本地仓库、远程仓库的交互
-
GitHub是一个在线平台,旨在促进在一个共同项目上工作的个人之间的代码托管、版本控制和协作。通过该平台,无论何时何地,都可以对项目进行操作(托管和审查代码,管理项目和与世界各地的其他开发者共同开发...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
git pull命令使用实例 git pull--rebase
-
面试官:git pull是哪两个指令的组合?
-
git 执行pull错误如何撤销 git pull fail
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 之后本地代码被覆盖 解决方案
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git命令之pull git.pull
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)