Windows 등 이종 빌드 머신에서 pip download 시 --platform 은 wheel 태그만 바꾸고 환경마커(sys_platform/python_version)는 빌드 머신 기준으로 평가돼 uvloop(리눅스)·sniffio·exceptiongroup(Py<3.11)이 누락되고 colorama·tzdata (win32)가 딸려오는 문제를 문서화. RHEL9/Py3.9 검증 절차(본체 + 이름 보강 + win32 잉여 제거) + 검증 커맨드 추가. 정상 폐쇄집합 29개 명시. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
192 lines
7.9 KiB
Markdown
192 lines
7.9 KiB
Markdown
# 폐쇄망 반입·구동 가이드 (Python venv, 컨테이너 미사용)
|
|
|
|
서버관리망이 컨테이너 없이 **Python 가상환경**으로 구동하는 환경일 때의 반입 절차.
|
|
핵심은 **소스 + wheelhouse(오프라인 .whl 묶음)** 를 매체로 들고 들어가 거기서 venv로 설치·실행하는 것.
|
|
|
|
> 정적 자산(pico·htmx·Pretendard·JetBrains Mono)은 이미 `app/static/`에 동봉돼 있어 **런타임 인터넷 불필요**.
|
|
> 외부 의존은 Python 패키지(pip)뿐 → 이걸 wheelhouse로 해결한다.
|
|
|
|
---
|
|
|
|
## 0. 사전 확인 (가장 중요)
|
|
|
|
폐쇄망 **타깃 서버**에서 Python 버전·아키텍처를 확인한다. wheel은 이 값에 맞춰 받아야 한다.
|
|
```bash
|
|
python3 --version # 예: Python 3.12.x → cp312
|
|
uname -m # 예: x86_64
|
|
```
|
|
- 타깃 Python이 **3.11/3.12** 등이면 wheelhouse도 그 버전으로 받아야 한다(컴파일 wheel: pydantic-core, psycopg 등).
|
|
- 가능하면 **타깃과 같은 OS/파이썬**(예: Rocky9 + python3.12)에서 wheelhouse를 만드는 게 가장 안전하다.
|
|
|
|
---
|
|
|
|
## 1. 인터넷 되는 곳에서 산출물 준비
|
|
|
|
**(a) 소스** — git 메타·가상환경 제외하고 압축
|
|
```bash
|
|
git archive --format=tar.gz -o pulp-console-src.tgz HEAD
|
|
# (또는 repo 폴더에서 .git/.venv/tests 빼고 zip)
|
|
```
|
|
|
|
**(b) wheelhouse** — 타깃 Python/플랫폼에 맞춰 다운로드
|
|
|
|
가장 안전한 방법은 **타깃과 동일한 OS/파이썬**(예: RHEL9 + python3.9)에서 받는 것:
|
|
```bash
|
|
pip download -r requirements.txt -d vendor/
|
|
```
|
|
이 경우 환경마커가 타깃 기준으로 평가돼 의존성이 정확히 맞는다.
|
|
|
|
> ⚠️ **빌드 머신이 타깃과 다르면(특히 Windows→Linux) 주의.**
|
|
> `pip download`의 `--platform`/`--python-version`은 **wheel 태그 선택에만** 쓰이고,
|
|
> 환경마커(`sys_platform`, `python_version`)는 **빌드 머신 기준**으로 평가된다.
|
|
> 그 결과 Windows에서 받으면 **리눅스/특정파이썬 전용 의존성이 누락**되고
|
|
> (`uvloop` = 리눅스 전용, `sniffio`/`exceptiongroup` = anyio·Py<3.11 의존),
|
|
> **win32 전용 잉여 wheel**(`colorama`, `tzdata`)이 딸려 온다.
|
|
> → 이대로 타깃에서 `pip install`하면 `No matching distribution for uvloop` 등으로 실패한다.
|
|
|
|
Windows 등 이종 빌드 머신에서 **RHEL9 / Python 3.9** 용으로 받을 때(검증된 절차):
|
|
```bash
|
|
# 1) 본체 (플랫폼/버전/ABI 명시 — manylinux 범위를 넓게 잡아 2_28 전용 wheel도 잡는다)
|
|
pip download -r requirements.txt -d vendor/ \
|
|
--only-binary=:all: --implementation cp --abi cp39 --python-version 39 \
|
|
--platform manylinux_2_28_x86_64 --platform manylinux_2_17_x86_64 \
|
|
--platform manylinux2014_x86_64 --platform manylinux1_x86_64
|
|
|
|
# 2) 마커 때문에 빠진 리눅스/Py3.9 전용 의존성을 "이름으로" 보강 (마커 게이팅 우회)
|
|
pip download uvloop sniffio "exceptiongroup>=1.0.2" -d vendor/ \
|
|
--only-binary=:all: --implementation cp --abi cp39 --python-version 39 \
|
|
--platform manylinux_2_28_x86_64 --platform manylinux_2_17_x86_64 \
|
|
--platform manylinux2014_x86_64 --platform manylinux1_x86_64
|
|
|
|
# 3) 리눅스에서 안 쓰는 win32 전용 잉여 wheel 제거
|
|
rm -f vendor/colorama-*.whl vendor/tzdata-*.whl
|
|
```
|
|
`# --python-version 39 → 타깃이 3.11/3.12면 311/312, --abi 도 cp311/cp312 로 바꾼다.`
|
|
|
|
**검증(반드시)** — 받은 뒤 폐쇄집합이 맞는지 확인:
|
|
```bash
|
|
ls vendor | grep -i uvloop # 있어야 함(리눅스)
|
|
ls vendor | grep -iE 'colorama|tzdata' # 없어야 함(win32 전용)
|
|
# 컴파일 wheel은 전부 cp39 manylinux x86_64 여야 함:
|
|
ls vendor | grep -viE 'py3-none-any|py2.py3-none-any'
|
|
```
|
|
현재 requirements 기준 정상 폐쇄집합은 **29개**다(win32 잉여 제외).
|
|
|
|
> 참고: `uvicorn[standard]`는 uvloop/httptools/watchfiles 등 컴파일 wheel을 포함한다. 버전 매칭이
|
|
> 까다로우면 `requirements.txt`의 `uvicorn[standard]`를 `uvicorn`(순정)으로 바꿔 wheel 세트를 줄일 수 있다
|
|
> (운영은 `--reload` 안 쓰므로 watchfiles 불필요). 다만 위 절차로 `[standard]`도 문제없이 반입된다.
|
|
|
|
---
|
|
|
|
## 2. 반입 매체에 담을 것
|
|
|
|
- `pulp-console-src.tgz` (소스 — 정적자산 포함)
|
|
- `vendor/` (wheelhouse)
|
|
- `boknet-ca.pem` (사내 HTTPS Pulp 검증용 CA)
|
|
- 환경변수 값 메모: `PULP_BASE_URL` / `PULP_USERNAME` / `PULP_PASSWORD` / `DATABASE_URL`
|
|
(비밀번호는 안전한 방법으로)
|
|
|
|
---
|
|
|
|
## 3. 폐쇄망에서 설치·구동
|
|
|
|
```bash
|
|
mkdir -p /opt/pulp-console && cd /opt/pulp-console
|
|
tar xzf /media/pulp-console-src.tgz # 소스 풀기
|
|
cp -r /media/vendor ./vendor # wheelhouse 복사
|
|
|
|
python3 -m venv .venv
|
|
.venv/bin/pip install --no-index --find-links vendor -r requirements.txt
|
|
```
|
|
|
|
환경변수(`.env` 또는 systemd) 설정 후 실행 — **운영은 `--reload` 금지**:
|
|
```bash
|
|
PULP_BASE_URL=https://repo.서버관리망:8080 \
|
|
PULP_USERNAME=admin PULP_PASSWORD='***' \
|
|
PULP_VERIFY_TLS=true PULP_CA_FILE=/opt/pulp-console/boknet-ca.pem \
|
|
DATABASE_URL='postgresql://...' \
|
|
.venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000
|
|
```
|
|
|
|
---
|
|
|
|
## 4. 상시 구동 (systemd 예시)
|
|
|
|
`/etc/systemd/system/pulp-console.service`:
|
|
```ini
|
|
[Unit]
|
|
Description=Pulp 패치 관리 콘솔
|
|
After=network.target
|
|
|
|
[Service]
|
|
WorkingDirectory=/opt/pulp-console
|
|
EnvironmentFile=/opt/pulp-console/.env
|
|
ExecStart=/opt/pulp-console/.venv/bin/uvicorn app.main:app --host 0.0.0.0 --port 8000
|
|
Restart=on-failure
|
|
User=pulpconsole
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
```
|
|
```bash
|
|
sudo systemctl daemon-reload && sudo systemctl enable --now pulp-console
|
|
```
|
|
`.env`(권한 600)에 `PULP_*`, `DATABASE_URL`, `PULP_CA_FILE` 등 기입.
|
|
|
|
---
|
|
|
|
## 5. 구동 확인
|
|
|
|
```bash
|
|
curl 127.0.0.1:8000/healthz # {"ok": true} (앱 생존)
|
|
curl 127.0.0.1:8000/pulp-status # Pulp 연결 배지 (실패 시 사유)
|
|
```
|
|
브라우저로 대시보드 접속 → 실제 저장소 목록 확인. 연동 검증은 `PULP_INTEGRATION.md §5` 체크리스트 참고.
|
|
|
|
---
|
|
|
|
## 6. 업데이트(다음 버전 반입)
|
|
|
|
- 소스만 바뀌면: 새 `pulp-console-src.tgz`만 반입해 교체 후 `systemctl restart pulp-console`.
|
|
- 의존성이 바뀌면(`requirements.txt` 변경): `vendor/`에 새 wheel도 함께 반입 후 `pip install --no-index --find-links vendor -r requirements.txt` 재실행.
|
|
|
|
---
|
|
|
|
## venv / pip 가 없을 때 (대안)
|
|
|
|
venv는 필수가 아니다. **필요한 건 Python 인터프리터 하나**뿐. 점점 더 미니멀한 순서:
|
|
|
|
**① venv만 없음 — `pip --target` + PYTHONPATH**
|
|
```bash
|
|
python3 -m pip install --no-index --find-links vendor --target ./libs -r requirements.txt
|
|
PYTHONPATH=./libs python3 -m uvicorn app.main:app --host 0.0.0.0 --port 8000
|
|
```
|
|
|
|
**② pip도 없음 — pip wheel 부트스트랩** (반입물에 `pip-*.whl` 포함: `pip download pip -d vendor/`)
|
|
```bash
|
|
python3 vendor/pip-*.whl/pip install --no-index --find-links vendor --target ./libs -r requirements.txt
|
|
# wheel 은 zip 이라 설치 없이 바로 실행됨. (또는 python3 -m ensurepip)
|
|
```
|
|
|
|
**③ pip 자체가 불가 — wheel 압축해제 + PYTHONPATH** (pip 0개)
|
|
```bash
|
|
mkdir libs && cd libs
|
|
for w in ../vendor/*.whl; do unzip -oq "$w"; done # wheel=zip, 컴파일 .so 포함
|
|
cd .. && PYTHONPATH=./libs python3 -m uvicorn app.main:app --host 0.0.0.0 --port 8000
|
|
```
|
|
|
|
**④ Python 자체가 없음 — 독립 실행형 Python 반입**
|
|
- python-build-standalone(astral-sh) tarball을 풀어 그 안의 `bin/python3`로 ①~③ 수행.
|
|
단, 그 Python 버전에 맞춰 wheelhouse를 받을 것(§0).
|
|
|
|
systemd 로 상시 구동 시 `ExecStart`를 위 실행 커맨드로 바꾸면 된다
|
|
(예: `Environment=PYTHONPATH=/opt/pulp-console/libs` + `ExecStart=/usr/bin/python3 -m uvicorn ...`).
|
|
|
|
---
|
|
|
|
## 폐쇄망에 이미 있어야 하는 것
|
|
- **Python 3.x** (타깃 버전 — §0). venv/pip 없어도 위 대안으로 가능.
|
|
- **Pulp 서버** (붙는 대상, 이미 존재)
|
|
- **Postgres** (감사 로그용; 없으면 배포는 되나 "감사 로그 기록 실패" 경고)
|
|
- **사내 CA(.pem)** (HTTPS Pulp 검증)
|