인터넷이 되는 장비에서 pip download 로 패키지를 모아 폐쇄망으로 옮기고 pip install --no-index 로 설치하는 방식이다. 요구사항 목록을 그대로 넘기면 상당수가 중간에 실패하는데, 원인이 몇 가지 유형으로 나뉜다. 유형을 알면 "왜 없다고 하는지"를 바로 판정할 수 있다.
pip download -d ./python-repo -r requirements.txt
pip install --no-index --find-links=./python-repo -r requirements.txt
Could not find a version that satisfies the requirement — 가능한 버전 목록이 함께 나올 때ERROR: Could not find a version that satisfies the requirement bleach==5.0.1
(from versions: 0.2.1, ..., 4.0.0, 4.1.0)
ERROR: No matching distribution found for bleach==5.0.1
괄호 안에 버전 목록이 나왔다는 것 자체가 인덱스 접속은 성공했다는 뜻이다. 패키지는 있는데 지금 환경에 맞는 배포본이 없는 것이다. 원인은 셋 중 하나다.
파이썬 버전이 낮다. 배포본에는 Requires-Python 이 들어 있고 pip 은 그 조건에 맞는 것만 후보로 본다. 위 예시에서 4.1.0 까지만 보였다면 5.x 가 요구하는 파이썬보다 실행 중인 파이썬이 낮다는 뜻이다.
python3 -V
pip -V
대상 환경이 아니라 현재 환경 기준으로 받고 있다. 기본적으로 pip download 는 지금 실행 중인 인터프리터와 플랫폼에 맞는 것을 받는다. 수집 장비와 설치 장비의 파이썬 버전이나 OS 가 다르면 여기서 어긋난다. 대상을 명시한다.
pip download -d ./python-repo \
--python-version 3.11 --platform manylinux2014_x86_64 \
--implementation cp --abi cp311 \
--only-binary=:all: \
-r requirements.txt
이 옵션들은 --only-binary=:all: 과 함께여야만 동작한다. 소스 배포본은 받는 쪽 환경에서 빌드해야 하므로 pip 이 교차 판정을 할 수 없기 때문이다. 순수 파이썬 패키지는 --platform any 로도 받아진다.
pip 이 너무 오래됐다. 오래된 pip 은 새 wheel 태그(manylinux_2_28, musllinux 등)를 이해하지 못해 있는 wheel 을 건너뛰고 "없다"고 한다. 수집 장비의 pip 을 먼저 올린다.
python3 -m pip install --upgrade pip
(from versions: none) 일 때ERROR: Could not find a version that satisfies the requirement s3-transfer==1.9.5 (from versions: none)
버전 목록이 비어 있으면 그 이름의 패키지를 인덱스에서 찾지 못한 것이다. 판정 순서는 다음과 같다.
이름이 틀렸다. 하이픈과 밑줄, 접두사가 어긋난 경우가 흔하다. 위 예시의 실제 이름은 s3transfer 다. PyPI 에서 이름을 직접 확인한다.
curl -s -o /dev/null -w '%{http_code}\n' https://pypi.org/pypi/s3transfer/json
공개 PyPI 에 없는 패키지다. 벤더가 주는 사내 패키지, 설치 매체에만 들어 있는 패키지가 여기 해당한다. 받아 올 곳이 없으므로 제공처에서 .whl 또는 .tar.gz 파일을 직접 받아 수집 디렉터리에 넣는다.
인덱스가 사내 저장소로 잡혀 있다. 사내 미러가 그 패키지를 프록시하지 않으면 없다고 나온다.
pip config list
pip download -i https://pypi.org/simple -d ./python-repo <package>
GPU · 딥러닝 관련 패키지는 별도 인덱스에 있는 경우가 많다. graphsurgeon, uff, onnx-graphsurgeon 같은 NVIDIA 계열 패키지는 공개 PyPI 에 이름만 있고 실제 배포본은 NVIDIA 인덱스나 설치 패키지 안에 들어 있다. PyPI 에 같은 이름의 껍데기 패키지가 있어서 엉뚱한 것을 받는 경우도 있으므로 출처를 확인하고 받는다.
pip download -d ./python-repo --extra-index-url https://pypi.nvidia.com <package>
Collecting graphsurgeon
Using cached graphsurgeon-0.0.1.dev5.tar.gz (7.9 kB)
Installing build dependencies ...
.tar.gz 를 받으면 pip 은 메타데이터를 얻으려고 빌드 의존성을 인터넷에서 추가로 받아 빌드를 시도한다. 폐쇄망에서는 이 단계가 통째로 실패한다. 가능하면 wheel 만 받는다.
pip download -d ./python-repo --only-binary=:all: -r requirements.txt
wheel 이 없는 패키지는 수집 장비에서 미리 wheel 로 만들어 옮긴다. 이때 수집 장비의 OS 와 파이썬이 설치 대상과 같아야 한다. 컴파일이 필요한 패키지는 대상과 같은 이미지에서 만드는 것이 확실하다.
pip wheel -w ./python-repo <package>
옮기기 전에 같은 조건으로 오프라인 설치가 되는지 확인한다. 이 단계를 건너뛰면 폐쇄망에 들어간 뒤에야 빠진 것을 발견한다.
python3 -m venv /tmp/offline-check
/tmp/offline-check/bin/pip install --no-index --find-links=./python-repo -r requirements.txt
--no-index 를 주지 않으면 빠진 패키지를 조용히 인터넷에서 받아 성공한 것처럼 보인다.