为什么Heroku在新的部署中安装旧版Python(pip)依赖项?

5

(按照Heroku的支持指引在此咨询)

我们发现一个项目中存在依赖问题,开发环境中库不匹配。细节并不重要,但根本原因是一种依赖有一个“>=”版本匹配在它的setup.py中 - 这意味着当一个开发者重新构建他的环境时,他会突然得到最新版本(0.4.0),而不是他先前拥有的旧版本(0.3.11),并开始收到一个DeprecationWarning

作为调试过程的一部分,我认为每当将repo推送到Heroku时,将会重新构建一个干净的环境,这让我错误地假设我们的DEV环境(每天重新构建)已经安装了最新版本。因为我们在dev环境上没有看到这个问题,所以我决定进行调查,并在远程环境上运行heroku run pip list

我很惊讶地发现,这个输出是旧版本和过期依赖项的抽签,而且根本不是一个干净的环境。结果我们可能在我们的live环境中有这个我们正在调试的问题,作为一个旧版的安装包的一部分。

最简单的解释是BeautifulSoup库。我们最近从v3升级到v4,在此过程中,库本身在PyPI上的名称从BeautifulSoup更改为beautifulsoup4。我们更新了requirements.txt以反映这一点,但是如果我现在在Heroku环境中运行pip list,我会得到两个版本:

~ $ heroku run bash
~ $ pip list
BeautifulSoup (3.2.1)
beautifulsoup4 (4.3.2)

所以,旧的依赖关系并没有被清除,它只是在那里。我可以通过启动一个Python会话轻松地证明它:

~ $ python
Python 2.7.4 (default, Apr  6 2013, 22:14:13)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import bs4
>>> import BeautifulSoup
>>>

这有点令人惊讶,我很惊奇为什么这没有在某个时候导致应用程序崩溃?

那么问题来了 - Heroku如何在后台管理依赖项 - 显然它不会擦除Python环境并在每次部署时重新运行pip install - 我能否强制执行此操作?

[编辑1]

顺便说一下,这是执行安装的buildpack - https://github.com/heroku/heroku-buildpack-python/blob/master/bin/compile

[编辑2]

Heroku Buildpack文档中:

CACHE_DIR的内容将在构建之间保持。您可以将诸如依赖关系分辨率之类的长时间过程的结果缓存到此处,以加速未来的构建。

并且往下说

bin/compile脚本将得到CACHE_DIR作为其第二个参数,该参数可用于在构建之间存储工件。存储在此目录中的工件将在后续构建期间在CACHE_DIR中可用。CACHE_DIR仅在编译包时可用,并且特定于正在构建的应用程序。

建议是:

Heroku用户可以使用heroku-repo插件清除他们的应用程序所使用的buildpack创建的构建缓存

也就是说 - 虽然我理解缓存被用来加速未来的编译,但我不明白为什么会安装缓存中的所有内容。这没有任何意义?

1个回答

3
Heroku会将Python环境安装在/app/.heroku/python中,并且整个.heroku目录在每次构建的开始时从CACHE_DIR复制,然后在完成后又复制回CACHE_DIR。如果在buildpack脚本中搜索restore_cachedump_cache,您会看到执行此操作的行。

因此,一旦您在Heroku应用程序中安装了某个内容,它就会一直保留,除非CACHE_DIR被某种方式擦除。显然,这并不理想,但这样做是为了避免重新编译和安装所有依赖项所需的非常长的构建时间。(值得一提的是,我认为现在有一种更好的方法可以使用轮子来缓存编译包,因此您可以每次都获得新鲜的环境,而无需等待所有内容重建。我可能会尝试提供一个示例并与Kenneth Reitz交流。)

在短期内,听起来您可以从明确固定所有依赖项的版本(包括依赖于其他依赖项的依赖项等)中受益。简单运行pip freeze > requirements.txt就是一个好的开始,但您还可以查看

pip-tools

对于BeautifulSoup更改其包名称(但不是您导入的模块的名称),这听起来非常糟糕,正是Heroku缓存崩溃的情况!我认为唯一的解决方案是使用heroku-repo插件并彻底清除缓存。

谢谢您的全面回答。我们一直在使用完全固定依赖的方式运行了很长时间,但后来遇到了一个依赖关系与我们固定的版本不匹配的问题。使用heroko_repopurge_cache至少清理了环境,让我们找出了实际发生了什么。这与日常维护一样重要 - 清除我们不再依赖的旧依赖项。 - Hugo Rodger-Brown
PS 如果你在关于构建包方面向 KR 发问 - 这个也让我们遇到了问题(作为调试的一部分)- https://github.com/heroku/heroku-buildpack-python/pull/152 - Hugo Rodger-Brown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接