OverlayFS是什么?容器镜像分层原理

本文聚焦容器镜像分层原理场景,从 OverlayFS、联合挂载、写时复制、容器可写层和镜像构建优化等维度展开,帮助团队理解镜像复用、启动速度和体积治理。

OverlayFS是什么,是理解 Docker 镜像为什么能快速构建、快速分发和快速启动的关键问题。很多人知道 Docker 镜像由多层组成,也知道容器会在镜像之上增加一个可写层,但如果不了解 OverlayFS,就很难解释这些层如何被组合成一个看起来完整的文件系统。OverlayFS 是 Linux 内核中的联合文件系统能力,它可以把多个目录叠加成一个统一视图,让上层目录覆盖下层目录,并通过写时复制机制处理文件修改。

在容器场景中,镜像层通常是只读的,容器运行时会在只读镜像层之上增加一个可写层。应用在容器内看到的是一个完整根文件系统,但实际写入会落到容器自己的可写层中,而不会修改底层镜像。这种设计让多个容器可以共享同一组镜像层,同时各自保持运行时变更互不影响。

OverlayFS 叠加镜像层与容器可写层

为什么容器镜像需要分层

如果每个容器镜像都是一个完整的大文件,构建、传输、存储和回滚都会非常低效。分层镜像解决了几个实际问题。

第一,减少重复存储。不同应用可能都基于同一个 Linux 发行版、同一套语言运行时或同一组基础依赖。把这些内容拆成层后,多个镜像可以复用同样的底层内容,不必重复保存。

第二,提高构建效率。Dockerfile 中每个会产生文件系统变更的指令通常会形成新的镜像层。当上层代码变化而底层依赖不变时,构建过程可以复用缓存,只重新构建变化部分。

第三,提升分发效率。镜像仓库和节点拉取镜像时,可以只下载本地缺失的层。对于大规模 Kubernetes 集群,这会明显降低网络传输和镜像拉取时间。

第四,增强版本可追溯性。镜像层具有内容摘要,镜像整体可以通过 manifest 组合引用这些层。相比把所有文件打包成一个不透明对象,分层模型更利于缓存、校验和治理。

容器镜像相关内容可以归入 容器镜像 方向理解;而 OverlayFS 则是连接镜像分层与容器运行时文件系统的底层机制。

OverlayFS 的核心概念:lower、upper、work、merged

OverlayFS 的模型并不复杂,但几个目录角色必须分清。

  • lowerdir:下层目录,通常对应只读镜像层,可以有多个。
  • upperdir:上层目录,通常对应容器可写层,用于保存新增或修改后的文件。
  • workdir:OverlayFS 工作目录,内核用于处理原子操作和内部状态。
  • merged:合并后的挂载点,容器进程最终看到的文件系统视图。

当容器读取文件时,OverlayFS 会先查看上层是否存在对应文件;如果上层没有,再到下层查找。这样一来,上层可以覆盖下层同路径文件。对于容器内进程来说,它看到的是 merged 目录,不需要知道文件到底来自哪个镜像层或可写层。

当容器修改下层已有文件时,OverlayFS 通常会先把该文件从 lowerdir 复制到 upperdir,再在 upperdir 中修改,这就是写时复制。删除文件也不是直接删除只读下层内容,而是在 upperdir 中创建特殊标记,让 merged 视图中不再显示该文件。

写时复制为什么重要

写时复制是容器文件系统高效运行的关键。它的价值体现在三个方面。

首先,它让镜像层保持不可变。镜像一旦构建完成,就可以被多个容器共享。容器运行中的写入只影响自己的可写层,不会污染镜像本身,也不会影响其他基于同一镜像启动的容器。

其次,它降低启动成本。启动容器不需要复制完整镜像,只需要准备挂载关系和可写层。相比复制一个完整根文件系统,联合挂载更轻量。

再次,它让运行状态与交付产物分离。镜像是交付产物,容器可写层是运行时状态。生产实践中通常不建议把重要数据长期保存在容器可写层,而应使用卷、对象存储、数据库或其他持久化方案。

OverlayFS 读取、修改与删除路径

Docker 中 overlay2 与镜像层的关系

Docker 在 Linux 上常见的存储驱动是 overlay2。它基于 OverlayFS,并支持多个 lowerdir。相比早期 overlay 驱动,overlay2 对多层镜像支持更自然,也成为很多发行版和容器环境中的默认选择。

一个镜像可能由多个只读层组成:基础系统层、软件包层、运行时层、依赖层、应用代码层等。容器启动时,overlay2 会把这些只读层按顺序作为 lowerdir,再创建容器专属 upperdir 和 workdir,最后挂载出 merged 目录作为容器根文件系统。

这也解释了为什么多个容器可以基于同一个镜像启动而互不影响。它们共享 lowerdir,但拥有不同 upperdir。容器删除后,可写层通常会随容器生命周期清理;镜像层则仍可保留,供其他容器或后续启动复用。

在 Kubernetes 中,节点上的 containerd、CRI-O 等运行时也会管理镜像层、快照和容器可写层。不同运行时实现细节可能不同,但“只读镜像层 + 可写运行层”的思路是一致的。

镜像层设计会直接影响构建速度和体积

