如何避免大型二进制文件 (Python_Onbuild) 的 Dockerfile 中的缓存失效



我正在我的dock文件中下载1.6 GB的二进制压缩文件,然后使用gunzip将其解压缩,从而存储3.6 GB的文件。我不希望它一直重复,因为这需要很多时间。它是一个静态文件,因此每次我使用 Jenkins/docker 将更改部署到服务器时都不应下载它。但是,每次下载它时,我都会提交更改,并运行 Jenkins 来部署它们。

这是我的码头工人文件:

FROM python:2.7.13-onbuild
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install --assume-yes apt-utils
RUN apt-get update && apt-get install -y curl
RUN apt-get update && apt-get install -y unzip
RUN curl -o - https://s3.amazonaws.com/dl4j-distribution/GoogleNews-vectors-negative300.bin.gz 
| gunzip > /usr/src/app/GoogleNews-vectors-negative300.bin

更新:我将dock文件更改为一个简单的文件,如下所示:

FROM python:2.7.13-onbuild
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
RUN echo "Test Cache"
CMD /usr/local/bin/gunicorn -t 240 -k gevent -w 1 -b 0.0.0.0:8000 --reload src.wsgi:app

现在,如果我不更改代码或任何其他文件,这工作正常,因此命令回显"test cache"不会重复。但是,一旦我对源文件夹中的任何文件进行任何更改,我执行以下步骤后的所有命令都会重复,我认为这些命令会将我的源代码复制到 docker 目录。这不应该在这个阶段发生,因为这意味着一旦我进行任何提交,我的所有命令都会重复。

这是我不对代码进行任何更改并第二次运行构建时的输出:

Sending build context to Docker daemon  239.1kB
Step 1/6 : FROM python:2.7.13-onbuild
# Executing 3 build triggers...
Step 1/1 : COPY requirements.txt /usr/src/app/
---> Using cache
Step 1/1 : RUN pip install --no-cache-dir -r requirements.txt
---> Using cache

Step 1/1 : COPY . /usr/src/app
---> Using cache
---> 1911c6dc9fce
Step 2/6 : RUN mkdir -p /usr/src/app
---> Using cache
---> 4019b029d05c
Step 3/6 : WORKDIR /usr/src/app
---> Using cache
---> 1a99833e908c
Step 4/6 : RUN echo "Test Cache"
---> Using cache
---> 488a62aa1b09

这是我对其中一个源文件进行一次更改的输出,您可以看到回显"测试缓存"被重复。

Sending build context to Docker daemon  239.1kB
Step 1/6 : FROM python:2.7.13-onbuild
# Executing 3 build triggers...
Step 1/1 : COPY requirements.txt /usr/src/app/
---> Using cache
Step 1/1 : RUN pip install --no-cache-dir -r requirements.txt
---> Using cache

Step 1/1 : COPY . /usr/src/app
---> 6fd1003e246a
Removing intermediate container f25a4d2910cf
Step 2/6 : RUN mkdir -p /usr/src/app
---> Running in ff324f381875
---> 3694086a2b6a
Removing intermediate container ff324f381875
Step 3/6 : WORKDIR /usr/src/app
---> 5f23ab9a15df
Removing intermediate container 0b0d796f97d0
Step 4/6 : RUN echo "Test Cache"
---> Running in 296d2f141015
Test Cache
---> f90c7708d9eb

我所有的命令都在重复,因为我使用python:2.7.13-onbuild作为基本图像。它的码头工人文件看起来像这样:

FROM python:2.7
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ONBUILD COPY requirements.txt /usr/src/app/
ONBUILD RUN pip install --no-cache-dir -r requirements.txt
ONBUILD COPY . /usr/src/app

由于我将其用作基本映像,因此复制命令在我的 docker 文件中的所有命令之前执行,并且每次我对源代码进行任何更改时,此复制命令都会更改上下文。

建议我直接使用 Python:2.7 作为基础映像,这样我就可以更好地控制此复制操作。我的新 docker 文件如下所示,末尾的复制命令解决了这个问题。

FROM python:2.7
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install --assume-yes apt-utils
RUN apt-get update && apt-get install -y curl
RUN apt-get update && apt-get install -y unzip
RUN curl -o - https://s3.amazonaws.com/dl4j-distribution/GoogleNews-vectors-negative300.bin.gz 
| gunzip > /usr/src/app/GoogleNews-vectors-negative300.bin
COPY requirements.txt /usr/src/app/
RUN pip install --no-cache-dir -r requirements.txt
COPY . /usr/src/app

根据此文档,通常不鼓励使用Python_onbuild图像。

这个解释的灵感来自我对同一问题的另一个问题的回答: 哪个 Python 变体用作 dockerfile 中的基础映像?

问题来自这样一个事实,即上下文文件的元数据在每次构建时都会更改,因为您在 Jenkins 管道中运行它。因此,docker build 命令无法使用其缓存。

你可以尝试做的是把这个大文件放在 Jenkins 机器上,然后在 Dockerfile 中引用本地文件。这样,您就不必在每次构建时重新下载它。

使用 RUN apt-get

update && apt-get install -y 可确保您的 Dockerfile 无需进一步编码或手动干预即可安装最新的软件包版本。这种技术称为"缓存无效化"。您还可以通过指定包版本来实现缓存无效化。

您的安装说明会破坏缓存,如 dockerfile 的最佳实践中所述。任何不是缓存的指令都将导致所有其他指令再次执行。

确保您的指令不会使缓存失效,除非必要,并将所有不会使缓存失效的说明尽可能放在 dockerfile 中。在您的情况下,将卷曲放在 dockerfile 中更高的位置,您应该没问题。

希望有帮助。

----更新

既然你更新了问题,我会更新我的答案。

  • 缓存未命中后的每个操作都将在构建期间执行。将导致缓存未命中的操作尽可能低地放在 dockerfile 中。
  • 如果文件发生更改,将文件复制到容器将导致缓存未命中

WORKDIR /usr/src/app操作是导致问题的操作,因为它会复制该文件夹中的所有文件。将该操作尽可能低地移动,并重复导致问题的其他操作。

最新更新