多阶段构建:把 Python 服务镜像从 1GB 瘦下来

举报
yd_256507724 发表于 2026/11/04 10:01:16 2026/11/04
【摘要】 很多团队第一次把 Python 服务打进 Docker,镜像动辄七八百兆甚至超过 1GB。拉取慢、发布慢,漏洞扫描还总是红一片。体积大通常不是业务代码的错,而是基础镜像、构建工具和缓存层叠在了一起。下面按一条可复现的排查顺序,把镜像瘦下来。先看现状。在构建机上执行 docker image ls,记下目标镜像的大小;再用 docker history 看每一层新增了多少。如果某一层突然增加几...

很多团队第一次把 Python 服务打进 Docker,镜像动辄七八百兆甚至超过 1GB。拉取慢、发布慢,漏洞扫描还总是红一片。体积大通常不是业务代码的错,而是基础镜像、构建工具和缓存层叠在了一起。下面按一条可复现的排查顺序,把镜像瘦下来。

先看现状。在构建机上执行 docker image ls,记下目标镜像的大小;再用 docker history 看每一层新增了多少。如果某一层突然增加几百兆,多半是 apt 或 pip 安装时把编译器和缓存留在了同一层。history 只能看到层大小,看不到具体文件。这时进入容器,用 du -h -d 1 / 就能定位是 /usr、/root/.cache 还是 /var/lib/apt。

第二步换基础镜像。开发阶段可以用 python:3.12,里面带 gcc 和头文件,方便安装带 C 扩展的包。发布阶段不要沿用这张镜像。python:3.12-slim 基于 Debian slim,一般能少掉一半以上。若依赖都很纯,可以试 python:3.12-alpine,体积更小,但 musl 会让部分带预编译轮子的包装不上,一报错就退回 slim,不要硬刚。

第三步用多阶段构建。第一阶段命名为 builder,安装编译依赖,并用 pip install --prefix=/install 把依赖装到独立目录。第二阶段只从 slim 开始,用 COPY --from=builder 把 /install 拷到 /usr/local,再复制业务代码。编译器、wheel 缓存和 apt 列表都留在 builder,不会进入最终镜像。注意不要在最终阶段再跑一次 pip install,否则前面的瘦身等于白做。

第四步管好层缓存和垃圾文件。把 requirements.txt 单独 COPY,然后再 COPY 源码,这样改一行业务代码不会让依赖层失效。同一条 RUN 里安装完立刻删除缓存:清理 apt 列表和 /root/.cache。拆成两条 RUN 再删除是没用的,因为前一层已经提交。另外准备一份 .dockerignore,排除 .git、虚拟环境、pycache、测试目录和本地 .env,避免把虚拟环境和密钥打进镜像。

第五步用非 root 运行。在最终阶段创建普通用户,把应用目录授权给它,再用 USER 切换。这不直接减小体积,但能减少扫描里的高危项,也避免容器被突破后直接拿到 root。

最后做验收。同一份代码分别用单阶段和多阶段构建,对比 docker image ls 的大小,并用同一条启动命令跑健康检查。瘦身前后接口行为应一致。一个 FastAPI 示例里,镜像从大约 1.05GB 降到大约 180MB,家庭带宽下拉取时间从两分钟降到二十秒左右。数字会随依赖变化,方法是稳定的:先定位大层,再把构建工具关在 builder 里,最终镜像只保留运行时需要的文件。

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

评论(0)

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

全部回复

上滑加载中

设置昵称

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

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

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