在 docker 构建中使用 pip 缓存目录

Posted

技术标签:

【中文标题】在 docker 构建中使用 pip 缓存目录【英文标题】:Using a pip cache directory in docker builds 【发布时间】:2020-01-20 22:02:18 【问题描述】:

我希望尽快在我的docker builds 中获取我的pip install 指令。

我已经阅读了manyposts,解释了如果您的requirements.txt 没有更改,在应用程序的其余部分之前添加您的requirements.txt 可以帮助您利用 Docker 自己的图像缓存。但是当依赖关系发生变化时,这根本没有帮助,即使是轻微的变化。

下一步是我们是否可以使用一致的 pip 缓存目录。默认情况下,pip 会将下载的包缓存在~/.cache/pip(在 Linux 上),因此,如果您曾经在系统上的任何位置安装过相同版本的模块,则不需要去并再次下载,但只需使用缓存版本。如果我们可以为 docker 构建使用共享缓存目录,这将有助于加快依赖安装。

但是,似乎没有任何简单的方法可以在运行docker build 时挂载卷。构建环境似乎基本上是不可穿透的。我发现one article 暗示了一种天才但复杂的方法,即在主机上运行rsync 服务器,然后在构建内部进行黑客攻击以获取主机 IP,从主机同步 pip 缓存。但我不喜欢在 Jenkins 中运行 rsync 服务器的想法(这在最好的时候并不是最安全的平台)。

有谁知道是否有其他方法可以更简单地实现共享缓存卷?

【问题讨论】:

您确定要将缓存放在您的 docker 镜像层中吗? 不,我没有。我希望能够使用可以在构建时共享的共享缓存。 【参考方案1】:

我建议你使用buildkit,另见this。

Dockerfile:

# syntax = docker/dockerfile:experimental
FROM python:3.6-alpine
RUN --mount=type=cache,target=/root/.cache/pip pip install pyyaml

注意# syntax = docker/dockerfile:experimental是必须的,你必须在Dockerfile的开头添加它才能启用这个功能。

1.

第一次执行构建:

export DOCKER_BUILDKIT=1
docker build --progress=plain -t abc:1 . --no-cache

第一条日志:

#9 [stage-0 2/2] RUN --mount=type=cache,target=/root/.cache/pip pip install...
#9   digest: sha256:55b70da1cbbe4d424f8c50c0678a01e855510bbda9d26f1ac5b983808f3bf4a5
#9 name: "[stage-0 2/2] RUN --mount=type=cache,target=/root/.cache/pip pip install pyyaml"
#9  started: 2019-09-20 03:11:35.296107357 +0000 UTC
#9 1.955 Collecting pyyaml
#9 3.050   Downloading https://files.pythonhosted.org/packages/e3/e8/b3212641ee2718d556df0f23f78de8303f068fe29cdaa7a91018849582fe/PyYAML-5.1.2.tar.gz (265kB)
#9 5.006 Building wheels for collected packages: pyyaml
#9 5.007   Building wheel for pyyaml (setup.py): started
#9 5.249   Building wheel for pyyaml (setup.py): finished with status 'done'
#9 5.250   Created wheel for pyyaml: filename=PyYAML-5.1.2-cp36-cp36m-linux_x86_64.whl size=44104 sha256=867daf35eab43c2d047ad737ea1e9eaeb4168b87501cd4d62c533f671208acaa
#9 5.250   Stored in directory: /root/.cache/pip/wheels/d9/45/dd/65f0b38450c47cf7e5312883deb97d065e030c5cca0a365030
#9 5.267 Successfully built pyyaml
#9 5.274 Installing collected packages: pyyaml
#9 5.309 Successfully installed pyyaml-5.1.2
#9completed: 2019-09-20 03:11:42.221146294 +0000 UTC
#9 duration: 6.925038937s

从上面可以看到,第一次构建会从网上下载pyyaml。

2.

第二次执行构建:

docker build --progress=plain -t abc:1 . --no-cache

第二条日志:

#9 [stage-0 2/2] RUN --mount=type=cache,target=/root/.cache/pip pip install...
#9   digest: sha256:55b70da1cbbe4d424f8c50c0678a01e855510bbda9d26f1ac5b983808f3bf4a5
#9 name: "[stage-0 2/2] RUN --mount=type=cache,target=/root/.cache/pip pip install pyyaml"
#9  started: 2019-09-20 03:16:58.588157354 +0000 UTC
#9 1.786 Collecting pyyaml
#9 2.234 Installing collected packages: pyyaml
#9 2.270 Successfully installed pyyaml-5.1.2
#9completed: 2019-09-20 03:17:01.933398002 +0000 UTC
#9 duration: 3.345240648s

