我可以使用以下简单的 Dockerfile 为我的 python 应用生成工作图像:
FROM python:3.7
WORKDIR /myapp
COPY Pipfile* ./
RUN pip install pipenv
RUN pipenv install --system --deploy
COPY src .
CMD ["python3", "app.py"]
但是,它会生成约 1 GB 的镜像,其中可能包含临时文件,并且部署起来很繁重。而且我只需要用于构建目的的完整 python 图像。我的应用程序可以在 alpine 变体上成功运行,因此我可以生成两次 Dockerfile:
FROM python:3.7 as builder
COPY Pipfile* ./
RUN pipenv lock --requirements > requirements.txt
RUN python3 -m venv /venv
RUN /venv/bin/pip install --upgrade pip
RUN /venv/bin/pip install -r requirements.txt
FROM python:3.7-alpine
COPY --from=builder /venv /venv
WORKDIR /myapp
COPY src .
CMD ["/venv/bin/python3", "app.py"]
到目前为止一切顺利,它也可以工作,缩小了 6 倍。但是这个方案被认为是一些“ stub ”,有一些缺点:
- 它有不必要的额外
COPY --from=builder步骤 - 它不使用
pipenv但还需要pip进行安装(+1 额外步骤,pipenv lock+pip install总是比pipenv install) 慢 - 它不会在系统范围内安装,而是安装在
/venv中,应避免在容器内安装 - 次要:构建会更多地污染中间图像缓存,并且需要下载两个图像变体。
如何结合这两种方法,使用 pipenv 获得基于 alpine 的轻量级图像,而没有提到的缺点?
或者您可以提供您的生产 Dockerfile 想法吗?
请您参考如下方法:
当您需要像 ciso8601 或一些需要构建过程的库时,问题就来了。构建工具并未“合并”到 slim 和 alpine 变体中,以实现较小的占用空间。
所以要安装 deps,你必须:
- 安装构建工具
- 在系统范围内从 Pipfile.lock 部署依赖项
- 卸载构建工具并清理缓存
并在单个 RUN 层中执行这 3 个操作,如下所示:
FROM python:3.7-slim
WORKDIR /app
# both files are explicitly required!
COPY Pipfile Pipfile.lock ./
RUN pip install pipenv && \
apt-get update && \
apt-get install -y --no-install-recommends gcc python3-dev libssl-dev && \
pipenv install --deploy --system && \
apt-get remove -y gcc python3-dev libssl-dev && \
apt-get autoremove -y && \
pip uninstall pipenv -y
COPY app ./
CMD ["python", "app.py"]
- 操纵构建系统将花费您大约 300MiB 和一些额外的时间
- 卸载 pipenv 可以再节省 20MiB(占最终大小的 10%)。
- 分隔
RUN命令不会从图层中删除数据,并且会生成约 500MiB 的图像。这是 Docker 的具体情况。
因此这将导致完美工作 ~200MiB 大小的图像,这是
- 比原始
python:3.7少 5 倍,(即 >1.0GiB) - 没有 alpine 不兼容(这些通常与 glibc 替换有关)
当时,我们可以接受 slim(debian buster)构建变体,更喜欢 slim 而不是 alpine(为了大多数兼容性)。如果你真的想进一步优化尺寸,我建议你看看这些家伙的一些优秀构建:
