镜像与容器是“只读层+可写层”的动态挂载关系,非复制;镜像由多个只读层(按dockerfile指令生成、sha256标识、dag结构)叠加构成,共享基础层;容器启动时添加独立可写层记录运行时变更,通过联合文件系统呈现统一视图。

镜像和容器在底层是通过“只读层 + 可写层”的叠加结构紧密关联的,不是复制关系,而是运行时动态挂载的关系。
镜像本质是一组只读层的叠加
每个镜像由多个只读文件系统层(Layer)构成,每层对应 Dockerfile 中一条指令(如 FROM、RUN、COPY)。这些层按顺序堆叠,通过联合文件系统(如 overlay2)合并成一个统一视图。底层共享机制让不同镜像可复用相同基础层(比如多个应用都基于 ubuntu:22.04,只需存一份基础层)。
- 所有层都是只读的,不可修改
- 层与层之间通过唯一 SHA256 ID 关联,形成有向无环图(DAG)结构
- 镜像顶层附带一个 JSON 配置文件,描述默认启动命令、环境变量、工作目录等运行时元数据
容器 = 镜像层 + 一个可写层(Container Layer)
执行 docker run 时,Docker 守护进程不会复制整个镜像,而是在镜像最上层动态添加一个全新的、空的可写层(也叫 “container layer” 或 “top layer”)。这个层专用于记录容器运行时的所有变更:
- 写入新文件、修改配置、安装临时软件,都发生在此层
- 读取文件时,从上层往下查找——可写层命中则返回;未命中则穿透到下层只读镜像层
- 删除文件时,采用“覆盖删除”(whiteout)机制:在可写层标记该路径为已删,屏蔽底层同名文件
生命周期解耦:镜像不变,容器可变
镜像一旦构建完成就固定不变;容器启动后所有运行态改动仅影响其专属可写层,与原始镜像完全隔离:
- 重启容器:可写层保留(除非使用 --rm 或 tmpfs 挂载)
- 停止并删除容器:可写层随之销毁,镜像毫发无损
- 用 docker commit 把容器当前状态保存为新镜像:实质是把该容器的可写层打包,再叠加到原镜像层之上,生成新层
底层存储位置与驱动协同
镜像层和容器层实际存储在宿主机的 /var/lib/docker/overlay2/(以 overlay2 驱动为例)目录下,各自有独立子目录:
- 镜像层存于
diff/子目录,带layerdb/元数据索引 - 容器可写层存于
diff/下对应容器 ID 的目录中 - 联合挂载点(merged)由内核通过 overlayfs 实现,对容器进程呈现为完整根文件系统