从上面你可以看到构建不再从互联网下载包,只是使用缓存。注意,这不是我使用 --no-cache 的传统 docker build 缓存,而是我安装到 build 中的 /root/.cache/pip

3.

第三次执行删除构建包缓存的构建:

docker builder prune
docker build --progress=plain -t abc:1 . --no-cache

第三条日志:

#9 [stage-0 2/2] RUN --mount=type=cache,target=/root/.cache/pip pip install...
#9   digest: sha256:55b70da1cbbe4d424f8c50c0678a01e855510bbda9d26f1ac5b983808f3bf4a5
#9 name: "[stage-0 2/2] RUN --mount=type=cache,target=/root/.cache/pip pip install pyyaml"
#9  started: 2019-09-20 03:19:07.434792944 +0000 UTC
#9 1.894 Collecting pyyaml
#9 2.740   Downloading https://files.pythonhosted.org/packages/e3/e8/b3212641ee2718d556df0f23f78de8303f068fe29cdaa7a91018849582fe/PyYAML-5.1.2.tar.gz (265kB)
#9 3.319 Building wheels for collected packages: pyyaml
#9 3.319   Building wheel for pyyaml (setup.py): started
#9 3.560   Building wheel for pyyaml (setup.py): finished with status 'done'
#9 3.560   Created wheel for pyyaml: filename=PyYAML-5.1.2-cp36-cp36m-linux_x86_64.whl size=44104 sha256=cea5bc4689e231df7915c2fc3abca225d4ee2e869a7540682aacb6d42eb17053
#9 3.560   Stored in directory: /root/.cache/pip/wheels/d9/45/dd/65f0b38450c47cf7e5312883deb97d065e030c5cca0a365030
#9 3.580 Successfully built pyyaml
#9 3.585 Installing collected packages: pyyaml
#9 3.622 Successfully installed pyyaml-5.1.2
#9completed: 2019-09-20 03:19:12.530742712 +0000 UTC
#9 duration: 5.095949768s

从上面可以看到是否删除buildkit缓存,重新下载包。

总之,它会给你一个在多次构建之间共享的缓存,并且这个缓存只会在镜像构建时被挂载。但是,图像本身不会有这些缓存,所以要避免图像中的大量中间层。

为使用 docker compose 并且懒得阅读 cmets 的人编辑...:

如果你设置了,你也可以使用 docker-compose COMPOSE_DOCKER_CLI_BUILD=1。例如:COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose build –

根据人们的问题 2020/09/02 更新:

不知道是从哪个版本开始的(我现在的版本是19.03.11),如果不指定mode缓存目录,下次构建时缓存不会被重用。

不知道具体原因,但可以在 Dockerfile 中添加mode=0755, 使其再次工作:

Dockerfile:

# syntax = docker/dockerfile:experimental
FROM python:3.6-alpine
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip pip install pyyaml

【讨论】:

完美运行,非常感谢。一个小问题-即使您将其包含在示例中,我也错过了# syntax = docker/dockerfile:experimental 行的重要性,因此没有复制它。最后在***.com/questions/55153089/… 纠正我的错误。您可能只想在答案中强调该行的必要性。 我刚刚回到这个问题,并记得我是多么感激它。然后我发现了这个 - meta.***.com/questions/288643/… - 我想我会奖励你 100 赏金,因为它给了我我想要的东西 =) 但看起来我需要 24 小时才能奖励它。 不会重用主机 pip 缓存,内部管理一个缓存以在不同的重建之间重用。 如果您设置了COMPOSE_DOCKER_CLI_BUILD=1,您也可以使用docker-compose 执行此操作。例如:COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose build 使用 Docker 20.10.6 和 docker-compose 1.27.4 可以在没有 # syntax = docker/dockerfile:experimental 注释的情况下工作。

以上是关于在 docker 构建中使用 pip 缓存目录的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 pip 从本地缓存安装?

Phonegap CLI 构建插件缓存?

让 cmake 使用自己的构建缓存

MyBatis的二级缓存

yum -y install pip No package pip available. Error: Nothing to do

使用下载缓存将 PIP 包安装到 Virtualenv