From 7dec188f7c040f09de90de0f77b0feb02b93e71b Mon Sep 17 00:00:00 2001 From: kangcheolung Date: Fri, 9 Oct 2026 14:59:27 +0900 Subject: [PATCH 1/2] =?UTF-8?q?chore:=20#452=20=EC=9E=84=EB=B2=A0=EB=94=A9?= =?UTF-8?q?=20=EC=84=9C=EB=B2=84=20torch=EB=A5=BC=20=ED=94=8C=EB=9E=AB?= =?UTF-8?q?=ED=8F=BC=EB=B3=84=20=EC=A1=B0=EA=B1=B4=EB=B6=80=20=EA=B3=A0?= =?UTF-8?q?=EC=A0=95=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit torch==2.4.1은 PyPI의 일반 휠도 만족해, PyTorch CPU 저장소에 접속하지 못하면 pip가 경고 없이 일반 휠을 선택하고 nvidia-* 12개가 다시 설치된다. x86 Linux에서만 torch==2.4.1+cpu를 요구해 CPU 저장소 장애 시 설치가 실패하게 하고, CPU 저장소에 +cpu 휠이 없는 arm64·macOS는 기존 torch==2.4.1을 유지한다. 서버 코드와 API는 변경하지 않는다. Co-Authored-By: Claude Sonnet 5.5 --- backend/embedding-server/requirements.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/embedding-server/requirements.txt b/backend/embedding-server/requirements.txt index 91685f9f..3f037bb3 100644 --- a/backend/embedding-server/requirements.txt +++ b/backend/embedding-server/requirements.txt @@ -1,9 +1,13 @@ -# torch를 NVIDIA 독점 패키지(nvidia-*)가 딸려오는 GPU용이 아닌 CPU 전용 빌드로 받는다. +# Linux x86_64에서는 NVIDIA 독점 패키지(nvidia-*)가 딸려오는 GPU용 torch 대신 CPU 전용 빌드(+cpu)를 강제한다. +# CPU 저장소에 접속하지 못하면 일반 torch로 넘어가지 않고 설치가 실패한다. --extra-index-url https://download.pytorch.org/whl/cpu fastapi==0.115.0 uvicorn==0.30.6 FlagEmbedding==1.2.11 -torch==2.4.1 +# arm64·macOS는 CPU 저장소에 +cpu 휠이 없고 GPU 패키지도 딸려오지 않아 기존 torch를 그대로 쓴다. +# 환경 마커에는 not을 쓸 수 없어 두 번째 줄은 첫 번째 조건의 반대를 or로 풀어 적는다. +torch==2.4.1+cpu ; sys_platform == "linux" and platform_machine == "x86_64" +torch==2.4.1 ; sys_platform != "linux" or platform_machine != "x86_64" transformers==4.44.2 peft==0.12.0 numpy==1.26.4 From 0e7cd4cdb783e98849404df5986862faff38b6da Mon Sep 17 00:00:00 2001 From: kangcheolung Date: Fri, 9 Oct 2026 14:59:27 +0900 Subject: [PATCH 2/2] =?UTF-8?q?docs:=20#452=20=EC=9E=84=EB=B2=A0=EB=94=A9?= =?UTF-8?q?=20=EC=84=9C=EB=B2=84=20torch=20=ED=94=8C=EB=9E=AB=ED=8F=BC=20?= =?UTF-8?q?=EB=A7=88=EC=BB=A4=20=EC=84=A4=EA=B3=84=20=EB=AC=B8=EC=84=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 배경, 결정(x86 Linux만 +cpu 강제), 선택하지 않은 방법, 재현과 4개 환경 검증, 검증하지 못한 범위를 기록한다. Co-Authored-By: Claude Sonnet 5.5 --- ...ng-#452-embedding-torch-platform-marker.md | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 docs/design/kangcheolung-#452-embedding-torch-platform-marker.md diff --git a/docs/design/kangcheolung-#452-embedding-torch-platform-marker.md b/docs/design/kangcheolung-#452-embedding-torch-platform-marker.md new file mode 100644 index 00000000..286fb4e0 --- /dev/null +++ b/docs/design/kangcheolung-#452-embedding-torch-platform-marker.md @@ -0,0 +1,106 @@ +# #452 임베딩 서버 torch를 플랫폼별 조건부 고정으로 바꿔 CPU 저장소 장애 시 NVIDIA 패키지 재유입 방지 + +closes #452 + +#450(PR #451)의 후속이다. + +--- + +## 배경 + +#450에서 `requirements.txt`에 PyTorch CPU 저장소(`--extra-index-url https://download.pytorch.org/whl/cpu`)를 추가해, linux/amd64 이미지에서 `torch 2.4.1+cpu`를 받고 NVIDIA 독점 패키지(`nvidia-*`) 12개를 제거했다. + +그러나 요구사항이 `torch==2.4.1`로 남아 있었다. + +- `==2.4.1`은 CPU 저장소의 `2.4.1+cpu`뿐 아니라 PyPI의 일반 `2.4.1`도 만족한다. (PEP 440은 `==`에서 local version 표기를 무시한다.) +- pip는 기본 인덱스와 추가 인덱스에 우선순위를 두지 않는다. 사용할 수 있는 후보 중에서 고른다. +- 따라서 **CPU 저장소에 접속하지 못하면 pip는 경고 없이 PyPI의 일반 `2.4.1`을 선택하고**, 이 휠은 `nvidia-*` 12개를 의존성으로 끌어온다. + +외부 접속이 제한된 서버나 CI에서 이미지를 빌드하면 라이선스 문제가 에러 없이 되살아난다. + +### 재현 (병합된 `develop`의 `requirements.txt`, linux/amd64, 저장소 접속 불가) + +접속 불가는 `download.pytorch.org`를 `127.0.0.1`로 돌려(`docker run --add-host`) 흉내 냈다. + +| 결과 | 값 | +|---|---| +| `pip install --dry-run` 종료코드 | **0 (성공)** | +| 선택된 torch | 일반 `2.4.1` | +| `nvidia-*` | **12개** | +| 설치 패키지 수 | 76개 | + +--- + +## 결정 + +**x86 Linux에서만 `+cpu`를 강제하고, 나머지 플랫폼은 기존 `torch==2.4.1`을 유지한다.** + +```text +torch==2.4.1+cpu ; sys_platform == "linux" and platform_machine == "x86_64" +torch==2.4.1 ; sys_platform != "linux" or platform_machine != "x86_64" +``` + +- x86 Linux에서는 `+cpu` 라벨이 붙은 휠만 요구하므로, CPU 저장소에 접속하지 못하면 일치하는 휠이 없어 **설치가 실패**한다. 일반 휠로 넘어가지 않는다. +- 활성화되는 줄은 항상 정확히 1개다. +- `--extra-index-url` 줄은 유지한다. +- 환경 마커에는 `not`을 쓸 수 없다(pip가 `InvalidMarker`로 거부). 그래서 두 번째 줄은 첫 번째 조건의 반대를 `or`로 풀어 적는다. + +### 선택하지 않은 방법 + +- **`torch==2.4.1+cpu`로 단독 고정**: x86에서는 문제를 막지만, CPU 저장소에는 linux/arm64와 macOS용 `+cpu` 휠이 없다(arm64용은 라벨 없는 `2.4.1`). 개발 PC(Apple Silicon)의 Docker 빌드가 `No matching distribution`으로 실패한다. 이 실패를 linux/arm64에서 재현했다. +- **Dockerfile에서 빌드 후 `nvidia-*`를 검사**: 마커 방식으로 핵심 위험이 막히므로 이번에는 추가하지 않는다. 이후 의존성 변화까지 잡고 싶으면 별도로 검토한다. +- **`--index-url`로 기본 인덱스를 교체**: PyPI의 나머지 패키지를 받지 못한다. + +--- + +## API 명세 + +변경 없음. 서버 코드와 `/embed`, `/embed/batch`, `/health*`, `/metrics` 계약은 그대로다. + +--- + +## 변경 범위 + +| 파일 | 변경 | +|---|---| +| `backend/embedding-server/requirements.txt` | `torch==2.4.1`을 플랫폼별 두 줄로 변경하고 주석 수정 | + +`Dockerfile`과 `requirements-test.txt`(`-r requirements.txt`)는 변경하지 않는다. 두 곳 모두 같은 파일을 읽으므로 이미지와 로컬 테스트가 같은 조건을 쓴다. + +--- + +## 검증 + +수정한 실제 `requirements.txt`와 `requirements-observability.txt`를 `python:3.11-slim`에서 `pip install --dry-run`으로 확인했다. + +| 환경 | CPU 저장소 | 종료코드 | torch | `nvidia-*` | 판정 | +|---|---|---|---|---|---| +| linux/amd64 | 정상 | 0 | `2.4.1+cpu` | 0개 | 기대대로 | +| linux/amd64 | 접속 불가 | **1** | `No matching distribution found for torch==2.4.1+cpu` | - | **실패해야 하는 경로, 기대대로** | +| linux/arm64 | 정상 | 0 | `2.4.1` | 0개 | 기대대로 | +| linux/arm64 | 접속 불가 | 0 | `2.4.1` | 0개 | 기대대로 (arm64는 원래 GPU 패키지가 없음) | + +실제 이미지 빌드와 테스트도 확인했다. + +| 항목 | 결과 | +|---|---| +| linux/amd64 이미지 빌드 | 성공. `x86_64`, `torch 2.4.1+cpu`, `torch.version.cuda=None`, `nvidia-*` 0개 | +| linux/arm64 이미지 빌드 | 성공. `aarch64`, `torch 2.4.1`, `torch.version.cuda=None`, `nvidia-*` 0개 | +| **linux/amd64 + CPU 저장소 접속 불가 상태의 `docker build`** | **빌드 실패(종료코드 1), 이미지 생성 안 됨** | +| `pytest test_main.py` (`requirements-test.txt` 설치 포함) | amd64 22 passed, arm64 22 passed | + +비교 기준으로 병합된 `develop`의 `requirements.txt`를 같은 조건(amd64, 저장소 접속 불가)에서 돌리면 위 "재현"의 결과(성공, `nvidia-*` 12개)가 나온다. + +### 검증하지 못한 범위 + +- 임베딩 값 비교와 `/health/ready`는 이번에 다시 하지 않았다. x86에서 설치되는 torch는 #450에서 이미 검증한 `2.4.1+cpu`와 같은 휠이고, 이번 변경은 설치 조건만 바꾸므로 설치 결과가 달라지지 않는다는 판단이다. (#450 설계 문서의 amd64 에뮬레이션 검증 결과 참조) +- 접속 불가는 `--add-host`로 흉내 낸 것이며 실제 방화벽·프록시 환경에서 재현한 것은 아니다. +- 운영 x86 서버의 이미지는 이 변경만으로 바뀌지 않는다. 재빌드·재배포 후 `nvidia-*` 0개, `torch 2.4.1+cpu`, `/health/ready`, 임베딩 값 비교를 확인해야 한다. + +--- + +## 이 이슈의 범위 밖 + +- README 라이선스 표 보강과 전이 의존성을 포함한 구성요소 목록, MinIO 이미지 태그 고정, 모델 버전 기록 +- `docs/images/architecture.png`의 Redis 로고 교체 +- MinIO·Grafana(AGPL-3.0)의 의무 범위는 OpenUP 멘토링에서 확인한다.