3、私有包仓库搭建:使用Nexus搭建私有PyPI仓库

说实话,做SDK发布最头疼的事是什么?

不是写代码,是包管理。

你想想看,公司内部几十个SDK模块,全扔到公共PyPI上?不合适。自己搞个文件服务器存whl包?版本乱成一锅粥。我经历过那种「这个包是谁传的?版本号怎么对不上?」的噩梦,后来才下定决心——必须上私有仓库。

今天咱们就聊聊怎么用Nexus搭一个靠谱的私有PyPI仓库。这东西我用了好几年,踩过坑,也总结了些经验,分享给你。

3.1 为什么选Nexus?

市面上的私有仓库方案不少,比如pypiserver、devpi、Artifactory。我个人习惯用Nexus,原因有三:

  • 全能型选手:不光管PyPI,还能管npm、Docker、Maven。一个服务搞定所有包类型
  • 权限控制成熟:LDAP集成、角色管理、仓库级别的读写权限,企业级需求都能满足
  • 社区版够用:免费版的功能已经覆盖了90%的日常场景

我在项目中遇到过团队用pypiserver,结果权限全靠文件系统控制,后来有人误删了包,回滚都找不到版本。从那以后,我对权限管理就特别敏感。

3.2 安装与初始化

Nexus的安装方式很多,我推荐用Docker,省心。

# 拉取镜像
docker pull sonatype/nexus3:latest

# 启动容器
docker run -d \
  --name nexus \
  -p 8081:8081 \
  -p 8082:8082 \
  -v /data/nexus:/nexus-data \
  sonatype/nexus3:latest

启动后访问 http://localhost:8081,默认管理员账号是 admin,密码在容器里的 /nexus-data/admin.password 文件中。

注意:第一次登录会让你改密码。别偷懒用弱密码,我见过有人用「admin123」,结果被内部同事扫出来乱删包。

3.3 创建PyPI仓库

Nexus的仓库类型有三种,咱们得先搞清楚:

仓库类型 说明 用途
hosted 托管私有包 存放公司内部开发的SDK
proxy 代理公共仓库 缓存PyPI官方包,加速下载
group 组合多个仓库 把hosted和proxy合并成一个地址

我一般会建三个仓库:

  1. pypi-hosted:私有包存放地
  2. pypi-proxy:代理 https://pypi.org
  3. pypi-group:把上面两个组合起来

操作步骤很简单:

1. 登录Nexus Web界面
2. 点击左侧「Repositories」→「Create repository」
3. 选择「pypi (hosted)」
4. 填写名称:pypi-hosted
5. 部署策略选「Allow redeploy」(允许覆盖,方便调试)
6. 点击「Create repository」
小技巧:部署策略我建议开发环境用「Allow redeploy」,生产环境改成「Disable redeploy」。曾经有同事在生产环境覆盖了一个稳定版本,导致下游构建全部失败,教训深刻。

3.4 配置认证与权限

仓库建好了,不能谁都能上传吧?

Nexus的权限模型分三层:用户 → 角色 → 权限。我习惯这样配:

3.4.1 创建角色

角色名:pypi-developer
权限:
  - nx-repository-view-pypi-*-browse
  - nx-repository-view-pypi-*-read
  - nx-repository-view-pypi-*-edit

角色名:pypi-admin
权限:
  - nx-repository-view-pypi-*-*
  - nx-repository-admin-pypi-*-*

3.4.2 创建用户并分配角色

用户名:sdk-publisher
角色:pypi-admin
用途:CI/CD流水线使用

用户名:sdk-developer
角色:pypi-developer
用途:开发人员下载包

嗯,这里要注意:密码别写在代码里。我一般用CI/CD的密钥管理服务,或者Nexus自带的「User Token」功能。

3.5 上传私有包

上传包需要配置 ~/.pypirc 文件:

[distutils]
index-servers =
    nexus

[nexus]
repository: http://localhost:8081/repository/pypi-hosted/
username: sdk-publisher
password: your-password

然后就可以上传了:

# 构建包
python setup.py sdist bdist_wheel

# 上传到私有仓库
twine upload --repository nexus dist/*

我在项目中遇到过一个问题:上传时提示 403 Forbidden。排查了半天,发现是用户权限没配好,少给了 edit 权限。所以上传前先确认角色权限。

3.6 下载私有包

下载就简单了,配置 pip.conf 指向group仓库:

[global]
index-url = http://localhost:8081/repository/pypi-group/simple/
trusted-host = localhost

# 如果需要认证
[install]
extra-index-url = http://sdk-publisher:password@localhost:8081/repository/pypi-group/simple/

然后正常使用pip:

pip install my-private-sdk==1.0.0

为什么用group仓库而不是直接指向hosted?因为group仓库会先查私有包,找不到再去公共PyPI拉,这样你只需要配一个源地址。

3.7 核心逻辑流程图

下面这张图是我画的私有包仓库整体架构,你看一眼就明白了:

开发者 / CI pypi-group 组合仓库 先查私有 pypi-hosted 再查公共 pypi-proxy 代理缓存 PyPI 上传私有包 私有PyPI仓库架构图 hosted(私有包) proxy(代理缓存) group(组合入口)

3.8 避坑指南

最后分享几个我踩过的坑:

坑1:版本号规范

私有包版本号一定要遵循PEP 440规范。我曾经用 1.0.0-beta 这种格式,结果pip解析失败。正确写法是 1.0.0b1。

坑2:仓库清理策略

Nexus默认不会自动清理旧版本。时间长了磁盘会爆。建议设置「Cleanup Policies」,保留最近10个版本,或者保留90天内的版本。

坑3:HTTPS配置

生产环境一定要配HTTPS。我见过有人用HTTP传输,密码被中间人抓包。Nexus支持反向代理,用Nginx加个证书就行。

好了,私有PyPI仓库的搭建就聊到这儿。这套方案我在多个项目里验证过,稳定可靠。你照着做,基本不会出大问题。

可可精品资料库