docker images 的 size 是各镜像层逻辑展开总和(含重复),而 du -sh 统计的是磁盘实际物理占用(共享层只存一份,含元数据、dangling 层等),故二者不一致。

docker images 显示的 SIZE 为什么和 du -sh 看到的不一致
因为 docker images 显示的是镜像层(layer)叠加后的逻辑大小,而 du -sh 统计的是磁盘上实际占用的存储空间——两者计算方式根本不同。
镜像层之间共享只读数据,docker images 的 SIZE 是各层内容“展开后”的总和(含重复),但磁盘上这些重复文件只存一份;而 du -sh /var/lib/docker/overlay2 算的是物理块占用,含元数据、空洞、未清理的 dangling 层等。
- 运行
docker system df -v才能看到真实磁盘使用 + 各镜像实际贡献的 layer 大小 - 刚
docker pull完一个镜像,docker images的 SIZE 通常比du小;但删掉几个旧镜像后,du可能远大于docker images总和——说明有 dangling 层残留 - overlay2 驱动下,
du -sh某个diff目录时,可能看到稀疏文件或硬链接,直接统计会失真
docker rmi 报错 “image is being used by running container” 却查不到对应容器
常见于容器已退出但未自动清理,或使用了 --rm 但启动失败残留了匿名容器引用。
关键不是看 docker ps,而是查所有容器状态,包括已停止的:
- 执行
docker ps -a | grep <image_id></image_id>,注意 IMAGE 列可能是<none></none>,得用docker ps -a --filter ancestor=<image_name_or_id></image_name_or_id> - 更可靠的方式是:运行
docker image inspect <image_id> -f '{{.Id}}' | xargs -I{} docker ps -a --filter ancestor={} -q | wc -l</image_id>,确认是否真被引用 - 如果输出为空但仍删不掉,可能是 build cache 或构建中临时镜像在引用——运行
docker builder prune(Docker 23.0+)或docker system prune --filter "until=24h"清理无主缓存
多阶段构建中 COPY --from=stage-name 为什么找不到 stage
stage 名必须严格匹配 FROM ... AS <name></name> 中的 <name></name>,且大小写敏感、不能含空格或特殊字符;更重要的是,stage 定义必须出现在 COPY --from 之前。
- 错误写法:
FROM alpine AS builder放在 Dockerfile 底部 → 构建时报invalid from flag value "builder": stage with name "builder" is not defined - 正确顺序:所有
FROM ... AS name必须在任何COPY --from=name之前,哪怕中间隔着注释或RUN -
--from不支持变量展开,COPY --from=${BUILD_STAGE}会当作字面量处理,直接报错 - 若想复用 stage 名,建议统一用小写字母+下划线,例如
build-env,避免和基础镜像名(如node:18)混淆
docker save 和 docker export 输出的 tar 包为什么不能互换使用
docker save 打包的是镜像(含元数据、layer、manifest),可被 docker load 恢复为完整镜像;docker export 导出的是容器文件系统快照(纯 tar,无历史、无元数据),只能解压查看或作为构建上下文,无法还原为镜像。
- 误用
docker export CONTAINER | docker load会报Error: invalid reference format—— 因为docker load期望的是镜像 tar,不是 rootfs tar - 需要迁移镜像到离线环境?用
docker save -o app.tar nginx:alpine,再docker load -i app.tar - 需要提取容器内某个配置文件?用
docker export CONTAINER > fs.tar,然后tar -xf fs.tar ./etc/nginx/conf.d/default.conf -
docker save输出体积通常更大(含压缩层),docker export更小但不可逆;两者都不保留容器运行时状态(如网络命名空间、挂载点)
镜像优化真正的难点不在命令怎么敲,而在分清「构建时依赖」和「运行时依赖」——很多臃肿来自 COPY 了整个 node_modules 或 go build 缓存,却没在最终 stage 清理。这点光靠 docker system prune 解决不了。










