You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

原因分析

  1. Docker分层存储机制:Docker镜像由多个只读层叠加而成,每一条RUN、COPY指令都会生成新层。删除文件的操作只会在当前层标记文件为"已删除",底层的原始文件依然存在并被计入镜像总大小。比如你在RUN中删除了/source,但基础镜像detector-src-2cd5a61.img中的/source目录仍在底层层中,不会被回收。
  2. 多层叠加导致体积累加:你的操作流程中,先移动/build、删除/source(生成一层),然后COPY新的/source目录(新增一层),再移回/build并执行构建(又新增一层),多层内容叠加后总大小被累加,而容器内看到的是最终层的文件状态,因此实际占用远小于镜像显示大小。
  3. 中间层残留临时产物:构建过程中产生的临时文件(如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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 12:17:54