借助BuildKit的新缓存来加快Docker中的点下载

2021-01-29 03:51:53

Docker使用层缓存来加快构建速度,但是层缓存并不总是足够的。当您快速开发Python应用程序并因此频繁更改依赖项列表时,最终将下载相同的软件包。

当您依赖小包装时,这没什么好玩的。下载占用数百兆字节的机器学习库时,这又没有什么好玩的。

随着稳定的Docker BuildKit的发布,Docker现在支持一种可以缓存这些下载内容的新缓存机制。

第一次运行此程序时,Docker当然必须从头开始运行pip install,并且pip将下载Flask及其依赖项。

$将构建上下文发送到Docker守护程序3.584kB步骤1/3:FROM python:3.9-slim-buster ---> b55839ea7a0e步骤2/3:COPY requirements.txt。 ---> 59cc359cfb53步骤3/3:运行pip install -r requirements.txt --->在b0d01b9495b6中运行收集烧瓶下载Flask-1.1.2-py2.py3-none-any.whl(94 kB)收集click> = 5.1下载click-7.1.2-py2.py3-none-any.whl(82 kB)收集其危险信息> = 0.24正在下载itsdangerous-1.1.0-py2.py3-none-any.whl(16 kB)...已成功标记示例:最新

第二次运行此操作时,Docker的层缓存开始了:requirements.txt不变,Dockerfile也没有,因此无需重新运行pip安装。

$ docker build -t示例--progress = plain。将构建上下文发送到Docker守护程序3.584kB步骤1/3:FROM python:3.9-slim-buster ---> b55839ea7a0e步骤2/3:COPY requirements.txt。 --->使用缓存---> 59cc359cfb53步骤3/3:运行pip install -r requirements.txt --->使用缓存---> 974a97388f3f成功构建974a97388f3f成功地标记了示例:最新

现在,当我们重建时,pip install再次运行…并且它将重新下载Flask及其所有依赖项!

$ docker build -t示例--progress = plain。将构建上下文发送到Docker守护程序3.584kB步骤1/3:FROM python:3.9-slim-buster ---> b55839ea7a0e步骤2/3:COPY requirements.txt。 ---> 503a903dd4c9步骤3/3:运行pip install -r requirements.txt --->在9d4aea743390中运行收集烧瓶下载Flask-1.1.2-py2.py3-none-any.whl(94 kB)收集click> = 5.1下载click-7.1.2-py2.py3-none-any.whl(82 kB)收集其危险信息> = 0.24下载其危险的1.1.0-py2.py3-none-any.whl(16 kB)收集Jinja2> = 2.10.1下载Jinja2-2.11.2-py2.py3-none-any.whl(125 kB)收集MarkupSafe。 = 0.23下载MarkupSafe-1.1.1.tar.gz(19 kB)收集Werkzeug。 = 0.15下载Werkzeug-1.0.1-py2.py3-none-any.whl(298 kB)正在收集matplotlib下载matplotlib-3.3.4-cp39-cp39-manylinux1_x86_64.whl(11.5 MB)...

如果您要更改requirements.txt,则会浪费大量时间等待相同的软件包一遍又一遍地下载。

当您在计算机上正常运行pip install(或Pipenv或Poetry)时,它会将下载内容缓存在您的主目录中,这样以后的安装就不需要重新下载相同的软件包了。是它自己的独立小文件系统,充其量是从先前缓存的层开始的。

并且由于缓存单位是RUN命令,因此您可以下载所有软件包,也可以不下载任何软件包。

为了解决这类问题,BuildKit增加了一种新的缓存:您可以跨构建缓存目录,应该假定它在任何时候都被删除了,从某种意义上说,它与在线CI提供的目录缓存非常相似。系统。

要使用它,我们只需要向RUN添加一个附加选项即可。我将要缓存/root/.cache目录,因为Pipenv和Poetry还将在该目录中存储文件; pip默认使用〜/ .cache / pip。

