온프레미스 배포 + 모델 연동 가이드 — eval-system-premium

jodal-eval-ai/pps-mono-repo · H100 GPU 클러스터 + vLLM + KURE-v1
branch: feat/onprem-h100-deploy · HEAD: bd5d51a (PR #197 merged) · 2026-05-22
요약: alpha 의 모든 최신 변경 (35 PR) 이 feat/onprem-h100-deploy 에 squash 머지됨. 온프렘 배포는 start.sh 한 명령 — .env.onprem → .env 자동 복사 후 docker compose up. 모델은 로컬 vLLM (Qwen3-32B :8305 + Qwen3-VL :8303 + KURE-v1 :8306), 외부 OpenRouter 비활성. 추가 인프라 0 (postgres·minio·redis·qdrant 도커 컨테이너 그대로).

1. 시스템 아키텍처

┌─────────────────────────────────────────────────────────────┐ │ portal-nginx :80 │ │ (인증 게이트웨이 + /app/* 라우팅) │ └────┬──────────────────────────┬────────────────────────────┘ │ │ ┌────────────▼─────────┐ ┌───────────▼──────────────┐ │ frontend :3030 │ │ BFF :4001 (FastAPI) │ │ Next.js 16 standalone│◀──▶│ — 헥사고날 (domain/ports)│ └──────────────────────┘ └────┬───────────┬─────────┘ │ │ ┌───────────────────────────┘ └────────┐ │ │ ┌──────────▼─────────┐ ┌──────────────┐ ┌────────────────▼─────────┐ │ hwpx-intelligence │ │ postgres :5432 │ │ MinIO :9000 │ │ :8001 (FastAPI) │ │ pps_rfp/eval_ │ │ eval-premium-images │ │ │ │ system/premium │ │ + __source__/ (원본) │ └─────┬──────────────┘ └────────────────┘ └─────────────────────────┘ │ ├─▶ Qwen3-32B vLLM :8305 (LLM) ├─▶ Qwen3-VL-8B :8303 (Vision) └─▶ KURE-v1 :8306 (Embedding)

2. 컴포넌트 인벤토리

컴포넌트포트실행역할
portal-nginx80docker인증 게이트웨이, /app/* 서브패스 프록시
frontend3030dockerNext.js 16 standalone — 비교 표 UI
BFF (eval-system-premium)4001dockerFastAPI 헥사고날, proposals CRUD + 이미지 + 검색
hwpx-intelligence8001uvicorn (host)HWP/HWPX 파싱 + LLM/VLM 호출 + 이미지 추출
postgres5432dockerpps_rfp / eval_system / eval_system_premium
pgadmin5050dockerDB 관리 UI
MinIO9000/9001docker이미지·원본파일 S3 호환 스토리지
Redis6379dockerCelery 브로커, BullMQ
Qdrant6333/6334docker벡터 검색 (RFP/proposal 임베딩)
Qwen3-32B vLLM8305vLLMLLM (RFP 구조화 + eval-chatbot)
Qwen3-VL-8B8303vLLM이미지 분석 (도면 OCR)
KURE-v1 임베딩8306자체 서빙한국어 임베딩 (semantic-search)
GPU info service8500자체GPU 가용성 모니터링

3. 모델 연동 — .env.onprem

MODEL_CONFIG_*_ENABLED 스위치로 dev/prod 분기. 온프렘은 전부 TYPE=local + URL=http://localhost:830X.

# LLM — RFP 구조화 + 평가 챗봇
MODEL_CONFIG_qwen3_32b_ENABLED=true
MODEL_CONFIG_qwen3_32b_TYPE=local
MODEL_CONFIG_qwen3_32b_PROVIDER=qwen
MODEL_CONFIG_qwen3_32b_URL=http://localhost:8305
MODEL_CONFIG_qwen3_32b_MODEL_NAME=Qwen/Qwen3-32B
MODEL_CONFIG_qwen3_32b_GPU_INFO_URL=http://localhost:8500
MODEL_CONFIG_qwen3_32b_PURPOSE=rfp-structure

# Vision — 도면/이미지 분석
MODEL_CONFIG_qwen3_vl_8b_instruct_ENABLED=true
MODEL_CONFIG_qwen3_vl_8b_instruct_TYPE=local
MODEL_CONFIG_qwen3_vl_8b_instruct_URL=http://localhost:8303/v1
MODEL_CONFIG_qwen3_vl_8b_instruct_MODEL_NAME=Qwen/Qwen3-VL-8B-Instruct
MODEL_CONFIG_qwen3_vl_8b_instruct_PURPOSE=rfp-image-analysis

# 평가 챗봇 (별도 alias — same vLLM 인스턴스 재사용)
MODEL_CONFIG_qwen3_32b_eval_ENABLED=true
MODEL_CONFIG_qwen3_32b_eval_URL=http://localhost:8305
MODEL_CONFIG_qwen3_32b_eval_PURPOSE=eval-chatbot

# Embedding — 한국어 KURE-v1
MODEL_CONFIG_local_embedding_ENABLED=true
MODEL_CONFIG_local_embedding_TYPE=local
MODEL_CONFIG_local_embedding_PROVIDER=kure
MODEL_CONFIG_local_embedding_URL=http://localhost:8306
MODEL_CONFIG_local_embedding_MODEL_NAME=nlpai-lab/KURE-v1
MODEL_CONFIG_local_embedding_PURPOSE=semantic-search
EMBEDDING_DIM=1536

# 외부 API 키 — 온프렘은 비활성
GEMINI_API_KEY=
OPENROUTER_API_KEY=  # 데모 후 revoke 권장
UPSTAGE_API_KEY=
USE_UPSTAGE_API=false

4. 부팅 절차 (1회성 — start.sh)

  1. GPU 모델 서빙 시작 (호스트 systemd 또는 별도 supervisor)
    # Qwen3-32B vLLM
    vllm serve Qwen/Qwen3-32B --port 8305 --tensor-parallel-size 2
    
    # Qwen3-VL-8B
    vllm serve Qwen/Qwen3-VL-8B-Instruct --port 8303 --tensor-parallel-size 1
    
    # KURE-v1 임베딩
    python -m kure_v1.server --port 8306
  2. hwpx-intelligence 부팅 (호스트 uvicorn, BFF 보다 먼저)
    cd ~/Github/1_Projects/hwpx-intelligence
    uv sync
    nohup uv run hpwx serve --host 0.0.0.0 --port 8001 > /var/log/hwpx.log 2>&1 &
  3. 온프렘 start.sh 실행 (이미지 tar 로드 + .env 자동 복사 + docker compose up)
    cd ~/Github/1_Projects/pps-mono-repo
    git pull origin feat/onprem-h100-deploy   # alpha 최신 squash 머지된 상태
    bash start.sh
    내부 동작:
    1. docker load < docker-images/pps-images.tar (이미지 로드, 첫 부팅만)
    2. cp .env.onprem .env
    3. docker compose up -d --no-build
  4. MinIO 버킷 자동 생성 — minio-init 컨테이너가 MINIO_BUCKETS env 의 버킷 자동 생성 (eval-premium-images, pps-rfp-processed, pps-rfp-ingest)
  5. postgres 자동 migration — BFF entrypoint 가 alembic upgrade head 실행
  6. 헬스체크
    curl localhost:4001/api/health         # {"status":"ok"}
    curl localhost:8001/api/health         # hwpx
    curl localhost:8305/v1/models          # vLLM
    docker compose ps                      # 모두 healthy

5. 데모 5/22 안전 체크리스트

항목확인 명령기대
vLLM Qwen3-32Bcurl localhost:8305/v1/models200
vLLM Qwen3-VLcurl localhost:8303/v1/models200
KURE-v1 임베딩curl localhost:8306/health200 (dim=1536)
hwpx-intelligencecurl localhost:8001/api/health200
BFFcurl localhost:4001/api/health{"status":"ok"}
BFF self-poller 가동env | grep PREMIUM_BFF_DISABLE_SELF_POLLERfalse
proposals 테이블psql ... -c "SELECT COUNT(*) FROM proposals"≥1
MinIO 영구화mc ls local/eval-premium-images/__source__/, prop-*
frontend /uploadcurl -o /dev/null -w '%{http_code}' localhost:3030/upload200
frontend /eval 비교.../eval?bid_id=demo-bid-1200 + 비교표

6. 운영 가이드 — 보안·백업·모니터링

영역P0 (즉시)P1 (2주)
보안 OpenRouter 키 revoke (메일 노출됨) → 새 키 발급 + Infisical/Doppler 시크릿 매니저 이전. PORTAL_JWT_SECRET openssl rand -hex 64 로 재생성 portal-nginx 사내 CA 인증서 mount (HTTPS), admin endpoint JWT scope 강제
백업 postgres pg_dump cron (30분 간격) → MinIO pps-backups 버킷. retention 7일 MinIO 객체 cross-region replication 또는 R2 sync
모니터링 Sentry DSN (BFF + Frontend) — 무료 tier 5분 셋업 Prometheus + Grafana (LLM 호출 count/latency/cost 메트릭)
로그 structlog JSON formatter + correlation_id (proposal_id) — BFF requirements 에 이미 있음, 적용만 Loki + Grafana log aggregation
LLM 안정성 vLLM 응답 timeout 120s (hwpx_client 적용됨), tenacity retry 추가 모델 fallback chain (vLLM 다운 시 OpenRouter)

7. 트러블슈팅

증상원인해결
BFF self-poller 가 무한 polling hwpx-intelligence 가 callback URL 미호출 (webhook 미구현) self-poller가 backup — 정상. webhook 구현 후 비활성 가능
큰 hwp (88K 단락) LLM stuck 27분 OpenRouter rate limit + LLM 호출 chunk 과대 per-zone 5분 timeout + status='partial' fallback (P0 권장 — 별도 PR)
/api/proposals 응답 4.5MB raw (extraction JSONB) 포함 — 33 proposal × 140KB ?include_raw=false opt-in → 32KB (~170× 슬림). PR #188
이미지 안 보임 frontend 가 옛 hwpx /api/records/.../images/ 호출 BFF endpoint /api/proposals/{id}/images/{filename} 사용 (PR #175, #179)
원본보기 404 source file not found PR #182 이전 업로드 = MinIO 미저장 hwpx /api/uploads/{job_id} lazy fetch → MinIO 자동 영구화 (PR #185)
표 헤더 분리 안 보임 border-collapse 환경에서 thead shadow 가 렌더 안 됨 각 th 에 border-b-4 border-[#1F48B8] (PR #184)
migration head 2개 → exit 255 alembic 분기 DDL 없는 merge-only revision 으로 수렴. CI 에 alembic heads | wc -l ≤ 1 검증 (P1)

8. 자주 쓰는 명령

# 전체 재시작
docker compose down && bash start.sh

# 특정 컨테이너 재기동 (BFF)
docker compose up -d --force-recreate eval-system-premium-bff

# 로그
docker compose logs -f eval-system-premium-bff
docker compose logs -f eval-system-premium-frontend

# DB 직접 조회
docker exec pps-postgres-1 psql -U pps_user -d eval_system_premium

# MinIO 객체 목록
docker exec pps-minio-1 mc ls --recursive local/eval-premium-images/

# 마이그레이션 (기존 proposal data_uri → MinIO)
curl -X POST http://localhost:4001/api/admin/migrate-images

# keyset 페이지네이션 테스트
curl "localhost:4001/api/proposals?limit=10&include_raw=false&cursor=..."

9. 참고 링크