재현 가능한 빌드를 만들려고 의존성 버전을 전부 고정했다. requirements.txt 를 == 로 박고, 로컬에서 잘 도는 걸 확인한 뒤 올렸다. 그런데 CI 가 이렇게 실패했다.
ERROR: Ignored the following versions that require a different python version:
2.5.0 Requires-Python >=3.12; 2.5.2 Requires-Python >=3.12
ERROR: Could not find a version that satisfies the requirement numpy==2.5.2
ERROR: No matching distribution found for numpy==2.5.2
파일에는 분명히 numpy==2.5.2 라고 적혀 있는데, 그 버전을 못 찾는다고 한다.
원인
numpy 는 2.5 부터 파이썬 3.12 이상만 지원한다.
내 개발 기계는 파이썬 3.14 였다. 거기서 설치된 numpy 2.5.2 를 그대로 고정했다. 그런데 배포와 CI 는 파이썬 3.11 이다. 3.11 에는 numpy 2.5 휠이 아예 없다. 그래서 설치 단계에서 멈춘다.
[로컬 3.14] freeze → numpy==2.5.2 가 박힌다
[배포 3.11] 설치 → 2.5.x 는 3.12+ 전용, 설치 불가
로컬만 3.14 라 로컬에선 멀쩡했다. 문제는 배포 환경에서만 드러났다. 고정 파일이 잘못된 게 아니라, 잘못된 환경에서 고정한 것이다.
도구도 같은 함정에 빠진다
의존성 취약점을 점검하는 pip-audit 를 돌렸더니 똑같은 에러로 감사가 시작조차 안 됐다.
pip-audit -r requirements.txt
# → No matching distribution found for numpy==2.5.2
이 도구는 임시 가상환경을 만들어 requirements 를 설치해 본 뒤 감사한다. 그 가상환경의 파이썬이 3.11 이면, 역시 numpy 2.5 를 못 깔아 설치 단계에서 넘어진다.
즉 도구를 프로젝트와 다른 파이썬으로 돌리면, 도구가 배포 환경을 흉내 내지 못한다. 프로젝트 파이썬으로 돌려야 한다.
# 프로젝트 파이썬으로 실행
./.venv/Scripts/python -m pip_audit -r requirements.txt
확인
각 패키지가 어떤 파이썬을 요구하는지 보면 바로 드러난다.
import json, urllib.request
d = json.load(urllib.request.urlopen('https://pypi.org/pypi/numpy/2.5.2/json'))
print(d['info']['requires_python']) # >=3.12
2.4.6 은 >=3.11, 2.5.2 는 >=3.12. 배포가 3.11 이면 2.4.x 가 마지막 호환 버전이다.
해결
배포에서 설치되는 버전으로 내렸다.
numpy==2.4.6 # 3.11+ 전용. 2.5.x 는 3.12+ 라 배포(3.11)에서 설치 불가
더 근본적으로는, 고정 파일을 배포와 같은 파이썬에서 만드는 것이다. 개발 기계에서 freeze 하지 말고, 배포와 같은 버전의 컨테이너 안에서 고정하면 이 어긋남이 애초에 생기지 않는다.
자동 갱신 봇이 되돌린다
의존성을 자동으로 올리는 봇은 배포가 3.11 인 걸 모른다. numpy 를 최신 2.5.x 로 올리는 요청을 계속 연다. 그 요청의 CI 는 매번 같은 이유로 빨간불이다.
봇에 상한을 알려 준다.
ignore:
# numpy 2.5+ 는 3.12+ 전용. 배포가 3.11 이라 상향 요청은 통과 못 한다.
- dependency-name: "numpy"
versions: [">=2.5.0"]
파이썬을 3.12 이상으로 올리기로 하면, 그때 이 규칙을 지운다.
정리
pip freeze로 만든 고정은 그 기계의 파이썬에 묶인다. 개발 기계가 배포보다 최신이면, 배포에서 안 깔리는 버전이 박힐 수 있다- 고정 파일은 배포와 같은 파이썬 환경에서 만든다
- 취약점 점검 같은 도구도 프로젝트 파이썬으로 돌려야 배포 환경을 재현한다
- 자동 갱신 봇에는 배포 환경과 맞지 않는 상향을 무시하도록 상한을 건다
버전을 고정할 땐 “무엇을 고정했나” 보다 “어디서 고정했나” 를 먼저 본다. 개발 기계는 배포보다 앞서 있는 경우가 많고, 그 차이는 로컬에서 끝까지 보이지 않는다.
댓글