基于 pypiserver 的 PyPI 私有仓库搭建实践

背景

前几天,在不同的 CentOS 服务器上尝试部署同一个发行版本的 Galaxy 生物信息分析平台的时候,总是发现在执行 sh run.sh 部署时由于网络限制导致的 requirements.txt 包安装出现 ReadTimeoutError。

galaxy@ecs-steven 08:58:14 /data/galaxy-dist/galaxy
$ sh run.sh
Found conda at: /data/galaxy-dist/anaconda2/bin/conda
Found Conda, virtualenv will not be used.
To use a virtualenv instead, create one with a non-Conda Python 2.7 at .venv
Activating Conda environment: _galaxy_18.05
Looking in indexes: https://wheels.galaxyproject.org/simple, https://pypi.python.org/simple
Collecting amqp==2.2.2 (from -r requirements.txt (line 1))

......

Collecting bx-python==0.8.1 (from -r requirements.txt (line 14))
  Downloading https://wheels.galaxyproject.org/packages/bx_python-0.8.1-cp27-cp27mu-manylinux1_x86_64.whl (3.2MB)
    50% |████████████████▎               | 1.6MB 4.1kB/s eta 0:06:15Exception:
Traceback (most recent call last):
  File "/data/galaxy-dist/anaconda2/envs/_galaxy_18.05/lib/python2.7/site-packages/pip/_internal/cli/base_command.py", line 143, in main
    status = self.run(options, args)

......

File "/data/galaxy-dist/anaconda2/envs/_galaxy_18.05/lib/python2.7/site-packages/pip/_vendor/urllib3/response.py", line 345, in _error_catcher
    raise ReadTimeoutError(self._pool, None, 'Read timed out.')
ReadTimeoutError: HTTPSConnectionPool(host='wheels.galaxyproject.org', port=443): Read timed out.

原因在于:

第一,Galaxy 的初始化部署,其中有一步就是通过 pip 去在线下载位于 https://wheels.galaxyproject.org/simplehttps://pypi.python.org/simple 这两个 PyPI 库的 requirements.txt 包,并执行安装。

第二,由于这两个 pypi 库位于国外,国内服务器想要下载里面的包可能会出现网络超时。

https://wheels.galaxyproject.org/ 的首页介绍,可以知道这是 Galaxy 基于 pypiserver-1.2.1 搭建的一个 PyPI 源(This instance is running version 1.2.1 of the pypiserver software.)。为了解决文章开头的 ReadTimeoutError,我们借着这个机会来学习一下如何使用 pypiserver 快速搭建一个属于自己的离线 PyPI 仓库(本文章使用 pip==18.1)。

PyPI 私有源

