CPU 서버 배포
이 가이드는 폐쇄망 환경에서 DO-Solution 2.0 CPU 스택을 배포하는 절차를 제공합니다.
선행 조건
- GPU 서버 환경 설정 가이드에 따라 환경 구성 완료
/home/$USER경로에 설치 패키지 반입 완료- 배포 서버에서 외부 Elasticsearch(Nori Plugin 설치)에 네트워크 접근 가능
- 호스트 IP 또는 도메인 확정
1. 작업 디렉터리 배치
scp 또는 rsync 등을 통해 /home/$USER에 파일을 반입한 후, 디렉터리 구조를 확인합니다:
bash
cd /home/$USER
# 기대하는 디렉터리 구조
/home/$USER
.
├── cpu
│ ├── data
│ │ ├── gunicorn.conf.py
│ │ └── supabase
│ │ └── volumes
│ │ ├── api
│ │ │ └── kong.yml
│ │ ├── db
│ │ │ ├── _supabase.sql
│ │ │ ├── init/schema.sql.example
│ │ │ ├── jwt.sql
│ │ │ ├── logs.sql
│ │ │ ├── pooler.sql
│ │ │ ├── realtime.sql
│ │ │ ├── roles.sql
│ │ │ └── webhooks.sql
│ │ ├── functions/main/index.ts
│ │ ├── logs/vector.yml
│ │ ├── pooler/pooler.exs
│ │ └── storage
│ ├── docker-compose.yml
│ ├── docker-load.sh
│ ├── env_generator.py
│ └── images
├── gpu
│ ├── data
│ │ ├── lk-parser/nginx.conf.template
│ │ ├── lk-parser-images
│ │ ├── lk-parser-input
│ │ ├── lk-parser-models
│ │ │ ├── chandra-v2/
│ │ │ ├── table-transformer-detection/
│ │ │ ├── table-transformer-structure-recognition-v1.1-all/
│ │ │ ├── resnet18.al_in1k/
│ │ │ └── docling-models/
│ │ └── lk-parser-output
│ ├── docker-compose.yml
│ ├── docker-load.sh
│ ├── env_generator.py
│ └── images
└── secret_bundle_generator.py2. Docker 이미지 로드
CPU Stack
bash
cd /home/$USER/cpu
chmod +x ./docker-load.sh
./docker-load.shGPU Stack
bash
cd /home/$USER/gpu
chmod +x ./docker-load.sh
./docker-load.sh로드된 이미지 확인
로드 후 이미지 목록을 확인합니다. 태그는 .env 파일의 이미지 태그 변수와 일치해야 합니다.
bash
docker imagesCPU Stack 이미지:
| 이미지 | 용도 | 포트 |
|---|---|---|
lk-admin:2.0.0 | 관리자 패널 | 3333 |
open-webui:main | 메인 UI, RAG, 파일 임베딩 | 3000 |
chunking-server:latest | 문서 청킹 서비스 | 8001 |
supabase/studio | Supabase 웹 대시보드 | — |
kong:2.8.1 | API 게이트웨이 | 8000 |
supabase/gotrue | 인증 서비스 (JWT) | — |
postgrest/postgrest | PostgreSQL REST API | — |
supabase/realtime | WebSocket 브로드캐스트 | — |
supabase/storage-api | 파일 객체 스토리지 | — |
supabase/postgres:15 | 메인 데이터베이스 | — |
supabase/supavisor | 커넥션 풀러 | 6543 |
redis:alpine | 세션 캐시 | 6379 |
GPU Stack 이미지:
| 이미지 | 용도 | 포트 |
|---|---|---|
text-embeddings-inference:cuda-1.9 | Embedding 서버 | 11435 |
text-embeddings-inference:cuda-1.9 | Reranking 서버 | 11436 |
vllm-openai:latest-x86_64-cu130 | vLLM / OCR 백엔드 | 8888 |
lk-ocr-api:latest | OCR/문서 파싱 API | 8504 |
nginx:alpine | OCR API 리버스 프록시 | 80 |
3. do.secrets 구성
do.secrets 파일은 JWT Secret, Postgres/Redis 비밀번호 등의 시크릿을 KEY=VALUE 형태로 저장합니다.
bash
# CPU 서버에서 실행 권장
cd /home/$USER
python3 secret_bundle_generator.py생성된 파일 확인:
bash
cat do.secrets
# 예시 출력:
##############################################################################
# DO-Solution shared secrets
# DO NOT commit to version control
##############################################################################
JWT_SECRET=<생성됨>
ANON_KEY=<생성됨>
SERVICE_ROLE_KEY=<생성됨>
POSTGRES_PASSWORD=<생성됨>
DASHBOARD_PASSWORD=<생성됨>
REDIS_PASSWORD=<생성됨>
SECRET_KEY_BASE=<생성됨>
VAULT_ENC_KEY=<생성됨>
PG_META_CRYPTO_KEY=<생성됨>
LOGFLARE_PUBLIC_ACCESS_TOKEN=<생성됨>
LOGFLARE_PRIVATE_ACCESS_TOKEN=<생성됨>
STORAGE_S3_ACCESS_KEY_SECRET=<생성됨>
WEBUI_SECRET_KEY=<생성됨>do.secrets 스택 디렉터리에 복사
동일 서버에서 양쪽 스택을 운영하는 경우:
bash
cp /home/$USER/do.secrets /home/$USER/cpu/do.secrets
cp /home/$USER/do.secrets /home/$USER/gpu/do.secrets별도 서버에서 GPU 스택을 운영하는 경우:
bash
# GPU 서버로 안전하게 전달
scp /home/$USER/do.secrets <gpu_user>@<gpu_host>:/home/<gpu_user>/gpu/do.secrets
cp /home/$USER/do.secrets /home/$USER/cpu/do.secrets권한 확인
do.secrets의 권한은 600이어야 합니다:
bash
stat -c '%a' /home/$USER/cpu/do.secrets
stat -c '%a' /home/$USER/gpu/do.secrets
# 기대값: 6004. CPU Stack .env 구성
생성 스크립트 실행
bash
cd /home/$USER/cpu
python3 env_generator.pydo.secrets가 없을 경우:
[ERROR] do.secrets not found at do.secrets
[ERROR] Run: python3 ../secret_bundle_generator.py
[ERROR] Then copy: cp ../do.secrets ./do.secrets
do.secrets가 있을 경우 입력 항목:
Enter host IP or domain (no scheme, no trailing slash): <호스트 IP 입력>
Enter Supabase tenant identifier [do-solution]: <테넌트 ID 입력>
Enter Elasticsearch URL (with scheme, e.g., http://10.0.0.50:9200): <ES URL 입력>
Enter Elasticsearch username: <ES 사용자명 입력>
Enter Elasticsearch password (input hidden): <ES 비밀번호 입력>
예시 출력:
[INFO] Output written to .env with permission 600
[INFO] ============================================================
[INFO] Generated .env successfully
[INFO] Host: 172.235.213.121
[INFO] Tenant: do-solution
[INFO] Elasticsearch URL: http://172.235.213.121:9200
[INFO] ============================================================
[INFO] IMPORTANT: Store this .env file securely
수동 조정 항목
생성된 .env를 검토하고 다음 항목을 환경에 맞게 수정합니다:
bash
# 메일 발송 사용 시 SMTP 설정
SMTP_ADMIN_EMAIL=admin@example.com
SMTP_HOST=supabase-mail
SMTP_PORT=2500
SMTP_USER=fake_mail_user
SMTP_PASS=fake_mail_password
SMTP_SENDER_NAME=fake_sender
# 외부 LLM 사용 시
OPENAI_API_KEY=5. CPU Stack 배포
사전 점검
bash
cd /home/$USER/cpu
# .env 파일 확인
ls -al .env
grep -E "^(POSTGRES_PASSWORD|JWT_SECRET|REDIS_PASSWORD)" .env | sed 's/=.*/=<REDACTED>/'
# docker-compose.yml 및 gunicorn 설정 확인
ls -al docker-compose.yml
ls -al data/gunicorn.conf.py컨테이너 기동
bash
cd /home/$USER/cpu
docker compose up -d컨테이너 상태 확인
bash
# 모든 컨테이너 상태 확인
docker compose ps
# 로그 확인 (문제 해결 시)
docker compose logs -f --tail=1006. GPU Stack .env 구성
bash
cd /home/$USER/gpu
python3 env_generator.py입력 항목:
Enter CPU server IP or domain reachable from this GPU host (no scheme, no trailing slash): <CPU 호스트 IP 입력>
예시 출력:
[INFO] Generated .env successfully
[INFO] CPU host: 172.235.213.121
[INFO] IMPORTANT: Store this .env file securely
[INFO] lk-ocr-api healthcheck will fail until the cpu stack is up and reachable
7. GPU Stack 배포
사전 점검
bash
cd /home/$USER/gpu
# GPU 가용성 확인
nvidia-smi
# 설정 파일 확인
ls -al docker-compose.yml .env
# CPU 서버 접근 가능 여부 확인 (CPU 스택이 기동되어 있어야 함)
nc -zv <CPU_HOST> 8000 # Supabase Kong
nc -zv <CPU_HOST> 6379 # Redis컨테이너 기동
bash
cd /home/$USER/gpu
docker compose up -d컨테이너 상태 확인
bash
docker compose ps
docker compose logs -f --tail=100GPU 할당 확인
bash
# GPU 사용 현황 확인
nvidia-smi
# 컨테이너별 GPU 사용량 확인
docker stats8. 설치 검증
모든 컨테이너가 Up 또는 healthy 상태여야 합니다.
bash
cd /home/$USER/cpu
docker compose ps
cd /home/$USER/gpu
docker compose psAdmin Panel 접속 확인
브라우저에서 http://<host_ip>:3333 접속하여 LK Admin 화면이 정상 표시되는지 확인합니다:
bash
curl -I http://<host_ip>:3333
# 기대값: HTTP/1.1 200 OKChunking Server 헬스 체크
bash
curl -i http://<host_ip>:8001/health
# 기대값: HTTP/1.1 200 OKElasticsearch 헬스 체크
bash
cd /home/$USER/cpu
set -a && . ./.env && set +a
curl -u "${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD}" \
"${ELASTICSEARCH_URL}/_cluster/health?pretty"
# 기대 status: "green" 또는 "yellow"Redis 연결 확인
bash
docker compose exec redis redis-cli -a "${REDIS_PASSWORD}" ping
# 기대값: PONGGPU 추론 서버 헬스 체크
bash
# OCR API (nginx 경유, 포트 80)
curl -i http://<gpu_host_ip>/health
# Embedding Server
curl -i http://<gpu_host_ip>:11435/health
# Reranking Server
curl -i http://<gpu_host_ip>:11436/health
# vLLM Server
curl -i http://<gpu_host_ip>:8888/health9. 기타 운영 명령어
bash
# 작업 디렉터리로 이동 (CPU 또는 GPU)
cd /home/$USER/cpu # 또는 /home/$USER/gpu
# 전체 서비스 중지
docker compose down
# 서비스 중지 및 볼륨 삭제 (주의: 데이터 손실)
docker compose down -v
# 특정 서비스 재시작
docker compose restart <service_name>
# 특정 서비스 로그 확인
docker compose logs -f <service_name>
# 이미지 변경 후 단일 서비스 업데이트
docker compose up -d --no-deps <service_name>부록: CPU Stack .env 목록
이미지 태그
| 변수명 | 기본값 | 설명 |
|---|---|---|
OPENWEBUI_IMAGE | ghcr.io/open-webui/open-webui:main | OpenWebUI 이미지 |
ADMIN_PANEL_IMAGE | …/lk-admin:2.0.0 | LK Admin Panel 이미지 |
CHUNKING_SERVER_IMAGE | …/chunking-server:latest | Chunking Server 이미지 |
Supabase 시크릿 (do.secrets에서 자동 주입 — 직접 수정 금지)
| 변수명 | 설명 |
|---|---|
POSTGRES_PASSWORD | PostgreSQL 슈퍼유저 비밀번호 |
JWT_SECRET | JWT 서명용 비밀키 |
ANON_KEY | 익명 사용자 JWT 토큰 |
SERVICE_ROLE_KEY | 서비스 역할 JWT (RLS 우회, 전체 권한) |
DASHBOARD_PASSWORD | Supabase Studio 로그인 비밀번호 |
SECRET_KEY_BASE | Supavisor/Realtime 암호화 키 |
VAULT_ENC_KEY | Supabase Vault 암호화 키 |
PG_META_CRYPTO_KEY | postgres-meta 암호화 키 |
Supabase Database
| 변수명 | 기본값 | 설명 |
|---|---|---|
POSTGRES_HOST | db | PostgreSQL 호스트명 |
POSTGRES_DB | postgres | 기본 데이터베이스명 |
POSTGRES_PORT | 5432 | PostgreSQL 포트 |
Connection Pooler (Supavisor)
| 변수명 | 기본값 | 설명 |
|---|---|---|
POOLER_PROXY_PORT_TRANSACTION | 6543 | 트랜잭션 풀링 포트 |
POOLER_DEFAULT_POOL_SIZE | 20 | 기본 풀 크기 |
POOLER_MAX_CLIENT_CONN | 100 | 최대 클라이언트 연결 수 |
POOLER_TENANT_ID | (사용자 입력) | Supabase 테넌트 ID |
Auth (GoTrue)
| 변수명 | 기본값 | 설명 |
|---|---|---|
SITE_URL | http://<HOST_IP>:3000 | 인증 리디렉트 URL |
JWT_EXPIRY | 3600 | JWT 만료 시간(초) |
DISABLE_SIGNUP | false | 회원가입 비활성화 |
API_EXTERNAL_URL | http://<HOST_IP>:8000 | 외부 API URL |
SMTP_ADMIN_EMAIL | admin@example.com | SMTP 관리자 이메일 |
SMTP_HOST | supabase-mail | SMTP 호스트 |
SMTP_PORT | 2500 | SMTP 포트 |
ENABLE_EMAIL_SIGNUP | true | 이메일 회원가입 허용 |
Elasticsearch
| 변수명 | 기본값 | 설명 |
|---|---|---|
ELASTICSEARCH_URL | (사용자 입력) | 외부 ES URL |
ELASTICSEARCH_USERNAME | (사용자 입력) | ES 사용자명 |
ELASTICSEARCH_PASSWORD | (사용자 입력) | ES 비밀번호 |
ELASTICSEARCH_INDEX_PREFIX | openwebui_strategy_h | 인덱스 접두어 |
OpenWebUI
| 변수명 | 기본값 | 설명 |
|---|---|---|
OPEN_WEBUI_PORT | 3000 | OpenWebUI 포트 |
WEBUI_URL | http://<HOST_IP>:3000 | 외부 URL |
OPENWEBUI_GUNICORN_WORKERS | 6 | gunicorn 워커 수 |
OPENWEBUI_S3_BUCKET_NAME | openwebui-files | 파일 저장 버킷명 |
RAG_EMBEDDING_BATCH_SIZE | 16 | 임베딩 배치 크기 |
Admin Panel
| 변수명 | 기본값 | 설명 |
|---|---|---|
ADMIN_API_BASE_URL | http://<HOST_IP>:3000 | OpenWebUI API URL |
ADMIN_FASTAPI_URL | http://<HOST_IP>:3000 | FastAPI URL |
Chunking Server
| 변수명 | 기본값 | 설명 |
|---|---|---|
CHUNK_SIZE | 600 | 청킹 단위 토큰 수 |
CHUNK_OVERLAP | 100 | 청크 간 중첩 토큰 수 |
CHUNKING_STRATEGY | A | 청킹 전략 식별자 |
부록: GPU Stack .env 목록
이미지 태그
| 변수명 | 기본값 | 설명 |
|---|---|---|
LK_VLLM_IMAGE | vllm/vllm-openai:latest-x86_64-cu130 | vLLM 이미지 |
LK_OCR_API_IMAGE | …/lk-ocr-api:latest | OCR API 이미지 |
TEI_IMAGE | ghcr.io/huggingface/text-embeddings-inference:cuda-1.9 | Embedding/Reranker 이미지 |
모델 경로
| 변수명 | 기본값 | 설명 |
|---|---|---|
EMBEDDINGS_MODELS_DIR | ./embedding/models | BGE-M3 가중치 |
EMBEDDINGS_RERANK_MODELS_DIR | ./embedding/models-rerank | BGE-Reranker-v2-M3 가중치 |
LK_PARSER_MODELS_DIR | ./lk-parser-models | vLLM 모델 가중치 |
LK_PARSER_INPUT_DIR | ./lk-parser-input | OCR 입력 디렉터리 |
LK_PARSER_OUTPUT_DIR | ./lk-parser-output | OCR 출력 디렉터리 |
Infrastructure Endpoints
| 변수명 | 기본값 | 설명 |
|---|---|---|
SUPABASE_URL | http://<CPU_HOST>:8000 | Supabase Kong URL |
OCR_SUPABASE_URL | http://<CPU_HOST>:8000 | OCR Supabase URL |
OCR_S3_BUCKET_NAME | lk-parser | OCR 결과 저장 버킷명 |
Service Ports
| 변수명 | 기본값 | 설명 |
|---|---|---|
LK_PARSER_API_PORT | 8504 | LK OCR API 노출 포트 |
CHANDRA_API_PORT | 8504 | OCR API 내부 포트 |