#语法= docker / dockerfile:1.2来自python:3.9-slim-buster COPY requirements.txt。 RUN --mount =类型= cache,target = / root / .cache \ pip install -r requirements.txt#...等等...

注意:在正在讨论的非常具体的主题之外,本文中的Dockerfile并不是最佳实践的示例,因为增加的复杂性将使本文的重点难以理解。

为确保您编写安全,正确,快速的Dockerfile,请考虑我的快速入门指南,其中包括打包过程和60多种最佳实践。

我还将设置DOCKER_BUILDKIT环境变量,以确保使用了BuildKit。

现在,当我构建Docker映像时,它将第一次必须从头开始下载所有内容:

$ docker build -t示例--progress = plain。 ...#9 [stage-0 3/3] RUN --mount =类型= cache,target = / root / .cache pip install -r requirements.txt#9 sha256:cff2b41a0170dccc42eda05f6a5495d3b00436849f28c262356eaea4a29a804f#9 2.816收集瓶#9 2.896下载Flask-1.1.2-py2.py3-none-any.whl(94 kB)#9 3.202收集点击= 5.1#9 3.215下载click-7.1.2-py2.py3-none-any.whl(82 kB)#9 3.226收集其危险= 0.24#9 3.240下载itsdangerous-1.1.0-py2.py3-none-any.whl(16 kB)#9 3.246收集Jinja2> = 2.10.1#9 3.269下载Jinja2-2.11.2-py2.py3-none-any.whl(125 kB)#9 3.405收集MarkupSafe。 = 0.23#9 3.423下载MarkupSafe-1.1.1.tar.gz(19 kB)...

注意输出格式不同;那是因为我们正在使用BuildKit。

通过普通的Docker缓存,我希望Flask和matplotlib能够再次下载。但是这次:

$ docker build -t示例--progress = plain。 ...#9 [stage-0 3/3] RUN --mount =类型= cache,target = / root / .cache pip install -r requirements.txt#9 sha256:42cbbeab455a114b05cbbcaa09a38fa56bc4ce6da820e3957055b164d24ef36f#9 2.421收集Django#9 2.504下载Django-3.1.5-py3-none-any.whl(7.8 MB)#9 3.579收集asgiref< 4> = 3.2.10#9 3.597下载asgiref-3.3.1-py3-none-any.whl(19 kB)#9 3.603收集sqlparse> = 0.2.2#9 3.618下载sqlparse-0.4.1-py3-none-any.whl(42 kB)#9 3.624收集烧瓶#9 3.626使用已缓存的Flask-1.1.2-py2.py3-none-any.whl (94 kB)#9 3.910收集点击= 5.1#9 3.912使用缓存的click-7.1.2-py2.py3-none-any.whl(82 kB)...

请注意,所有“使用已缓存的< package>”-我们不必下载Flask,它是在本地缓存中找到的!

缓存的文件存储在Docker内部。因此,如果您在每次都以新环境开头的某种Cloud CI服务中进行构建,则缓存将无法生存。

您可能可以说服CI系统缓存/var/lib/docker/buildkit/cache.db(例如在GitHub Actions上使用cache动作)。我没有尝试过,所以我不确定是否会可以,但是如果这样做,您还将在各个版本之间保存下载。

但是,您至少可以使用此技术来加快开发过程中或具有持久文件系统的CI服务器上的构建速度。

了解如何构建快速的,可立即投入生产的Docker映像-阅读Docker Python打包指南的其余部分。

从可以节省时间的快速构建,到可以确保安全的最佳安全实践,如何快速获得打包Python应用程序以进行生产所需的专业知识? 通过使用Docker Production Quickstart上的Python,快速学习最佳实践。 订阅我的时事通讯,并与2400多名Python开发人员和数据科学家一起学习实用的工具和技术,从Docker打包到测试再到Python最佳实践,并每周在收件箱中提供免费的新文章。