PyPI速度慢,我该如何运行自己的服务器?

44
当一个新的开发者加入团队,或者Jenkins运行完整的构建时,我需要创建一个新的virtualenv。我经常发现使用Pip和大量(超过10个)要求设置虚拟环境需要很长时间从PyPI安装所有内容。通常会失败,并显示以下错误信息:
Downloading/unpacking Django==1.4.5 (from -r requirements.pip (line 1))
Exception:
Traceback (most recent call last):
  File "/var/lib/jenkins/jobs/hermes-web/workspace/web/.venv/lib/python2.6/site-packages/pip-1.2.1-py2.6.egg/pip/basecommand.py", line 107, in main
    status = self.run(options, args)
  File "/var/lib/jenkins/jobs/hermes-web/workspace/web/.venv/lib/python2.6/site-packages/pip-1.2.1-py2.6.egg/pip/commands/install.py", line 256, in run
    requirement_set.prepare_files(finder, force_root_egg_info=self.bundle, bundle=self.bundle)
  File "/var/lib/jenkins/jobs/hermes-web/workspace/web/.venv/lib/python2.6/site-packages/pip-1.2.1-py2.6.egg/pip/req.py", line 1018, in prepare_files
    self.unpack_url(url, location, self.is_download)
  File "/var/lib/jenkins/jobs/hermes-web/workspace/web/.venv/lib/python2.6/site-packages/pip-1.2.1-py2.6.egg/pip/req.py", line 1142, in unpack_url
    retval = unpack_http_url(link, location, self.download_cache, self.download_dir)
  File "/var/lib/jenkins/jobs/hermes-web/workspace/web/.venv/lib/python2.6/site-packages/pip-1.2.1-py2.6.egg/pip/download.py", line 463, in unpack_http_url
    download_hash = _download_url(resp, link, temp_location)
  File "/var/lib/jenkins/jobs/hermes-web/workspace/web/.venv/lib/python2.6/site-packages/pip-1.2.1-py2.6.egg/pip/download.py", line 380, in _download_url
    chunk = resp.read(4096)
  File "/usr/lib64/python2.6/socket.py", line 353, in read
    data = self._sock.recv(left)
  File "/usr/lib64/python2.6/httplib.py", line 538, in read
    s = self.fp.read(amt)
  File "/usr/lib64/python2.6/socket.py", line 353, in read
    data = self._sock.recv(left)
timeout: timed out

我知道Pip的--use-mirrors标志,有时我的团队成员会通过使用--index-url http://f.pypi.python.org/simple(或其他镜像)来解决问题,直到他们找到一个能够及时响应的镜像。我们在英国,但在德国有一个PyPI镜像,并且我们没有从其他网站下载数据的问题。
因此,我正在寻找为我们团队内部镜像PyPI的方法。
我看过的选项是:
  1. 运行自己的PyPI实例。有官方的PyPI实现:CheeseShop以及几个第三方实现,例如:djangopypipypiserver(见脚注)。

    这种方法的问题在于我不需要完整的PyPI功能和文件上传,我只想要镜像它提供的内容。

  2. 使用pep381clientpypi-mirror运行PyPI镜像。

    看起来这个方法可能可行,但是需要我的镜像先从PyPI下载所有东西。我已经设置了一个pep381client的测试实例,但我的下载速度在5 Kb/s到200 Kb/s之间变化(位,不是字节)。除非有完整的PyPI存档副本,否则我需要几周时间才能拥有一个有用的镜像。

  3. 使用PyPI轮询代理,例如yopypi

    现在这个方法已经无关紧要了,因为http://pypi.python.org本身由几个地理位置不同的服务器组成。

  4. 在开发者之间复制virtualenv,或者托管当前项目依赖项的文件夹

    这种方法不可扩展:我们有几个不同的Python项目,其依赖关系会随时间(缓慢)变化。只要任何项目的依赖关系发生变化,就必须更新这个中央文件夹以添加新的依赖项。复制virtualenv比复制包更糟糕,因为任何带有C模块的Python包都需要为目标系统编译。我们的团队既有Linux用户也有OS X用户。

    (这仍然看起来是一堆糟糕方案中最好的选择。)

  5. 使用智能PyPI缓存代理:collective.eggproxy

    这似乎是一个非常好的解决方案,但PyPI上的最后版本日期为2009年,并且讨论了mod_python。

其他大型Python团队都做些什么?快速安装相同的Python包集的最佳解决方案是什么?

脚注:


1
就我个人而言,当我需要编写脚本来重复创建虚拟环境时,我只是为我想要的包构建了 .egg 文件,并将它们与创建虚拟环境的脚本一起提交到仓库中。不过,我不认为自己是一个大型 Python 团队的一员。 - FatalError
5个回答

35

您是否拥有共享文件系统?

