用轮子仓库搭建内部 Python 索引
目标
在联网的一侧把 Python 软件包及其依赖收集为 wheel,并用哈希固定;然后在隔离网络一侧搭建 PEP 503 内部索引,通过 pip.conf 指向它,并确认即使外部被封闭也能完成安装。
为什么重要
隔离网络导入中代价最高的错误,是“带走了却不够,还得再出去”和“带走了却在服务器上不匹配”。前者只要在外部把依赖整体解析后带走就能避免,后者只要写明目标服务器的 Python 版本和平台再下载就能避免。而在介质传递过程中被改动的文件,会被哈希检查模式抓到。这个 Pod 一开始就能访问互联网(80/443),所以承担下载端的角色,而隔离网络一侧的确认,由评分器把发往外部的 HTTP(S) 转到关闭的代理上,在封闭的状态下进行。
步骤
- 把
requests==2.32.3及其依赖只按这个 Pod 的 Python(3.12)所用的 wheel 下载,收集到/root/pip/wheelhouse/中。 - 隔离网络服务器是 Python 3.11(x86_64,manylinux2014)。把同样的需求按该目标所用的 wheel 下载,收集到
/root/pip/wheelhouse-py311/中。 - 创建
/root/pip/requirements.txt,把/root/pip/wheelhouse/中的所有 wheel 都写成이름==버전 --hash=sha256:<값>(占位符依次为软件包名、版本和哈希值)这样的行。 - 在每个
/srv/pypi/simple/<정규화한 이름>/(占位符为规范化后的名称)目录中放入相应的 wheel,做成 PEP 503 形式的索引。 - 在
/etc/hosts中加入127.0.0.1 pypi.airgap.internal,并启动把/srv/pypi通过 8080 端口提供出去的python3 -m http.server。访问记录保存到/root/pip/index.log。 - 在
/etc/pip.conf中写入index-url = http://pypi.airgap.internal:8080/simple,以及信任该地址的设置。评分器会在外部被封闭的情况下,查看仅凭这项配置能否下载到 requests。 - 创建 venv
/root/pip/venv,并以哈希检查模式安装requirements.txt。 - 假设没有索引,在 venv
/root/pip/venv-usb中用--no-index --find-links /root/pip/wheelhouse安装同样的需求。
参考
- 只下载:
pip download -d <디렉터리> ...(占位符为目录)、指定目标:--platform manylinux2014_x86_64 --python-version 3.11 --only-binary=:all: - 一行哈希:
pip hash <휠>(占位符为 wheel 文件名)、读取了哪个配置文件:pip config debug - 名称规范化:转为小写,并把连续的
.、-、_替换为一个-。charset_normalizer→charset-normalizer - 常见错误 1:对
http://的内部索引去掉trusted-host。pip 只会留下警告并忽略该索引。 - 常见错误 2:直接安装到系统 Python。Ubuntu 24.04 依据 PEP 668 会拦下——请使用 venv。
- 常见错误 3:关闭启动服务器的终端,或者把服务器杀掉。第 6–7 步的评分需要服务器处于运行状态。
下载端:连依赖一起下载 wheel
把 requests==2.32.3 及其依赖只按 wheel 下载(使用这个 Pod 的 Python 所对应的版本),收集到 /root/pip/wheelhouse/ 中。
pip 有一个不安装、只收集文件的子命令。如果混入源码分发包(.tar.gz),隔离网络服务器上就会要求构建工具,所以也请同时使用只下载二进制文件的选项。
按目标服务器的 Python 来下载
为 Python 3.11(x86_64,manylinux2014)服务器下载同样的需求,收集到 /root/pip/wheelhouse-py311/ 中。
pip download 可以单独指定目标的平台和 Python 版本。文档写明,有一个选项必须与这些选项一起使用。下载之后,请查看文件名中的标签(cp311 等)。
用版本和哈希固定
创建 /root/pip/requirements.txt,把 /root/pip/wheelhouse/ 中的所有 wheel 都写成 이름==버전 --hash=sha256:<값>(占位符依次为软件包名、版本和哈希值)这样的行。
wheel 文件名的前两段就是名称和版本。有一个子命令可以让 pip 直接计算哈希,其值与 sha256sum 相同。在同一行中同时写上需求和 --hash。
制作 PEP 503 形式的内部索引
在每个 /srv/pypi/simple/<정규화한 이름>/(占位符为规范化后的名称)目录中放入相应的 wheel。
目录名必须是按规范对软件包名称进行规范化后的结果,pip 才能找到。小写,并且连续的点、连字符、下划线换成一个连字符。不要与 wheel 文件名内部的下划线混淆。
用内部名称启动索引
在 /etc/hosts 中加入 127.0.0.1 pypi.airgap.internal,并启动把 /srv/pypi 通过 8080 端口提供出去的服务器。访问记录保存到 /root/pip/index.log。
Python 标准库的 http.server 会以文件名链接的形式提供目录列表。请把要提供的目录和端口作为参数传入,并放到后台启动,使关闭终端后仍然存活。这个服务器把访问记录输出到标准错误。
用 pip.conf 指向内部索引
在 /etc/pip.conf 中写入 index-url = http://pypi.airgap.internal:8080/simple,以及信任该地址的设置。
pip 默认不信任非 https 的索引(只有 localhost 例外)。有一个设置键可以让它信任某个主机名。请用 pip config debug 确认文件是否真的被读取。
用哈希检查模式安装到 venv
创建 venv /root/pip/venv,并以哈希检查模式安装 /root/pip/requirements.txt。
Ubuntu 24.04 的系统 Python 无法直接安装。请先创建 venv,再用其中的 pip 安装 requirements 文件。文件中只要有 --hash,哈希检查模式就会开启,不过也有用来显式指定的选项。
不用索引,只靠 wheelhouse 安装
创建 venv /root/pip/venv-usb,并用 --no-index --find-links /root/pip/wheelhouse 安装 /root/pip/requirements.txt。
把让 pip 完全不看索引的选项,与指定查找文件的目录的选项一起使用。这样安装能成功,就意味着 wheelhouse 本身是完整的。