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.py

2. Docker 이미지 로드

CPU Stack

bash
cd /home/$USER/cpu
chmod +x ./docker-load.sh
./docker-load.sh

GPU Stack

bash
cd /home/$USER/gpu
chmod +x ./docker-load.sh
./docker-load.sh

로드된 이미지 확인

로드 후 이미지 목록을 확인합니다. 태그는 .env 파일의 이미지 태그 변수와 일치해야 합니다.

bash
docker images

CPU Stack 이미지:

이미지용도포트
lk-admin:2.0.0관리자 패널3333
open-webui:main메인 UI, RAG, 파일 임베딩3000
chunking-server:latest문서 청킹 서비스8001
supabase/studioSupabase 웹 대시보드
kong:2.8.1API 게이트웨이8000
supabase/gotrue인증 서비스 (JWT)
postgrest/postgrestPostgreSQL REST API
supabase/realtimeWebSocket 브로드캐스트
supabase/storage-api파일 객체 스토리지
supabase/postgres:15메인 데이터베이스
supabase/supavisor커넥션 풀러6543
redis:alpine세션 캐시6379

GPU Stack 이미지:

이미지용도포트
text-embeddings-inference:cuda-1.9Embedding 서버11435
text-embeddings-inference:cuda-1.9Reranking 서버11436
vllm-openai:latest-x86_64-cu130vLLM / OCR 백엔드8888
lk-ocr-api:latestOCR/문서 파싱 API8504
nginx:alpineOCR 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
# 기대값: 600

4. CPU Stack .env 구성

생성 스크립트 실행

bash
cd /home/$USER/cpu
python3 env_generator.py

do.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=100

6. 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=100

GPU 할당 확인

bash
# GPU 사용 현황 확인
nvidia-smi

# 컨테이너별 GPU 사용량 확인
docker stats

8. 설치 검증

모든 컨테이너가 Up 또는 healthy 상태여야 합니다.

bash
cd /home/$USER/cpu
docker compose ps

cd /home/$USER/gpu
docker compose ps

Admin Panel 접속 확인

브라우저에서 http://<host_ip>:3333 접속하여 LK Admin 화면이 정상 표시되는지 확인합니다:

bash
curl -I http://<host_ip>:3333
# 기대값: HTTP/1.1 200 OK

Chunking Server 헬스 체크

bash
curl -i http://<host_ip>:8001/health
# 기대값: HTTP/1.1 200 OK

Elasticsearch 헬스 체크

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
# 기대값: PONG

GPU 추론 서버 헬스 체크

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/health

9. 기타 운영 명령어

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_IMAGEghcr.io/open-webui/open-webui:mainOpenWebUI 이미지
ADMIN_PANEL_IMAGE…/lk-admin:2.0.0LK Admin Panel 이미지
CHUNKING_SERVER_IMAGE…/chunking-server:latestChunking Server 이미지

Supabase 시크릿 (do.secrets에서 자동 주입 — 직접 수정 금지)

변수명설명
POSTGRES_PASSWORDPostgreSQL 슈퍼유저 비밀번호
JWT_SECRETJWT 서명용 비밀키
ANON_KEY익명 사용자 JWT 토큰
SERVICE_ROLE_KEY서비스 역할 JWT (RLS 우회, 전체 권한)
DASHBOARD_PASSWORDSupabase Studio 로그인 비밀번호
SECRET_KEY_BASESupavisor/Realtime 암호화 키
VAULT_ENC_KEYSupabase Vault 암호화 키
PG_META_CRYPTO_KEYpostgres-meta 암호화 키

Supabase Database

변수명기본값설명
POSTGRES_HOSTdbPostgreSQL 호스트명
POSTGRES_DBpostgres기본 데이터베이스명
POSTGRES_PORT5432PostgreSQL 포트

Connection Pooler (Supavisor)

변수명기본값설명
POOLER_PROXY_PORT_TRANSACTION6543트랜잭션 풀링 포트
POOLER_DEFAULT_POOL_SIZE20기본 풀 크기
POOLER_MAX_CLIENT_CONN100최대 클라이언트 연결 수
POOLER_TENANT_ID(사용자 입력)Supabase 테넌트 ID

Auth (GoTrue)

변수명기본값설명
SITE_URLhttp://<HOST_IP>:3000인증 리디렉트 URL
JWT_EXPIRY3600JWT 만료 시간(초)
DISABLE_SIGNUPfalse회원가입 비활성화
API_EXTERNAL_URLhttp://<HOST_IP>:8000외부 API URL
SMTP_ADMIN_EMAILadmin@example.comSMTP 관리자 이메일
SMTP_HOSTsupabase-mailSMTP 호스트
SMTP_PORT2500SMTP 포트
ENABLE_EMAIL_SIGNUPtrue이메일 회원가입 허용

Elasticsearch

변수명기본값설명
ELASTICSEARCH_URL(사용자 입력)외부 ES URL
ELASTICSEARCH_USERNAME(사용자 입력)ES 사용자명
ELASTICSEARCH_PASSWORD(사용자 입력)ES 비밀번호
ELASTICSEARCH_INDEX_PREFIXopenwebui_strategy_h인덱스 접두어

OpenWebUI

변수명기본값설명
OPEN_WEBUI_PORT3000OpenWebUI 포트
WEBUI_URLhttp://<HOST_IP>:3000외부 URL
OPENWEBUI_GUNICORN_WORKERS6gunicorn 워커 수
OPENWEBUI_S3_BUCKET_NAMEopenwebui-files파일 저장 버킷명
RAG_EMBEDDING_BATCH_SIZE16임베딩 배치 크기

Admin Panel

변수명기본값설명
ADMIN_API_BASE_URLhttp://<HOST_IP>:3000OpenWebUI API URL
ADMIN_FASTAPI_URLhttp://<HOST_IP>:3000FastAPI URL

Chunking Server

변수명기본값설명
CHUNK_SIZE600청킹 단위 토큰 수
CHUNK_OVERLAP100청크 간 중첩 토큰 수
CHUNKING_STRATEGYA청킹 전략 식별자

부록: GPU Stack .env 목록

이미지 태그

변수명기본값설명
LK_VLLM_IMAGEvllm/vllm-openai:latest-x86_64-cu130vLLM 이미지
LK_OCR_API_IMAGE…/lk-ocr-api:latestOCR API 이미지
TEI_IMAGEghcr.io/huggingface/text-embeddings-inference:cuda-1.9Embedding/Reranker 이미지

모델 경로

변수명기본값설명
EMBEDDINGS_MODELS_DIR./embedding/modelsBGE-M3 가중치
EMBEDDINGS_RERANK_MODELS_DIR./embedding/models-rerankBGE-Reranker-v2-M3 가중치
LK_PARSER_MODELS_DIR./lk-parser-modelsvLLM 모델 가중치
LK_PARSER_INPUT_DIR./lk-parser-inputOCR 입력 디렉터리
LK_PARSER_OUTPUT_DIR./lk-parser-outputOCR 출력 디렉터리

Infrastructure Endpoints

변수명기본값설명
SUPABASE_URLhttp://<CPU_HOST>:8000Supabase Kong URL
OCR_SUPABASE_URLhttp://<CPU_HOST>:8000OCR Supabase URL
OCR_S3_BUCKET_NAMElk-parserOCR 결과 저장 버킷명

Service Ports

변수명기본값설명
LK_PARSER_API_PORT8504LK OCR API 노출 포트
CHANDRA_API_PORT8504OCR API 내부 포트