使用Devpi与Nginx构建高可用PyPI镜像源
前言:为什么你的pip install
又超时了?
对于每一位Python开发者来说,pip install
无疑是最常用的命令之一。然而,团队开发中,我们常常会遇到这些痛点:
- 速度瓶颈:团队几十号人,CI/CD流水线上百个任务,全都从国外的官方PyPI源拉取包,下载速度慢得令人抓狂,严重影响开发和部署效率。
- 单点故障:官方PyPI偶尔会抖动,或者公司出口网络出现问题,导致所有依赖安装失败,研发流程瞬间停摆。
- 安全与合规:无法对团队使用的第三方包进行统一管理和安全审计。
- 私有包托管:团队内部开发的公共库无处安放,只能通过Git仓库等原始方式共享。
为了彻底解决这些问题,我们需要一个私有的、高速的、且永不宕机的Python包仓库。今天,我将手把手带你使用业界最强大的开源工具 devpi
和 Nginx
,构建一个具备自动故障转移能力的高可用PyPI镜像源。
最终目标:无论清华源、阿里源还是其他任何一个镜像挂了,我们的 pip install
依然能丝滑流畅地运行,对开发者完全透明!
1 | +-----------+ +-------------------+ +-------------------------+ +--------------------------+ |
第一章:核心武器介绍 - Devpi 与 Nginx
在开始之前,我们先了解一下两位主角:
-
Devpi: 一个功能完备的Python包服务器。它不仅仅是
pypi.org
的一个缓存代理,更是一个强大的私有包仓库和版本发布管理工具。我们将主要利用它的缓存镜像功能。 -
Nginx: 一款高性能的HTTP和反向代理服务器。在这里,它将扮演我们镜像源的“智能调度员”和“故障哨兵”,负责监测上游镜像源的健康状况,并在某个源出现问题时,自动将流量切换到健康的备用源上。
第二章:基础建设 - 搭建Devpi缓存服务器
首先,我们需要一个能稳定运行的devpi
服务。
步骤 1: 准备服务器与安装Devpi
在一台Linux服务器(本教程以Ubuntu为例)上,确保已安装Python和pip。
1 | # 更新并安装依赖 |
步骤 2: 初始化Devpi
这个一次性操作会为你创建数据目录和 root
超级管理员。
1 | devpi-init |
在提示中,为 root
用户设置一个安全的密码,并牢牢记住它。
步骤 3: 让Devpi在后台稳定运行
为了生产环境的稳定,我们将 devpi
配置成一个 systemd
系统服务,实现开机自启和后台运行。
-
创建服务文件:
1
sudo nano /etc/systemd/system/devpi.service
-
粘贴以下配置 (注意修改
User
和ExecStart
中的路径为你自己的):
1 | (venv) czq2@czq2:~/clip-video$ sudo cat /etc/systemd/system/devpi.service |
--host=0.0.0.0
确保局域网内的其他机器可以访问。
- 启动并验证服务:看到绿色的
1
2
3
4sudo systemctl daemon-reload
sudo systemctl enable devpi # 开机自启
sudo systemctl start devpi # 启动
sudo systemctl status devpi # 检查状态active (running)
,恭喜你,基础的devpi
镜像服务已经成功运行在http://<你的服务器IP>:3141
上了!
- 成功输出
1 | (venv) czq2@czq2:~/clip-video$ sudo systemctl start devpi |
- 错误分析
1 | sudo journalctl -u devpi.service -n 50 --no-pager |
第三章:构建护城河 - Nginx高可用反向代理
现在,我们要为 devpi
构建一个坚固的前哨站,让它不再直接依赖任何单一的上游源。
步骤 1: 安装 Nginx
1 | sudo apt update |
步骤 2: 编写Nginx高可用配置
这是实现自动故障转移的核心。
-
创建Nginx配置文件:
1
sudo nano /etc/nginx/sites-available/pypi-proxy
-
粘贴以下魔法配置:
1 |
|
- 启用配置并重启Nginx:现在,一个强大的、能自动切换源的反向代理已经在
1
2
3sudo ln -s /etc/nginx/sites-available/pypi-proxy /etc/nginx/sites-enabled/
sudo nginx -t # 测试配置语法
sudo systemctl restart nginx # 重启Nginxhttp://192.168.10.158:8088
上为你待命。
第四章:合体!将Devpi接入Nginx代理
万事俱备,只差最后一步:让 devpi
通过我们的 Nginx “护城河”去访问世界。
-
停止Devpi服务:
1
sudo systemctl stop devpi
-
修改Devpi的启动参数:
1
sudo nano /etc/systemd/system/devpi.service
-
在
ExecStart
行的末尾,添加--mirror-url
参数,指向我们的Nginx代理:1
2
3# ...
ExecStart=/home/your_username/.local/bin/devpi-server --host=0.0.0.0 --port=3141 --mirror-url http://192.168.10.158:8088/pypi
# ... -
重新加载并启动Devpi:
1
2sudo systemctl daemon-reload
sudo systemctl start devpi
第五章:享受成果 - 配置客户端
现在,让团队的所有开发者和CI/CD服务器都享受到这个稳定高速的镜像源吧!
在每一台客户端机器上,创建或修改 ~/.pip/pip.conf
(macOS/Linux) 或 %APPDATA%\pip\pip.ini
(Windows) 文件:
1 | [global] |
index-url
指向我们搭建的devpi
服务。trusted-host
告诉pip
这是一个可信任的HTTP源。
使用docker compose 搭建 devpi
- docker-comose.yml
1 | # version 属性已过时,可以移除 |
- nignx conf
1 | # nginx_conf/nginx.conf (HTTP 代理版本) |
- docker run
1 | sudo docker-compose up -d --build |
自建devpi镜像
- Dockerfile
1 | # Dockerfile (最终稳定版) |
- docker-compose.yml
1 | # docker-compose.yml (最终、决定性版本) |
-
- 在你的客户端电脑上,安装
devpi-client
:
1
2sudo chown -R czq2:czq2 ./volume # 更改目录权限
pip install devpi-client - 在你的客户端电脑上,安装
-
- 登录到你的新
devpi
服务器:
1
2
3
4
5
6
7# 指向服务器
devpi use http://<你的服务器IP>:7104
# 首次登录 root 用户,devpi-server 会自动创建,无需密码
# 然后会强制你设置新密码
devpi login root --password=""
# (按照提示输入你的新 root 密码) - 登录到你的新
-
- 【关键】配置
root/pypi
镜像:
默认的root/pypi
指向pypi.org
。我们需要将它修改为指向我们内部的nginx-proxy
。
1
2# 确保你已登录 root
devpi index root/pypi mirror_url=http://nginx-proxy- 注意: 这里的
http://nginx-proxy
是devpi-lib
容器内部访问nginx-proxy
容器的地址。devpi-server
在收到这个配置后,它内部发起的请求就会走这条路。
- 【关键】配置
-
- 验证:
在你的客户端电脑上,配置好pip
指向http://<服务器IP>:7104/root/pypi/
,然后执行pip install numpy
。
- 验证:
成功日志
1 | (.venv) czq2@czq2:~/pypi-docker$ sudo docker logs devpi-lib |
python 搭建高可用
- python flask
1 | # ha_proxy.py |
- supervisord.conf
1 | ; supervisord.conf (最终生产版) |
同步更新dockerfile和docker-compose.yml
- Dockerfile
1 | # Dockerfile (最终生产版) |
- docker-compose.yml
1 | # docker-compose.yml (与最终高可用版 Dockerfile 配合使用) |
- docker build
1 |
|
- mirror set
1 | devpi login root --password="" |