核心是安装与清理必须在同一RUN指令中完成,用&&连接apt-get update、install、clean及rm命令,并优选alpine或distroless基础镜像,配合多阶段构建和.dockerignore优化镜像体积。

核心就一条:安装和清理必须在同一个 RUN 指令里完成。Docker 的分层机制决定了,哪怕你下一行就 RUN rm -rf /var/lib/apt/lists/*,缓存文件也早已固化在上一层中,删不掉。
合并安装与清理,一步到位
apt-get 下载的包文件、索引缓存、临时目录都会留在镜像里,必须在同一层中清除:
- 用
&&连接所有操作,确保原子性 - 加上
--no-install-recommends避免装一堆非必要依赖 - 执行
apt-get clean清除/var/cache/apt/archives/下的 deb 包 - 再用
rm -rf /var/lib/apt/lists/*删除包索引 - 顺手清掉
/tmp和/var/tmp更稳妥(尤其构建中用过临时下载)
示例写法:
RUN apt-get update \&& apt-get install -y --no-install-recommends curl wget \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
别用通用基础镜像硬扛
ubuntu 或 debian 镜像自带大量系统工具和库,光基础层就 70MB 起。apt 安装越多,冗余越明显。
- 生产环境优先选
alpine:latest(约 5MB),改用apk add --no-cache - 对安全性要求高的服务,直接上
gcr.io/distroless/base,无 shell、无包管理器,只留运行时必需 - 静态编译程序可考虑
scratch,零基础体积,完全自包含
多阶段构建切掉整个构建环境
如果项目需要编译(比如 Go、Rust、C++),千万别把 gcc、make、头文件全塞进最终镜像。
- 第一阶段用完整镜像(如
golang:1.21)编译出二进制 - 第二阶段换极小镜像(如
alpine或distroless) - 只用
COPY --from=builder复制产物,其余一概不带
这样能避开 90% 的 apt 相关体积问题——因为最终镜像压根不用 apt。
检查构建上下文是否偷偷塞了东西
就算 Dockerfile 写得再干净,如果 docker build . 时传入了大量无关文件,也会间接影响 COPY 行为或触发缓存失效。
- 务必配好
.dockerignore,至少过滤掉node_modules/、__pycache__/、.git/、*.log - 避免在 Dockerfile 里
COPY . .,只复制真正需要的文件或子目录 - 确认没有在 RUN 中隐式下载大文件后又没清理(比如 curl + tar + rm 分三行)


















