改进 docker 基于 pip 的 python 应用程序的构建时间

Improving docker build time for pip based python application

我们有一个 python 项目,当前 docker 构建需要 350 秒。这是当前的 Dockerfile

FROM python:3.9

RUN apt-get update && \
    apt-get install -y python2.7

WORKDIR /var/app
COPY . .
RUN pip install

ENTRYPOINT ["python3", "/var/app/src/main.py"]

docker build 这需要 350 秒 这里有明显的改进空间所以,我把它改成了这个

FROM python:3.9

RUN apt-get update && \
    apt-get install -y python2.7

WORKDIR /var/app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
RUN pip install

ENTRYPOINT ["python3", "/var/app/src/main.py"]

这将后续构建时间缩短为 1 秒

经过一番搜索,我也遇到了以下问题,

FROM python:3.9

RUN apt-get update && \
    apt-get install -y python2.7

WORKDIR /var/app
COPY requirements.txt .
RUN  --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
COPY . .
RUN pip install

ENTRYPOINT ["python3", "/var/app/src/main.py"]

这需要大约 80 秒的时间,但比第一个好

我没有使用经验 pip/docker fyi

对于 #2,作为 docker 缓存层的副作用,如果我的任何依赖项依赖项版本发生变化,因为使用范围 operators,那么我仍然不会重建任何东西。这是#3 试图解决的问题吗?即它会尽可能多地重用缓存,但也会确保更新任何必要的东西

如果不是,我不知道#3 是怎么回事。 /root/.cache/pip 是 pip 特定目录还是可以是任何内容?

前两者的区别是Docker。 Docker 维护一个 build cache:如果上一步被缓存,并且此 RUN 指令是之前 运行 的指令或此 COPY 指令复制相同的文件,然后 Docker 跳过构建该层并使用上次构建它时的输出。

因此在第一种形式中,每当任何文件更改时,COPY 行都会使构建缓存无效,您必须重复 RUN pip install 行。但是在第二种形式中,你只有 COPY requirements.txt . 第一。如果该文件没有更改,那么您仍在处理构建缓存,您也可以跳过 RUN pip install 行。这是标准的 Docker 做法;您不会错过任何东西,也没有任何注意事项。


最后两者之间的区别是一个点。 Pip 还 maintains a cache 它下载的东西。如果没有 Docker,如果您第二次 运行 pip install -r requirements.txt,pip 将找到其本地缓存并避免 re-downloading 个文件。

但是,在 Docker 中,每个图像构建都从同一个空图像开始。 RUN --mount 选项挂载一个持久目录作为 pip 缓存。这一方面为您提供了一个存储可以重复使用的文件的地方,另一方面避免了在最终图像中存储冗余的 wheel 文件。挂载目标目录需要与 pip 期望其缓存的位置相同。

您应该发现,如果您没有更改 requirements.txt,那么构建将再次跳过 RUN pip install 步骤,与您的第二个 Docker 文件相同。如果有,那么它至少会跳过下载许多软件包。根据您的网络速度,这可能会导致后续重建 运行 更快。


... if any of my dependencies dependency version changes ...

大多数包管理器有两个不同的版本列表副本,user-managed 依赖文件和一个单独的锁定文件列出要安装的确切版本。

在 Python 中,情况有点混乱,因为有几个不同的包管理器。如果我没有使用 Pipfile 或 Poetry 等替代工具,那么我建议的设置是在 setup.cfg 文件

中使用标准 Setuptools library. List your application's dependencies
[options]
install_requires =
  some-package >=1.0,<2.0

在您的主机系统上,使用它安装到虚拟环境中,然后 运行 pip freeze 生成 requirements.txt 文件。

python3 -m venv ./venv
. ./venv/bin/activate
pip install -e .
pip freeze > requirements.txt

现在 requirements.txt 文件包含您直接和间接依赖的每个库的确切版本。不要hand-edit这个文件;不要在您的 Docker 文件中重新生成它;请将其签入源代码管理。有了一对依赖文件,requirements.txt 现在在功能上是锁定文件。

另请参阅 Repeatable Installs 上的 pip 文档。如果您选择使用这些包管理器之一,Pipfile 和 Poetry 都维护自己的锁定文件。