最早写 Dockerfile 基本是照着教程抄:FROM python:3.8,COPY . .,RUN pip install -r requirements.txt。结果镜像 1.2G,每次部署推送到仓库都要等好几分钟。
动作一:换基础镜像
python:3.8 是完整版 Debian,带编译器、文档、一堆用不上的包。换成 slim 版:
FROM python:3.8-slim
体积立刻从 900M 掉到 120M 左右。如果依赖里有需要编译的 C 扩展(比如 mysqlclient),再临时装 build-essential,装完删掉。
动作二:多阶段构建
编译依赖和运行依赖是两套东西,没必要都留在最终镜像里:
FROM python:3.8-slim AS builder
WORKDIR /build
RUN apt-get update && apt-get install -y --no-install-recommends gcc default-libmysqlclient-dev
COPY requirements.txt .
RUN pip wheel --no-cache-dir -r requirements.txt -w /wheels
FROM python:3.8-slim
WORKDIR /app
COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir --no-index --find-links=/wheels /wheels/* \
&& rm -rf /wheels
COPY . .
CMD ["python", "main.py"]
最终镜像里只剩下 .whl 装好的包,编译工具链全留在 builder 阶段被丢弃。
动作三:让缓存真正生效
COPY . . 放在 pip install 之前,会导致改一行代码就让依赖层缓存全部失效,每次重新装包。正确顺序是先拷 requirements.txt、装依赖,再拷源码:
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
再配一个 .dockerignore,把 .git、node_modules、data.db、__pycache__ 排除掉。之前没写这个,把 300M 的本地数据库一起打进镜像了。
顺手看一眼镜像构成
docker history 镜像名 --no-trunc
按层列出体积和命令,哪一层大一眼就看出来。我那次最大的层就是 apt 安装缓存没清。
三个动作做完,镜像从 1.2G 到 80M,拉取时间从 4 分钟变成十几秒,服务器磁盘也宽裕了。
- THE END -
最后修改:2022年2月11日
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://mi-blog.cn/archives/652
共有 0 条评论