Docker镜像采用分层架构,每条有效指令(如FROM、RUN、COPY)生成一个只读层,层按序叠加并通过UnionFS联合挂载为统一视图,支持缓存复用、体积优化与差异传输。

Docker 镜像层叠架构不是抽象概念,而是可观察、可验证的文件系统行为。掌握它不需要背理论,关键在于理解“每一层 = 一次变更快照”这个核心逻辑,并通过命令和构建过程反复印证。
从 Dockerfile 指令看层怎么生成
每条有效指令(FROM、RUN、COPY、ADD)都会产生一个新层,但并非所有指令都创建实际文件变更: - FROM:拉取基础镜像,作为最底层(如 alpine:3.18 或 ubuntu:22.04) - RUN:执行命令并持久化结果(如 apt install、pip install),生成含二进制/库的新层 - COPY / ADD:把本地文件或远程资源复制进镜像,新增文件即新增层 - ENV、LABEL、EXPOSE:元数据指令,不改变文件系统,通常不单独成层(部分版本会合并为轻量层)注意:指令顺序直接影响层内容和缓存效果。比如把 COPY . /app 放在 RUN pip install -r requirements.txt 前面,会导致每次代码变动都失效依赖层缓存。
建议动手试:写一个两行 Dockerfile(FROM alpine && RUN apk add curl),用 docker build --no-cache -t test . 构建后,再加一行 COPY hello.txt /,重新构建,用 docker history test 查看新增了一层。
用命令直观看到层结构
不用猜,直接查镜像内部层级: - docker history <image-name>:列出各层大小、创建时间、对应指令,最上面是顶层 - docker image inspect <image-name> --format='{{json .RootFS.Layers}}':输出每层的 SHA256 摘要,这是层的唯一身份标识 - docker save <image-name> | tar -t | head -20:解包镜像,看到实际 layer.tar 文件,确认层是独立归档单元这些输出能验证“层是只读、按序叠加、内容哈希寻址”的事实,比读文档更可靠。
理解联合挂载(UnionFS)怎么让层“合起来”
镜像本身不运行,真正起作用的是容器启动时的联合挂载机制: - 所有镜像层被挂为 lowerdir(只读堆栈) - 容器运行时新增一个 upperdir(可写层),所有写操作(如日志、临时文件)都在这里 - mergedir 是最终呈现给进程的统一视图,底层文件未被修改,只是被上层文件“遮盖”这意味着:你删掉一个底层存在的文件,其实是上层生成一个“whiteout”标记;你改配置,本质是在 upperdir 写新文件,原文件仍在下层完好无损。
拿真实问题反推层设计的价值
遇到以下情况,就该回头想层原理: - 构建变慢 → 检查哪一层缓存失效(docker build 输出里看 “Using cache” 是否中断) - 镜像太大 → 用 docker history 找出臃肿层(比如某 RUN 指令装了调试工具却没清理) - 多个服务镜像共存磁盘占用小 → 因为它们共享相同的基础 OS 层和通用依赖层 - 推送/拉取快 → 远程仓库只传差异层,相同层跳过传输不复杂但容易忽略


















