d030a2b7b0
빈 볼륨 첫 기동 시 postgres 가 migrations/*.sql 을 psql autocommit 으로 실행해 스키마는 만들되 schema_migrations 스탬프를 안 남김 → fastapi init_db 가 documents 존재로 'fresh' 오판해 baseline 로드를 건너뛰고 001 부터 재replay → CREATE TABLE users(IF NOT EXISTS 없음) 충돌 → DR/신규환경 부팅 크래시. fresh-boot 을 init_db 의 baseline + migration runner 단일 경로로 일원화. 기존 prod 볼륨은 비어있지 않아 init scripts 미발동 = 무영향. 관련 docs 정정. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.6 KiB
8.6 KiB
Storage Layout — Document Server
버전: 2026-05-11 (Storage PR-1 read-only inventory 결과 반영)
역할 분리 원칙: feedback_knowledge_in_db_blob_in_nas.md — 지식·검색 대상 = DB, binary·source = NAS.
Plan 정합: ~/.claude/plans/beszel-tingly-sloth.md v6 의 Storage Backbone 트랙.
전제
- DB 본체 (Postgres) = GPU 서버 잔류 (CPU/RAM 우위, 결정 라운드 9).
- NAS = bulk binary / source / 변경 적은 자료 backbone.
- AI 호출은 GPU/맥미니로 라우팅 (Document Server 와 별 채널).
머신 / 마운트 토폴로지 (2026-05-11 실측)
| 머신 | 역할 | IP | 디스크 |
|---|---|---|---|
| GPU 서버 (RTX 4070 Ti Super, Ubuntu) | Docker 호스트 — fastapi / postgres / worker / Caddy / frontend | LAN 192.168.1.186 / Tailscale 100.111.160.84 | rootfs 936G / 182G used / 715G free |
| DS1525+ (Synology) | NFS export + Hyper Backup + DR Tier 1 | LAN 192.168.1.227 / Tailscale 100.101.79.37 | /volume4 3.5TB / 401GB used / 3.1TB free |
| Mac mini M4 Pro | MLX inference (Document Server 외부) | LAN 192.168.1.x / Tailscale 100.76.254.116 | (Document Server storage 영역 0) |
GPU 서버의 NFS mount (/proc/mounts 실측):
192.168.1.227:/volume4/Document_Server /mnt/nas/Document_Server
nfs4 rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,
soft,proto=tcp,timeo=10,retrans=3,_netdev
의미:
- 이미 soft mount + timeo=10 + retrans=3 적용 중 → plan v6 Storage PR-2 의 "실측 후 mount 전략 결정" 의 현 baseline 이 곧 권고안. 변경 필요 X.
- vers=4.1, NFSv4 (NFSv3 아님 → grace period / lock 처리 OK).
- LAN 직결 (Tailscale 경유 아님) — D10 (DS1525+ Tailscale TCP 차단) 영향 없음.
NAS volume 안 Document Server layout
/mnt/nas/Document_Server/ (= NAS /volume4/Document_Server/):
| 경로 | 용도 | 크기 | 변경 빈도 | 분류 |
|---|---|---|---|---|
PKM/ |
사용자 컨텐츠 원본 (knowledge + 입력 inbox + references) | 38GB | 일 단위 | 이미 NAS ✓ |
PKM/Knowledge/ |
정리된 지식 자료 (압력용기, ASME, 가스, 등) | 31GB | 일 단위 | 이미 NAS ✓ |
PKM/References/ |
레퍼런스 PDF | 5.5GB | 주 단위 | 이미 NAS ✓ |
PKM/Inbox/ |
업로드 진입 (drag-drop / file_watcher) | 1.5GB | 시간 단위 | 이미 NAS ✓ |
PKM/.preview/ |
LibreOffice PDF 변환 cache | (소량, 6 entry) | 신규 업로드 시 | 이미 NAS ✓ (검토: GPU 로 이동 가치 작음) |
PKM/Recordings/ |
음성 녹음 | 20KB | 거의 X | 이미 NAS ✓ |
PKM/Videos/ |
비디오 | 116KB | 거의 X | 이미 NAS ✓ |
PKM/Archive/ |
아카이브 | 0 | — | 이미 NAS ✓ |
Main/ |
별 디렉토리 (의미 확인 필요) | 14GB | ? | 이미 NAS ✓ |
extracted_images/ |
Markdown Phase 1B.5 추출 이미지 (document_images) |
1.2MB | 변환 시 | 이미 NAS ✓ |
study_question_images/ |
가스기사 문제 첨부 이미지 (PR-8) | 12MB | 회차 업로드 시 | 이미 NAS ✓ |
프로그래밍 전 참고 자료/ |
(소량) | 56KB | 거의 X | 이미 NAS ✓ |
결론: NAS 의 binary/source layer 는 이미 잘 구성되어 있음. 추가 이관 후보 (Storage PR-3/4 candidate) 는 사실상 없음 — 단, PR-4 MailPlus ingest 도입 시 extracted_emails/ 신규 디렉토리 추가 예정.
GPU 서버 local storage (Postgres + worker 모델 + 로그)
| 경로 / Volume | 용도 | 크기 | 분류 |
|---|---|---|---|
Postgres data dir (pgdata named volume) |
DB 본체 | 1.1GB | GPU 잔류 (plan 결정) |
hyungi_document_server_ollama_data |
Ollama 모델 weight (embedding / 분류 / 임베딩 등) | 11.9GB | GPU 잔류 (GPU 인접 필수) |
hyungi_document_server_stt_models |
STT (faster-whisper 등) 모델 | 3.0GB | GPU 잔류 |
hyungi_document_server_reranker_cache |
bge-reranker-v2-m3 cache | 2.1GB | GPU 잔류 |
hyungi_document_server_ocr_models |
OCR 모델 | 1.4GB | GPU 잔류 |
hyungi_document_server_marker_models |
marker-pdf cache | 4KB (외부 HF cache 사용 추정) | GPU 잔류 |
hyungi_document_server_caddy_data |
Caddy ACME / log | (작음) | GPU 잔류 |
~/Documents/code/hyungi_Document_Server/logs/ |
fastapi 로그 (rotation) | 21MB | GPU 잔류 |
합계: AI 모델 캐시 ~18.5GB + Postgres 1.1GB + 로그/Caddy < 100MB ≈ GPU local 20GB 사용 중.
컨테이너 마운트 매트릭스 (docker-compose.yml 발췌)
| 컨테이너 | 마운트 | 모드 | 비고 |
|---|---|---|---|
| postgres | pgdata:/var/lib/postgresql/data |
rw | DB 본체 named volume (initdb.d 마운트는 2026-06-29 제거 — 아래 관찰) |
| kordoc-service | ${NAS}/Document_Server:/documents |
ro | PDF/HWP parse |
| ocr-service | ${NAS}/Document_Server:/documents + ocr_models:/root/.cache |
ro + rw | |
| marker-service | ${NAS}/Document_Server:/documents + marker_models:/models |
ro + rw | PDF→markdown |
| stt-service | ${NAS}/Document_Server:/documents + stt_models:/root/.cache |
ro + rw | |
| ai-gateway / ollama | ollama_data:/root/.ollama |
rw | GPU 인접 |
| reranker | reranker_cache:/data |
rw | |
| fastapi | ${NAS}/Document_Server:/documents + ./config.yaml ./domain_policy.yaml ./scripts ./logs ./migrations |
rw + ro/rw | NAS 쓰기 권한은 fastapi 만 |
| caddy | ./Caddyfile + caddy_data:/data |
rw |
관찰:
- worker 컨테이너 (kordoc/ocr/marker/stt) 는 모두 NAS read-only 마운트 → 원본 안전.
- fastapi 만 NAS rw → 업로드/preview/extracted_images 쓰기 단일 책임.
./migrations은 fastapi 의/app/migrations에만 마운트. migration runner 는 fastapiinit_db()단일 경로. (~2026-06-29: postgresdocker-entrypoint-initdb.d마운트 제거. 기존엔 "첫 생성 시만 실행 → 효과 X" 로 봤으나, 빈 볼륨 첫 기동 시 postgres 가 migrations/*.sql 을 실제 실행해 스키마는 만들되 schema_migrations 스탬프를 안 남겨 → init_db 의 baseline fresh 판정을 깨고 부팅 크래시 유발. fresh-DB/DR 부팅을 init_db+baseline 단일 경로로 일원화.)
정책 정리
NAS 에 두는 것 (binary / source / 변경 적음)
- 사용자 컨텐츠 원본 (
PKM/*) - 변환 cache (
PKM/.preview/,extracted_images/) - 학습 자료 첨부 (
study_question_images/) - 향후:
extracted_emails/(PR-4)
GPU 서버 local 에 두는 것 (latency 민감 / hot path / 큰 caching)
- Postgres data dir (DB 본체)
- HNSW index, pgvector index (Postgres 내부)
- AI 모델 weight cache (embedding / OCR / STT / reranker / marker / ollama)
- worker 임시 캐시 (각 컨테이너 named volume)
- 로그 (
./logs)
명확하게 어디에 두지 않음
- 검색 인덱스: Postgres 안 (pgvector + pg_trgm) — NAS X
- chunk text: Postgres 안 (
document_chunks.text_content) — NAS X - 메모 본문: Postgres 안 (
documents.extracted_text) — NAS X - AI 분류 결과: Postgres 안 (
documents.ai_domain/ai_tags) — NAS X
NFS mount 옵션 권고 (Storage PR-2 baseline)
현 GPU 서버 mount = 이미 권고안과 같음:
192.168.1.227:/volume4/Document_Server /mnt/nas/Document_Server nfs4
rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,
soft,proto=tcp,timeo=10,retrans=3,_netdev
근거:
soft— NAS down 시 process 영구 hang 회피 (plan v6 Storage PR-2 핵심 요구). 단 쓰기 도중 부분 실패 위험 → fastapi 의upload/extract/markerworker 가 fsync + rename(atomic) + DB row 작성 ordering 필수 (코드 검토는 PR-2 영역).timeo=10/retrans=3— 1초 단위 timeout × 3회. 30초 안 NAS 응답 없으면 EIO. 운영 1년+ 안정 (별 incident 없음).vers=4.1— NFSv3 의 lock daemon 불필요, idempotent._netdev— boot 시 network 이후 마운트.
Storage PR-2 시 점검 항목 (read-only PR-1 scope 외)
- 한글 NFC/NFD 정규화 wrapper (
feedback_nfs_korean_path_normalize.md) — 기존document_images경로 처리 코드 일반화 - uid/gid 매핑 (Synology user ↔ Docker container user)
- NAS 장애 시뮬레이션 gate (운영 mount 아닌 isolated test mount 부터)
- 쓰기 경로 fsync + rename(atomic) + 실패 명시 처리
백업 정책
- NAS = Synology Hyper Backup (DR Tier 1, 별 트랙
project_db_backup.md참조) - Postgres = pkm DB → Tier 0 GPU + Tier 1 DS1525+ Vol3 + Tier 2 C2 Hyper Backup (별 트랙)
- AI 모델 캐시 = 백업 불필요 (재다운로드 가능)
다음 단계
- Storage PR-2 (NFS 표준화 + 정규화 wrapper + 장애 시뮬 gate) — 운영 변경 동반 → 별 PR
- Storage PR-3/4 (원본 이관) — 현 상태 이미 NAS, 추가 작업 0
- Storage PR-5 (events
raw_metadata첨부 = extracted_emails) — events PR-4 (MailPlus ingest) 와 합류