【问题标题】:Improving docker build time for pip based python application改进基于 pip 的 python 应用程序的 docker 构建时间
【发布时间】:2022-02-20 04:07:22
【问题描述】:

我们有一个 python 项目,当前的 docker build 需要 350s。这是当前的 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 多岁左右的时间,但比第一个要好

  • 我不明白#2 的注意事项是什么(为了安全起见)。
  • 什么时候应该使用#3

我没有使用 pip/docker fyi 的经验

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

如果不是,我不知道#3 发生了什么。 /root/.cache/pip 是特定于 pip 的目录还是可以是任何目录?

【问题讨论】:

  • 你使用python 3.9基础镜像安装Python 2.7...逻辑?
  • 这真的是特定于我们的应用程序的功能。 afaik 这是历史性的和必需的,没有它我们就无法完成我们正在尝试做的事情。我确信有更好的方法可以做到这一点,但我们可以稍后再谈@KevinC 编辑:似乎是在 mesos 上运行的容器的问题,因此需要同时安装 2.7

标签: python docker pip


【解决方案1】:

前两者的区别在于 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 会找到它的本地缓存并避免重新下载文件。

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

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


...如果我的任何依赖项依赖版本更改...

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

在 Python 中,情况有点混乱,因为有几个不同的包管理器。如果我没有使用像 Pipfile 或 Poetry 这样的替代工具,那么我建议的设置是使用标准的 Setuptools 库。 List your application's dependenciessetup.cfg 文件中

[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 文件包含您直接和间接依赖的每个库的确切版本。不要手动编辑此文件;不要在 Dockerfile 中重新生成它;将其检查到源代码管理中。有了这对依赖文件,requirements.txt 现在在功能上就是锁定文件。

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

【讨论】:

    猜你喜欢
    • 2016-07-16
    • 2011-08-24
    • 1970-01-01
    • 2017-06-04
    • 2022-08-11
    • 2019-06-19
    • 2011-03-02
    • 1970-01-01
    • 2022-12-05
    相关资源
    最近更新 更多