python:3.9-slim是最稳妥的基础镜像,因alpine的musl libc导致numpy等包需源码编译而失败,多阶段构建须严格分离builder(装build-essential)与runner(仅copy site-packages和代码),并强制--no-cache-dir、清理.pyc和__pycache__、配.dockerignore、剔除dev依赖。

python:3.9-slim 是当前最稳妥的起点,不是 alpine,也不是完整版 python:3.9。选错基础镜像,后续所有优化都事倍功半。
为什么不能用 python:3.9-alpine?
不是体积小就一定好。Alpine 用 musl libc,而绝大多数 Python 包(尤其是 numpy、psycopg2、pydantic)只提供 glibc 兼容的预编译 wheel。结果就是:pip install 强制源码编译——卡住、报错 fatal error: Python.h: No such file or directory、漏装 gcc 或 musl-dev。常见现象包括:
-
pip install psycopg2卡在编译阶段 - 构建时间比
slim多 2–3 倍 - 运行时报
ImportError: libpq.so.5: cannot open shared object file
多阶段构建必须拆开 builder 和 runner 阶段
光写两个 FROM 不算真正多阶段。关键在于:builder 阶段可以装 build-essential,runner 阶段必须彻底剥离它们——最终镜像里连 gcc 的二进制文件都不能存在。实操要点:
- builder 阶段用
python:3.9-slim,不要用alpine - 合并安装与清理:
RUN apt-get update && apt-get install -y --no-install-recommends build-essential && apt-get clean && rm -rf /var/lib/apt/lists/* - runner 阶段必须是独立的
FROM python:3.9-slim - 只
COPY --from=builder两个路径:/usr/local/lib/python3.9/site-packages和你的代码目录,别复制整个/usr/local - runner 阶段禁止再执行
RUN pip install,否则依赖会重复进一层
--no-cache-dir 和清理 __pycache__ 是硬性要求
pip 默认把 wheel 缓存在 /root/.cache/pip,这个路径不属 SITE-PACKAGES,但会固化进镜像层。不清理,单缓存就能占 100MB+。正确写法必须是原子性的一条 RUN:
RUN pip install --no-cache-dir -r requirements.txt \ && find /usr/local/lib/python3.9/site-packages -name "*.pyc" -delete \ && find /usr/local/lib/python3.9/site-packages -type d -name "__pycache__" -delete
注意:--no-cache-dir 必须显式加,find 命令要覆盖 .pyc 文件和整个 __pycache__ 目录。
容易被忽略的“隐形体积”来源
很多团队优化到一半就停了,因为没意识到这些点:
-
.dockerignore没配:日志、__pycache__、.git、venv被打包进构建上下文,触发无谓的COPY层 - requirements.txt 里混了开发依赖(如
pytest、mypy),却在 runner 阶段全装 - 用
COPY . .而不是选择性复制,把测试文件、文档、配置模板全塞进去 - 没删掉
apt缓存残留:/var/lib/apt/lists/*占几十 MB,且不会被后续RUN rm自动清理
真正压到 100MB 以内,靠的不是某一个技巧,而是每一步都做“减法”——删掉所有非运行必需的东西,哪怕只有几 MB。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











