Linux Docker 镜像管理与优化

13次阅读

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

Linux Docker 镜像管理与优化

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 解决不了。

text=ZqhQzanResources