因为我想要使用pip的缓存设置。这很简单,只需在例如/mnt下创建一个名为pip-cache的文件夹即可。

mkdir /mnt/pip-cache

然后每个开发人员都会将以下行放入其pip配置文件中(unix = $HOME/.pip/pip.conf,win = %HOME%\pip\pip.ini)

[global]
download-cache = /mnt/pip-cache

它仍会检查PyPi并寻找最新版本。然后检查该版本是否在缓存中。如果是,则从缓存中安装它。如果不是,则下载它,并将其存储在缓存中并进行安装。因此,每个程序包只会在新版本时下载一次。


2
这看起来是一个很棒的选择。不过,你的示例pip.conf是错误的——它不应该有缩进,否则Pip会报错ConfigParser.ParsingError: File contains parsing errors。我本来可以自己编辑它,但是SO不允许我进行小的编辑。 - Wilfred Hughes
我已经测试过这个,它完美地工作了。我希望我能为你点赞更多,谢谢。赞赏你不仅考虑了运行服务器的最佳方式。 - Wilfred Hughes
我们已经决定从团队内的构建服务器复制Pip缓存包:https://gist.github.com/Wilfred/5221953 - Wilfred Hughes
3
pip也有命令行选项--download-cache=<dir>,所以如果更容易的话,你不需要编辑配置文件。 - dalore
pip的速度非常慢,慢得让编写它的开发人员感到尴尬——即使在最快的硬件上,它在“安装pip依赖项…”阶段也需要花费几分钟时间,而且大部分时间都是在无所事事。即使Windows更新也比它更快地检查其依赖项。 - Igor Levicki

9
虽然它不能解决您的PyPI问题,但可以使用Terrarium将构建的虚拟环境交给开发人员(或部署)。

使用terrarium打包、压缩和保存虚拟环境。您可以将它们存储在本地甚至将它们存储在S3上。来自GitHub文档的说明:

$ pip install terrarium
$ terrarium --target testenv --storage-dir /mnt/storage install requirements.txt

在构建新环境后,Terrarium 将会归档并压缩环境,然后将其复制到存储目录指定的位置。对于指定相同存储目录的相同需求集的后续安装,Terrarium 将从/mnt/storage复制和提取压缩的归档文件。要准确显示 Terrarium 如何命名归档文件,请运行以下命令:
$ terrarium key requirements.txt more_requirements.txt
x86_64-2.6-c33a239222ddb1f47fcff08f3ea1b5e1

谢谢,我不知道Terrarium。它是否处理OS X和Linux用户之间的共享情况?我们有纯Python和C模块,因此我怀疑编译的软件包将跨平台。 - Wilfred Hughes
我真希望我知道。:(虽然我很想拥有一台Mac...)如果我有机会,我会看看我能弄清楚什么。我自2013年PyCon以来才开始使用这个软件包(在那里听说过它并遇到了开发人员)。 - Kyle Kelley
3
我是Terrarium的作者。编译好的软件包不能跨平台使用,Terrarium并不能解决这个问题。如果你的需求不经常改变,那么每个平台类型的第一个用户运行该命令时将成为构建者。在下一次需求更改之前,所有后续运行该命令的用户都将下载预编译版本。看起来Terrarium会是一个易于使用的命令界面,可以帮助你完成手动操作。如果你遇到任何阻止你以这种方式使用它的问题,请告诉我。 - Kyle Gibson

8
我最近将devpi安装到我的开发团队的Vagrant配置中,使其包缓存位于主机文件系统上。这使得每个虚拟机都可以拥有自己的devpi-server守护进程,并将其用作virtualenv/pip的index-url。当虚拟机被销毁并重新配置时,包不必一遍又一遍地下载。每个开发人员只需下载一次即可构建本地缓存,长期保存在主机文件系统上。
我们还有一个内部PyPi索引,目前只是通过Apache提供服务的目录。最终,我也会将其转换为devpi代理服务器,这样我们的构建服务器除了托管私有库之外,还将维护Python依赖项的软件包缓存。这将在我们的开发环境、生产部署和公共PyPi之间创建一个额外的缓冲区。
这似乎是迄今为止我找到的最强大的解决方案。

3
我搜索了一段时间的私有PyPI服务器,必须确认Devpi似乎是它们中最好的一个。Devpi的作者还编写了pytest和tox,因此可以期望在开发和测试方面得到非常好的支持。 - Jan Vlcinsky

4

看一下David Wolever的pip2pi。你只需要设置一个cron job,以保持公司或团队所需软件包的镜像,然后将你的pips指向内部镜像即可。


-2

设置本地服务器,然后修改本地计算机的 hosts 文件,将实际 URL 覆盖为指向本地服务器,从而跳过标准 DNS。完成后,可以删除 host 文件中的该行。

或者,您可以在 pip 中找到 URL 并进行修改。


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