Docker 多阶段构建入门:把 Python 应用镜像从 900MB 瘦身到 120MB

举报
yd_226544297 发表于 2026/11/10 15:18:41 2026/11/10
【摘要】 第一次给自己的 Python 小项目写 Dockerfile 时,我信心满满地执行了 docker build,看到镜像大小的那一刻却愣住了:一个只有几十行代码的 FastAPI 接口,镜像居然有 900MB。传到服务器要等半天,换个环境重新拉取又要半天。从那以后,我开始认真研究镜像瘦身,而多阶段构建是其中性价比最高的一招。 为什么镜像会越来越胖新手常写的 Dockerfile 大概是这个样...

第一次给自己的 Python 小项目写 Dockerfile 时,我信心满满地执行了 docker build,看到镜像大小的那一刻却愣住了:一个只有几十行代码的 FastAPI 接口,镜像居然有 900MB。传到服务器要等半天,换个环境重新拉取又要半天。从那以后,我开始认真研究镜像瘦身,而多阶段构建是其中性价比最高的一招。

为什么镜像会越来越胖

新手常写的 Dockerfile 大概是这个样子:从 python:3.12 出发,装 gcc、装依赖、复制代码,一气呵成。问题就藏在这里:编译某些依赖需要 gcc、make 这些构建工具,它们本身就有几百 MB;pip 安装时留下的缓存、下载的 wheel 包也会被一并打进镜像层。更关键的是,Docker 镜像是分层叠加的,某一层删掉的文件其实还占着空间,镜像只会越长越胖。

多阶段构建的核心思路

多阶段构建的做法很直观:把“构建”和“运行”拆成两个阶段。第一个阶段叫 builder,里面可以随便装编译工具、随便折腾;第二个阶段是最终的运行环境,只从 builder 里把真正需要的成果复制过来,其余一概不要。最终镜像里没有 gcc、没有 pip 缓存,只有一份干净的运行环境。

动手写一个两阶段 Dockerfile

假设项目结构很简单:一个主程序文件和一份依赖清单。

# 第一阶段:构建
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt

# 第二阶段:运行
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /install /usr/local
COPY main.py .
CMD ["python", "main.py"]

关键点有三处:一是基础镜像选用 slim 而不是完整版,底子就轻了几百 MB;二是 pip 加上 --no-cache-dir,不留安装缓存;三是 COPY --from=builder 只搬运装好的依赖,不搬运构建工具。构建完成后用 docker images 对比一下:单阶段写法约 900MB,两阶段写法一般能压到 120MB 左右。

三个新手最容易踩的坑

第一,忘记写 .dockerignore。把 .git、pycache、.venv、测试数据都排除在构建上下文之外,否则 COPY 命令会把本地杂物全带进镜像。第二,COPY 的顺序不对。先复制依赖清单再安装依赖,这样只有依赖变化时才会重新安装;如果先复制全部代码,改一行代码就要重新装一遍依赖,构建时间会翻倍。第三,运行时缺系统库。有的 Python 包依赖 libpq、libxml2 这类系统库,构建阶段里有、运行镜像里却没有,容器一启动就报错,记得在运行阶段单独安装所需的运行时库。

小结

多阶段构建并没有什么魔法,它只是把“做饭的厨房”和“端上桌的菜”分开:厨房可以乱,端上桌的必须干净。对初学者来说,记住一个模板就够了:builder 阶段装依赖,运行阶段只拿结果,再配上 slim 基础镜像和 .dockerignore,镜像体积立刻就能降一个数量级。下次写 Dockerfile,不妨先问自己一句:这一层进镜像的东西,运行时真的需要吗?

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。