04_image/4.7_internal.md
Docker 镜像是怎么实现增量的修改和维护的?为什么容器启动如此之快?这一切都归功于 Docker 的镜像分层存储设计。
在之前的章节中,我们一直强调镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的。因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。
Docker 镜像并不是一个单纯的文件,而是由一组文件系统叠加构成的。
最底层的镜像称为 基础镜像 (Base Image),通常是各种 Linux 发行版的 root 文件系统,如 Ubuntu、Debian、CentOS 等。
当我们在基础镜像之上构建新的镜像时 (例如安装了 Nginx),Docker 并不是复制一份基础镜像,而是在基础镜像之上,新建一个层 (Layer),并在该层中仅记录为了安装 Nginx 而发生的文件变更 (添加、修改、删除)。
这种分层存储结构使得镜像的复用、分发变得非常高效:
ubuntu:24.04),那么宿主机只需要下载一份 ubuntu:24.04,所有镜像都可以共享它。我们要理解的一个关键概念是:镜像的每一层都是只读的 (Read-only)。
那么,既然镜像只读,容器为什么能写文件呢?
当容器启动时,Docker 会在镜像的最上层,添加一个新的 可写层 (Writable Layer),通常被称为 容器层。
flowchart TD
subgraph Container ["运行中的容器"]
direction TB
L4["容器层 (可写, Writable Container Layer)"]
L3["镜像层 (只读, Read-only Image Layer)"]
L2["镜像层 (只读, Read-only Image Layer)"]
L1["基础镜像层 (只读, Base Image Layer)"]
L4 --- L3 --- L2 --- L1
end
Note["所有的写操作都在容器层这里"] -.-> L4
这就是为什么:
Docker 镜像的每一层都有一个唯一的 ID,这个 ID 是根据该层的内容计算出来的哈希值 (SHA256)。这意味着:
Docker 使用联合文件系统 (Union FS) 与写时复制思路来实现这种分层挂载。传统的实现方式常见于 overlay2、aufs、btrfs、zfs 等存储驱动;而在 Docker Engine 29.0 及之后的全新安装中,默认镜像后端已经变为 containerd image store,它使用 snapshotter 来管理这些层。
版本背景:Docker Engine 29.0(发布于 2026 年 1 月)是一个重要版本分界点,在全新安装场景下默认启用 containerd image store 作为镜像存储后端。这对镜像管理、OCI 合规性和供应链安全都有深远影响。如果你的 Docker 版本低于 29.0,镜像存储仍使用传统的 classic store 路径。
虽然底层实现细节不同,但它们都遵循上述的 分层 + CoW 模型;因此,无论你看到的是 overlay2 还是 containerd snapshotter,理解镜像层、容器层和写时复制的方式都是一样重要的。
想要深入了解 Overlay2 等文件系统的具体实现原理,包括 WorkDir、UpperDir、LowerDir 等底层细节,请阅读 第十二章 底层实现 中的 联合文件系统 章节。