首页/云/云与容器速查/镜像分层与写时复制
容器与 Docker106 条

镜像分层与写时复制

镜像由只读层叠加而成,容器启动时加一个可写薄层:相同层在多个镜像间共享,改文件触发写时复制。层设计直接决定拉取速度与镜像体积。

云与容器速查云更新于 2026-10-13

镜像分层是什么

Docker 镜像不是一个大文件,而是由若干只读层叠加成的清单:Dockerfile 里每条 FROM、RUN、COPY、ADD 等指令各产生一层,容器启动时在顶层再加一个可写薄层。读文件时按层自上而下查找,改文件时由存储驱动触发写时复制(CoW),把整份文件从只读层复制到可写层。这套机制决定镜像体积、拉取速度与磁盘占用:层能在不同镜像间共享,但用错方向会让体积迅速膨胀。

基本信息

适用平台Docker/Podman 等 OCI 运行时,Linux 上默认 overlay2 存储驱动
层的来源Dockerfile 每条会产生文件系统改动的指令各生成一层
可写层容器创建时新增,容器删除即消失,不会回到镜像里
写时复制修改来自下层的大文件会整份复制到可写层,吃空间
共享同一基础镜像的镜像与容器共享底层,省磁盘省拉取
查看docker history 看逐层体积,docker inspect 的 RootFS.Layers 看层 ID

典型使用场景

  • 排查镜像为什么大:先看层数与各层体积,定位是哪条指令引入的
  • 优化拉取速度:把变动频繁的指令放到后面,稳定的依赖层可被缓存复用
  • 判断容器里改动的去向:确认哪些文件进了可写层、哪些该挂卷
  • 多项目共享同一基础镜像:底层只拉一次,整体分发更快
  • 写 Dockerfile 时决定 RUN 合并还是拆分:层数与缓存命中率之间取舍

查看层构成

查看层构成
docker history nginx:1.27-alpine   # 逐层看指令与新增体积
docker inspect nginx:1.27-alpine --format '{{len .RootFS.Layers}}'   # 只看层数
docker image inspect myapp:1.2.3 --format '{{json .RootFS}}' | head -c 300   # 看层摘要
docker system df -v | head -20   # 看镜像的共享与独占体积
docker diff myapp   # 看某容器相对镜像改了哪些文件

输出逐列读法

列含义正常/异常
IMAGE层 ID(截断显示)多个镜像里出现同一 ID 说明层被共享
CREATED该层构建时间时间错乱通常来自缓存复用或旧层被改写
CREATED BY生成该层的指令出现 RUN 里的大体积写出即为膨胀源头
SIZE该层新增体积单层上百 MB 就该检查是否误带了数据
COMMENT构建时的说明注释为空属正常,来自 commit 的层常带说明
overlay2 下同一个文件被多个镜像共享时磁盘只存一份:删镜像前先看共享列,否则会误判能回收多少空间。
挂了卷或 tmpfs 的目录不写可写层:日志、缓存、数据库数据都应落在卷里;反过来,写进可写层的数据会随容器删除一起消失。

易错点

  • 在容器里改大文件再 commit:可写层把整份文件复制一遍,镜像体积成倍增长且内容无法复现
  • 把几十 GB 数据集 COPY 进镜像:层体积等于数据体积,推送拉取慢到不可用,正确做法是运行时挂卷
  • 以为删掉文件就能减体积:删除只在下层记录白盒,镜像大小不变,需要重建镜像或多阶段构建
  • 在 RUN 里先装编译工具再删:删除发生在同一层,工具仍占空间,应把编译与运行拆到不同 FROM 阶段

数据来源与参考

  • Docker Docs:Images and layers
  • Docker Docs:Storage driver

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