理解 OverlayFS 后,再看 Dockerfile 优化就会更有方向。镜像层不是越多越好,也不是越少越好,关键在于把变化频率不同的内容合理分层。

常见优化原则包括:

  1. 把基础系统和语言运行时放在较低层,减少重复构建。
  2. 把依赖安装放在应用代码复制之前,让依赖层更容易命中缓存。
  3. 使用多阶段构建,把编译环境和运行环境分离。
  4. 在同一层内完成安装和清理,避免无用缓存残留在历史层中。
  5. 避免频繁变动的文件过早进入镜像层,例如构建时间戳、临时日志、大型测试产物。
  6. 使用明确版本的基础镜像,减少 latest 带来的不可控变化。

需要注意的是,删除文件不一定能减少已有层的体积。如果某个大文件在前一层被加入镜像,后一层再删除它,最终镜像历史中仍然可能包含该大文件。正确做法是在同一层内避免引入无用文件,或通过多阶段构建只复制最终产物。

容器可写层不适合保存关键数据

很多初学者会误以为容器里写入的文件就是镜像的一部分。实际上,运行时新增或修改的内容通常位于容器可写层,容器删除后这些内容也会消失。除非使用 docker commit 这类方式把可写层再固化成新镜像,否则运行时变更不会回写到底层镜像。

生产环境中应遵循以下边界:

  • 配置应通过环境变量、配置文件挂载或配置中心注入,而不是手工改容器内部文件。
  • 日志应输出到标准输出、日志采集系统或挂载卷,避免长期堆积在可写层。
  • 数据库、上传文件、模型文件等持久数据应放在卷或外部存储中。
  • 容器可写层应被视为临时运行空间,而不是可靠存储。

这一点对于 Kubernetes 尤其重要。Pod 被重建、调度到其他节点或容器被重新创建时,本地可写层不会天然保留。需要持久化的数据应使用 PVC、对象存储或其他存储系统。

容器镜像分层优化与运行数据边界

常见问题排查:镜像层与 OverlayFS 相关现象

当遇到镜像过大、构建缓存不生效、容器内文件修改异常或磁盘空间增长过快时,可以按以下方向排查。

第一,看 Dockerfile 层设计。频繁变化的 COPY 是否放得太靠前?依赖安装是否每次都被迫重新执行?临时文件是否在独立层中被保留下来?

第二,看容器可写层增长。日志、缓存、上传文件、临时文件如果不断写入容器层,会造成节点磁盘压力。应把这些路径迁移到挂载卷或外部系统。

第三,看镜像清理策略。节点上历史镜像层过多会占用大量磁盘,但清理时要避免删除正在运行容器依赖的层。Kubernetes 节点通常需要结合 kubelet 镜像 GC 策略和运行时清理机制。

第四,看底层文件系统支持。OverlayFS 对底层文件系统有一定要求,某些特殊文件系统、内核版本或挂载参数可能影响表现。生产环境应使用被发行版和容器运行时明确支持的组合。

FAQ:关于 OverlayFS 和镜像分层的深入问题

1. OverlayFS 和 Docker 镜像是一回事吗?

不是。Docker 镜像是一种打包、分发和描述应用文件系统的格式;OverlayFS 是 Linux 内核提供的联合挂载能力。Docker 或容器运行时可以利用 OverlayFS 把多个镜像层和容器可写层组合成运行时文件系统。

2. 为什么修改容器内文件不会改变镜像?

因为镜像层通常是只读的。容器修改文件时,OverlayFS 会把被修改文件复制到容器可写层,再在可写层中完成变更。底层镜像仍保持不变,这也是同一个镜像可以启动多个互不影响容器的原因。

3. Dockerfile 中删除文件为什么镜像还是很大?

如果大文件在前一层已经写入镜像,后一层删除它只是在新的层中记录删除效果,历史层中的内容仍可能存在。应在同一条 RUN 指令中完成安装、使用和清理,或使用多阶段构建避免把编译缓存、源码和临时文件带入最终镜像。

4. overlay2 是否总是最佳选择?

overlay2 是 Linux Docker 环境中非常常见且成熟的选择,但是否最佳仍取决于内核版本、发行版、底层文件系统和运行场景。大多数通用容器场景适合 overlay2;特殊高性能 IO、强持久化或安全隔离场景则需要结合存储方案整体评估。

5. Kubernetes 用户需要关心 OverlayFS 吗?

应用开发者不一定需要直接操作 OverlayFS,但平台团队和排障人员应该理解其原理。镜像拉取慢、节点磁盘被写满、容器重启后文件消失、构建缓存异常等问题,都与镜像层和可写层机制密切相关。

总结:OverlayFS 让镜像分层从概念变成运行时能力

理解 OverlayFS是什么,不只是为了掌握一个 Linux 文件系统名词,而是为了真正理解容器镜像分层原理。镜像层负责复用和分发,可写层负责承载运行时变更,OverlayFS 则把它们组合成容器进程看到的完整文件系统。对企业团队来说,掌握这一机制可以直接指导 Dockerfile 优化、镜像仓库治理、节点磁盘管理和 Kubernetes 容器运行问题排查。

转载请注明出处:https://www.cloudnative-tech.com/p/7316/

(0)
上一篇 1小时前
下一篇 1小时前

相关推荐