镜像分层是什么
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 的目录不写可写层:日志、缓存、数据库数据都应落在卷里;反过来,写进可写层的数据会随容器删除一起消失。