真正起效的是「构建与运行环境分离」+「主动删非运行文件」,--no-cache-dir仅解决pip缓存;应选python:3.11-slim基础镜像,多阶段构建末尾须显式删除pip、tests、__pycache__及未声明依赖。

直接说结论:多阶段构建 + --no-cache-dir 是有效手段,但单独用它们几乎压不住 numpy/scipy 这类包的体积;真正起效的是「构建与运行环境分离」+「主动删非运行文件」,--no-cache-dir 只解决 pip 缓存这一个点,别指望它单挑 500MB。
为什么 --no-cache-dir 单独用效果有限
它只跳过 pip 自己的下载缓存(~/.cache/pip),但不碰以下内容:
- 编译产生的
.so文件、.a文件仍完整保留在site-packages中 - 每个包自带的
tests/、test_*.py、docs/目录照常复制 -
pip、setuptools、wheel二进制仍被装进venv/bin/ - Python 自带的
pyc缓存(__pycache__/)默认照常生成
多阶段构建中必须显式清理的 4 类文件
光靠 COPY --from=builder 复制整个 venv,会把 builder 阶段的“构建残留”全拖进最终镜像。必须在 builder 阶段末尾加清理步骤:
- 删包管理器:
RUN rm -f /opt/venv/bin/pip* /opt/venv/bin/easy_install* - 删测试代码:
RUN find /opt/venv/lib/python*/site-packages -name "tests" -type d -exec rm -rf {} + 2>/dev/null || true - 删 pyc 缓存:
RUN find /opt/venv -name "__pycache__" -type d -exec rm -rf {} + - 删未声明依赖:
RUN /opt/venv/bin/python -m pip uninstall -y $(/opt/venv/bin/python -m pip freeze | grep -v -F -f requirements.txt | cut -d= -f1 | tr '\n' ' ')
基础镜像选 python:3.11-slim,别碰 alpine
Alpine 上 numpy/scipy 必须源码编译,gcc/g++/gfortran 全得带上,builder 阶段反而更大,且容易因 musl libc 导致运行时报 ImportError: cannot open shared object file。实际对比:
Docker Hub (hub.docker.com)。此技能适用于所有 Docker Hub 操作,包括读取、创建、更新和删除数据。只要任务涉及 Docker Hub,就使用此技能。
立即学习“Python免费学习笔记(深入)”;
-
python:3.11-slim(Debian Bookworm):基础层 ~65MB,numpy wheel 直接安装,无编译开销 -
python:3.11-alpine:基础层 ~30MB,但装 numpy 后 builder 阶段膨胀到 400MB+,最终镜像未必更小 - 关键差异:
slim镜像支持apt-get autoremove --purge清构建工具,alpine的apk del对已链接的 .so 文件清理不彻底
最终镜像里还藏着什么你没删干净
即使做完以上所有操作,用 docker run -it --rm <image> du -sh /opt/venv/lib/python*/site-packages/* | sort -hr | head -10</image> 检查,常会发现:
-
numpy/.libs/下一堆libgfortran-*.so—— 这些是 runtime 依赖,不能删,但可确认是否重复(比如被 scipy 再装一遍) -
scipy/.libs/和numpy/.libs/内容高度重叠,说明没做依赖去重 -
pydantic或fastapi带的py.typed、pyproject.toml等元数据文件,纯开发用,删掉不影响运行
最省事的验证方式:启动容器后执行 /opt/venv/bin/python -c "import numpy, scipy, sklearn; print('ok')" —— 能过就说明删得够狠,也够准。

















