改进 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 秒的时间,但比第一个好
- 我不明白#2 的注意事项是什么(安全起见)。
- 我什么时候应该使用#3
我没有使用经验 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 都维护自己的锁定文件。
我们有一个 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 秒的时间,但比第一个好
- 我不明白#2 的注意事项是什么(安全起见)。
- 我什么时候应该使用#3
我没有使用经验 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
文件
[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 都维护自己的锁定文件。