Docker 多阶段构建实战:把 Python 镜像从 900MB 瘦身到 120MB
上周我把一个几百行代码的 Python 小服务搬上容器,docker images 一看竟有 900MB。排查后发现问题不在业务代码,而在构建方式:基础镜像太重,构建工具和中间文件全留在了最终镜像里。改用多阶段构建后,同一份代码只剩 120MB 左右。这篇短文记录这次瘦身。
一、镜像为什么变胖
习惯从 python:3.12 完整镜像起手,它自带编译器和开发头文件,单基础层就有几百兆;pip install 又装了 gcc 等编译依赖,缓存和临时文件没有清理,也一层层留了下来。容器运行只需要最终产物,构建工具本来就不该跟着上船。
二、多阶段构建怎么做
把“构建”和“运行”拆开:第一阶段用完整镜像编译、安装依赖;第二阶段换干净的 slim 镜像,只把成果复制过来。Dockerfile 用 FROM … AS builder 命名第一阶段,再用 COPY --from=builder 搬文件,构建阶段装再多工具也不影响最终体积。
三、可以直接用的例子
项目只有主程序文件和依赖清单文件(Flask、requests)。
# 第一阶段:构建
FROM python:3.12 AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
COPY . .
# 第二阶段:运行
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /install /usr/local
COPY --from=builder /app/app.py .
CMD ["python", "app.py"]
细节:pip 加 --no-cache-dir;–prefix=/install 把依赖装到固定目录,方便整目录复制;第二阶段只复制主程序文件,不复制整个构建目录。构建命令不变:docker build -t myapp:slim .,再用 docker images 对比。
四、三个坑
一是路径写错:–prefix 目录与 COPY --from 源路径必须一致,否则运行时报 ModuleNotFoundError,构建时却不报错。
二是缺系统库:slim 很精简,运行时可能缺 libpq、libssl 等动态库,在第二阶段用 apt-get install 补上即可,往往只多几兆。
三是泄露配置:COPY . . 会把 .env、证书带进镜像。用 .dockerignore 排除 .env、__pycache__、.git 和测试目录,既瘦身也更安全。
五、效果
重新构建后镜像从 900MB 降到 120MB 左右,启动没有变慢,健康检查一次通过。多阶段构建不是万能药:依赖本身很大、运行期需要编译器时,瘦身空间有限。但对大多数 Python Web 服务,这是一次投入小、收益确定的优化,值得作为默认写法。手头有臃肿镜像的话,按模板改一次,前后各跑一次 docker images 就能看到差别。
- 点赞
- 收藏
- 关注作者
评论(0)