PyPI(Python Package Index,https://pypi.org/) 是 Python 官方的第三方库的仓库,所有人都可以下载第三方库或上传自己开发的库到 PyPI。
通常我们使用 pip 安装 Python 包,默认就是从 https://pypi.python.org/pypi (https://pypi.org/) 上安装。当然,我们也可以通过配置 pip.conf 或者使用命令行从指定的 PyPI 源安装。

# 从阿里云的 PyPI 源安装
pip install --index-url https://mirrors.aliyun.com/pypi/simple/ PACKAGE-NAME

# 替换默认 pip 源为阿里云
mkdir ~/.pip
tee ~/.pip/pip.conf <<-'EOF'
[global]
index-url = https://mirrors.aliyun.com/pypi/simple/
[install]
trusted-host= mirrors.aliyun.com
EOF

这里需要提到的是,有些是公司内部的项目,不方便放到外网上去,这个时候我们就要搭建自己的内网 PyPI 源服务器,需要安全并且拥有同样的舒适体验。关于 PyPI 私有源的实现,Python 官方的 PyPi Implementations 说明中列出了几个比较成熟的实现方案:

PyPi Implementations

这里选择 pypiserver,除了 Galaxy 的原因外,最重要的是因为他最小而且使用简单。

pypiserver 简介

pypiserver is a minimal PyPI compatible server for pip or easy_install. It is based on bottle and serves packages from regular directories. Wheels, bdists, eggs and accompanying PGP-signatures can be uploaded either with pip, setuptools, twine, pypi-uploader, or simply copied with scp.

pypiserver 服务端配置

pypiserver > 1.2.x works with Python 2.7 and 3.4+ or pypy. Older Python versions may still work, but they are not tested. For legacy Python versions, use pypiserver-1.1.x series.

也就是说,pypiserver 1.2.x 以上版本要求 Python 2.7 或 3.4+,低版本的 Python 请使用 pypiserver-1.1.x。

# 替换默认 pip 源为阿里云
$ mkdir ~/.pip
$ tee ~/.pip/pip.conf <<-'EOF'
[global]
index-url = https://mirrors.aliyun.com/pypi/simple/
[install]
trusted-host= mirrors.aliyun.com
EOF

# 直接在线安装 pypiserver
$ pip install pypiserver

# 离线安装 pypiserver
$ wget  https://files.pythonhosted.org/packages/ec/f6/593ff8da4862f73c55027c32ac6f73ea09eabb546e7ebec82f83cc034fcb/pypiserver-1.2.4-py2.py3-none-any.whl
$ cp pypiserver-1.2.4-py2.py3-none-any.whl /tmp/pypiserver/
$ pip install /tmp/pypiserver/pypiserver-1.2.4-py2.py3-none-any.whl

# 创建 pypiserver 离线包的保存路径
$ mkdir ~/packages

# 以 mako 包为例,下载该包并拷贝至 ~/packages
$ cd ~/packages
$ pip download -d /home/shenweiyan/packages mako

# 启动 pypiserver 服务
$ pypi-server -p 8080 ~/packages &

pypiserver 客户端配置

$ python -c "import mako"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'mako'

# 从本地镜像搜索包
$ pip search --index http://localhost:8080 Mako
Mako (1.0.7)  - 1.0.7

# 从指定的本地镜像安装包
pip install -i http://localhost:8080/simple/ mako
pip 从本地 pypiserver 安装 mako

pypiserver 客户端推荐的个人配置:

tee ~/.pip/pip.conf <<-'EOF'
[global]
index-url = http://120.77.xx.xx/simple
extra-index-url = https://mirrors.aliyun.com/pypi/simple/
[install]
trusted-host = 120.77.xx.xx
EOF

requirements.txt 离线 PyPI 仓库

一般 Python 项目使用 pip 安装的包,都可以通过 pip freeze >requirements.txt 导出环境中已有的模块。搭建 requirements.txt 离线 PyPI 仓库,我们首先需要把 requirements.txt 所有的模块安装包下载到本地。

$ pip download -d /home/shenweiyan/packages -r /home/shenweiyan/galaxy/requirements.txt --index-url https://mirrors.aliyun.com/pypi/simple --extra-index-url https://wheels.galaxyproject.org/simple
Looking in indexes: https://mirrors.aliyun.com/pypi/simple, https://wheels.galaxyproject.org/simple
Collecting amqp==2.2.2 (from -r //home/shenweiyan/galaxy/requirements.txt (line 1))
  Downloading https://mirrors.aliyun.com/pypi/packages/88/4a/8c45a882d842678963516ebd9cf584a4ded51af719234c3b696c2e884c60/amqp-2.2.2-py2.py3-none-any.whl (48kB)
    100% |████████████████████████████████| 51kB 779kB/s
  Saved ./amqp-2.2.2-py2.py3-none-any.whl

......

Collecting wrapt==1.10.11 (from -r /home/shenweiyan/galaxy/requirements.txt (line 134))
  Downloading https://wheels.galaxyproject.org/packages/wrapt-1.10.11-cp27-cp27mu-manylinux1_x86_64.whl (64kB)
    100% |████████████████████████████████| 71kB 321kB/s
  Saved /home/galaxy/packages/wrapt-1.10.11-cp27-cp27mu-manylinux1_x86_64.whl
Successfully downloaded amqp appdirs asn1crypto babel bagit bcrypt bdbag beaker bioblend bleach boltons boto bunch bx-python bz2file certifi ...... wcwidth webencodings webob whoosh wrapt

我们把 /home/shenweiyan/packages 整个目录拷贝到目标服务器(可连网但速度极慢,目标路径:/data/galaxy-dist/packages),搭建并启动 pypiserver,然后从本地离线 PyPI 仓库安装 requirements 软件:

# 登陆目标服务器,离线安装 pypiserver

# 启动 pypiserver
$ cd /data/galaxy-dist/packages
$ pypi-server -p 8080 /data/galaxy-dist/packages &

# 安装 requirements 软件
$ conda activate galaxy
$ pip install --index-url http://localhost:8080/simple/ --extra-index-url https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt
Looking in indexes: http://localhost:8080/simple/, https://mirrors.aliyun.com/pypi/simple/
Requirement already satisfied: amqp==2.2.2 in ./galaxy-dist/anaconda2/envs/galaxy/lib/python2.7/site-packages (from -r /data/galaxy-dist/galaxy/requirements.txt (line 1)) (2.2.2)
Requirement already satisfied: appdirs==1.4.3 in ./galaxy-dist/anaconda2/envs/galaxy/lib/python2.7/site-packages (from -r /data/galaxy-dist/galaxy/requirements.txt (line 2)) (1.4.3)

......

Collecting bdbag==1.2.4 (from -r /data/galaxy-dist/galaxy/requirements.txt (line 7))
  Downloading http://localhost:8080/packages/bdbag-1.2.4-py2-none-any.whl (42kB)
    100% |████████████████████████████████| 51kB 52.0MB/s
Collecting beaker==1.9.1 (from -r /data/galaxy-dist/galaxy/requirements.txt (line 8))
  Downloading http://localhost:8080/packages/Beaker-1.9.1.tar.gz (40kB)
    100% |████████████████████████████████| 40kB 49.4MB/s

......

Successfully installed bdbag-1.2.4 beaker-1.9.1 ...... warlock-1.2.0 webob-1.4.2

到这里,基于 pypiserver 的离线本地 PyPI 仓库基本搭建与使用实践就已经介绍完毕了。对于一个完整的 Python 项目,如果需要从连网的开发服务器迁移至内网(无法使用外网,或者部分资源位于墙外,墙内下载速度差)的部署服务器,pypiserver 可能是一个不错的解决方案。

  • 对于 conda 依赖的 Python 项目,国内推荐使用清华大学的镜像。
  • 对于 PyPI 源,国内推荐使用阿里云或者清华大学的 PyPI 镜像。
  • 对于特定项目的第三方 PyPI 源,可考虑 pypiserver 实现离线本地化。

pypiserver 的一些高级用法,如基于 systemd 和 supervisor 的自动化启动管理;基于 Docker 技术的部署与使用;基于 Nginx 反向代理的 pypiserver 运行等等,我们后面有时间再进行介绍。有需要的童鞋也可参考 pypiserver 的 GitHub 说明文档:https://github.com/pypiserver/pypiserver

参考资料

公众号:生信科技爱好者
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • 无题 文/梨落如风(西安) 篮球弹进框子。他用一个漂亮的三分球,终结了焦灼的七点十分。此时天色尚早,月亮尚未填进...
    北方的海洋阅读 104评论 0 0
  • 第五章 身世 “吼。”那只白熊轻轻地叫了声,然后又转身跑了。 “这究竟是怎么回事?不过它现在好像对我没有什么恶意...
    道非道名可名阅读 142评论 0 0
  • 不懂感恩的人,无论表面上有多大的成就,看起来多么光鲜亮丽,根本就不可能幸福,等于什么也没得到:不感恩,就不珍惜;不...
    璞学苑阅读 441评论 0 0