Docker镜像大小异常:显示20GB但内部实际不足10GB的问题问询
Docker镜像大小异常排查与解决
问题描述
遇到Docker镜像大小异常问题:镜像7976d82ebd9f显示大小为20GB,且镜像层大小持续增长,镜像列表如下:
<none> <none> 7976d82ebd9f 9 seconds ago 20GB <none> <none> 69b7404e0fa7 7 minutes ago 14.8GB <none> <none> 5553abaac35a 7 minutes ago 14.8GB <none> <none> c6b650ffd1e9 7 minutes ago 13.2GB <none> <none> 52c05db14947 9 minutes ago 9.33GB <none> <none> 6332544fea4b 9 minutes ago 9.33GB detector-src-2cd5a61.img latest 8a48f7c375cd 43 hours ago 9.33GB
但进入镜像内部查看,实际占用空间不足10GB,符合预期的构建+代码大小,目录占用详情:
root@f7b6e187e357:/# du -sh ./* 0 ./bin 4.0K ./boot 0 ./dev 1.8M ./etc 4.0K ./home 0 ./lib 0 ./lib32 0 ./lib64 0 ./libx32 4.0K ./media 4.0K ./mnt 698M ./opt du: cannot access './proc/11/task/11/fd/4': No such file or directory du: cannot access './proc/11/task/11/fdinfo/4': No such file or directory du: cannot access './proc/11/fd/3': No such file or directory du: cannot access './proc/11/fdinfo/3': No such file or directory 0 ./proc 16K ./root 84K ./run 0 ./sbin 6.3G ./source 4.0K ./srv 0 ./sys 4.0K ./tmp 1.9G ./usr 34M ./var
操作逻辑:在容器内重新构建,更新源码但保留build目录,代码已复制到detector-src-2cd5a61.img镜像中,删除旧源码目录,保留的build目录会被新构建覆盖,对应的Dockerfile:
1 FROM detector-src-2cd5a61.img as builder 2 MAINTAINER MPK Software <email@domain.dom> 3 ENV DEBIAN_FRONTEND=noninteractive 4 5 RUN mv /source/build /build \ 6 && rm -rf /build/ubuntu \ 7 && rm -rf /source 8 COPY . /source/ 9 WORKDIR /source 10 11 RUN mv /build /source/build \ 12 && cd build \ 13 && cmake -DCMAKE_BUILD_TYPE=Release \ 14 -DINSTALL_PREFIX=/usr \ 15 -DBUILD_TESTS=OFF ../ \ 16 && make -j $(nproc) \ 17 && make pack
原因分析
- Docker分层存储机制:Docker镜像由多个只读层叠加而成,每一条
RUN、COPY指令都会生成新层。删除文件的操作只会在当前层标记文件为"已删除",底层的原始文件依然存在并被计入镜像总大小。比如你在RUN中删除了/source,但基础镜像detector-src-2cd5a61.img中的/source目录仍在底层层中,不会被回收。 - 多层叠加导致体积累加:你的操作流程中,先移动
/build、删除/source(生成一层),然后COPY新的/source目录(新增一层),再移回/build并执行构建(又新增一层),多层内容叠加后总大小被累加,而容器内看到的是最终层的文件状态,因此实际占用远小于镜像显示大小。 - 中间层残留临时产物:构建过程中产生的临时文件(如cmake缓存、make中间目标文件)可能未被清理,这些文件会留在中间层中,进一步增大镜像体积。
解决办法
1. 使用多阶段构建(推荐)
通过多阶段构建丢弃所有构建中间层,只保留最终需要的产物,大幅降低镜像体积。示例:
# 第一阶段:完成构建 FROM detector-src-2cd5a61.img as builder MAINTAINER MPK Software <email@domain.dom> ENV DEBIAN_FRONTEND=noninteractive RUN mv /source/build /build \ && rm -rf /build/ubuntu \ && rm -rf /source COPY . /source/ WORKDIR /source RUN mv /build /source/build \ && cd build \ && cmake -DCMAKE_BUILD_TYPE=Release \ -DINSTALL_PREFIX=/usr \ -DBUILD_TESTS=OFF ../ \ && make -j $(nproc) \ && make pack # 第二阶段:生成最终镜像(使用干净的基础镜像) FROM ubuntu:20.04 # 替换为你需要的基础镜像 # 复制构建阶段的产物到最终镜像 COPY --from=builder /source/build/your-product.tar.gz /opt/ # 添加必要的环境配置、启动命令等
2. 合并构建与清理到同一RUN层
在同一个RUN指令中完成构建并清理临时文件,避免中间层残留大文件。示例:
FROM detector-src-2cd5a61.img as builder MAINTAINER MPK Software <email@domain.dom> ENV DEBIAN_FRONTEND=noninteractive COPY . /source/ WORKDIR /source RUN mv /source/build /build \ && rm -rf /build/ubuntu \ && rm -rf /source/* \ && mv /build /source/build \ && cd build \ && cmake -DCMAKE_BUILD_TYPE=Release \ -DINSTALL_PREFIX=/usr \ -DBUILD_TESTS=OFF ../ \ && make -j $(nproc) \ && make pack \ && rm -rf ../CMakeCache.txt ../CMakeFiles # 清理cmake临时文件
3. 优化COPY上下文
创建.dockerignore文件,排除不必要的大文件(如.git、日志、缓存、测试数据等),避免这些文件被COPY到镜像中。示例.dockerignore内容:
.git/ *.log tmp/ tests/test_data/
4. 复用基础镜像层
尽量避免移动或重复复制已有内容,直接复用基础镜像中的build目录,减少不必要的层生成。
内容的提问来源于stack exchange,提问作者noname7619
相关产品推荐
相关产品推荐

