95 lines
6.7 KiB
Markdown
95 lines
6.7 KiB
Markdown
# Vignette 이식성 참조 — Docker 구성
|
|
|
|
> 이 문서는 개발·이식성용 Docker 구성 참조다. 현재 production NAS 배포의 단일 진입점·승인·rollback 경계는 [`ops/deployment-pipeline.md`](./ops/deployment-pipeline.md)를 따른다.
|
|
|
|
목표: 어떤 호스트(네 PC / 학교 서버 / 클라우드 VM)든 `docker compose up -d` 한 방으로 뜨고, **옮길 때 환경변수 몇 줄만** 바꾼다.
|
|
|
|
## 1. 한 방 실행
|
|
|
|
```bash
|
|
cd infra
|
|
cp .env.example .env # 값 채우기(아래 표)
|
|
docker compose up -d
|
|
# web/api/db/rag/proxy 컨테이너 기동. http://localhost:8080
|
|
```
|
|
|
|
전부 컨테이너: `web`(React/nginx) · `api`(FastAPI) · `db`(postgres16+pgvector) · `rag`(BGE-M3+reranker) · `proxy`(Caddy, TLS·SSE·WSS).
|
|
|
|
## 2. 핵심 — "엔진"만 컨테이너 밖 (이식성의 열쇠)
|
|
|
|
AI provider는 모두 호스트 엔진 게이트웨이 뒤에 둔다. 게이트웨이가 Claude CLI·Anthropic API·Codex CLI·Agy CLI의 모델 탐색과 실행을 맡고, 컨테이너 API는 **`ENGINE_URL`/`ENGINE_MODE`로 게이트웨이와 provider를 선택한다.** CLI는 호스트 인증을 재사용하고 API 키는 게이트웨이 호스트에만 주입한다.
|
|
|
|
설정 경로 **3가지(사용자 선택)**:
|
|
1. **yml / .env** — `infra/.env`의 `ENGINE_URL`·`ENGINE_MODE` (기본·운영)
|
|
2. **docker compose** — `docker compose run -e ENGINE_MODE=claude_api ...` 즉석 오버라이드
|
|
3. **설정 페이지(관리자 UI)** — 런타임에 provider·연결 주소·사용 가능 모델·추론 강도를 선택한다. 게이트웨이가 확인하지 못한 조합은 저장하지 않는다.
|
|
|
|
| 시나리오 | ENGINE_MODE | ENGINE_URL |
|
|
|---|---|---|
|
|
| **네 PC 운영** (Claude CLI) | `claude_cli` | `http://host.docker.internal:9099` |
|
|
| **네 PC 운영** (Codex CLI, 기본 Terra/Medium) | `codex_cli` | `http://host.docker.internal:9099` |
|
|
| **네 PC 운영** (Agy CLI, 기본 Gemini 3.6 Flash/High) | `agy_cli` | `http://host.docker.internal:9099` |
|
|
| **클라우드/타호스트 이전** | `claude_api` | `http://host.docker.internal:9099` (`ANTHROPIC_API_KEY`는 게이트웨이 호스트에 주입) |
|
|
| **원격 엔진 PC** | 위 provider 중 설치·인증된 항목 | `http://<엔진PC-IP>:9099` |
|
|
|
|
> 호스트 게이트웨이는 `apps/api/engine_gateway/`에 있으며 컨테이너 밖에서 실행한다. Claude CLI는 상주 멀티턴 풀을, Codex/Agy는 각 CLI를, `claude_api`는 Anthropic API를 호출한다. 관리자 UI의 모델 목록은 이 게이트웨이의 `GET /v1/capabilities`가 소유한다.
|
|
|
|
### 2.1 NAS preview 원격 엔진 relay
|
|
|
|
NAS preview가 Windows 호스트의 엔진을 소비할 때는 `scripts/start-nas-preview-engine.ps1`만 쓴다. 이 경로는
|
|
기본 loopback이며, LAN 주소는 `-ConfirmNasPreviewLanExposure`를 명시한 경우에만 허용한다. 실행 source는
|
|
detached-clean HEAD/tree, launcher·Python·env SHA-256, NAS가 소비할 정확한 `ENGINE_URL`에 결속한다. 기존
|
|
listener 재사용, wildcard bind, source 내부 runtime/receipt, reparse-point 경로, readiness 실패는 모두
|
|
fail-closed다. 실제 provider 생성은 `/ready?force=true`로 정확히 한 번 확인하고, 실패하면 이번 실행이 소유한
|
|
PID/listener만 정리한다.
|
|
|
|
먼저 `-CheckOnly`로 `mutation=false` 영수증을 확인한다. 실제 시작은 별도 승인 뒤 외부 runtime-state/receipt
|
|
디렉터리를 미리 만들고 같은 인자로 `-CheckOnly`만 제거해 단 한 번 실행한다. 비밀값은 명령행·stdout·receipt에
|
|
기록하지 않는다. 성공 뒤 NAS origin의 health 3회, `/auth/me` 401, OpenAPI·asset, 실제 회기 turn→review를 다시
|
|
통과하기 전에는 preview를 GREEN으로 표시하지 않는다.
|
|
|
|
## 3. 환경변수 (.env)
|
|
|
|
| 변수 | 설명 |
|
|
|---|---|
|
|
| `POSTGRES_PASSWORD` | DB 비밀번호(필수) |
|
|
| `SESSION_SECRET` | 세션 서명키(필수, 랜덤) |
|
|
| `AUTH_ALLOWED_EMAIL_DOMAINS` | Google 로그인 허용 이메일 도메인(JSON 배열). 기본 `["hs.ac.kr","twentyoz.kr"]`. Google Console authorized domains가 아니라 서버에서 `email`/`hd` claim으로 강제 |
|
|
| `FRONTEND_ORIGIN_MAP` | API callback host → frontend origin 매핑(JSON 객체). 기본 `api-vignette.chanpaca.net → vignette.chanpaca.net`, `api-vnet.18ka.net → vnet.18ka.net` |
|
|
| `OPENAI_API_KEY` | 음성(STT/TTS) |
|
|
| `ANTHROPIC_API_KEY` | `claude_api` provider용. API 컨테이너가 아니라 엔진 게이트웨이 호스트에 주입 |
|
|
| `ENGINE_MODE` / `ENGINE_URL` | provider와 엔진 게이트웨이 위치(위 표) |
|
|
| `SITE_ADDRESS` | 외부노출 도메인(예: `vignette.chanpaca.net`). 비우면 로컬 :80 |
|
|
| `ACME_EMAIL` | 외부노출 시 Let's Encrypt 자동 TLS용 |
|
|
| `HTTP_PORT`/`HTTPS_PORT` | 호스트 포트 매핑 |
|
|
|
|
## 4. 외부 공유 (chanpaca.net, 교수 테스트)
|
|
|
|
두 가지 — 호스트 상황에 맞게:
|
|
- **Caddy 자동 TLS**: 공인 IP·도메인 있으면 `SITE_ADDRESS=vignette.chanpaca.net` + `ACME_EMAIL` → Caddy가 인증서 자동 발급.
|
|
|
|
## 4.1 vnet.18ka.net 공개 경로
|
|
|
|
`vnet.18ka.net`을 공개 Google OAuth로 쓰려면 세 조건이 같이 맞아야 한다.
|
|
|
|
1. DNS: `vnet.18ka.net`은 웹, `api-vnet.18ka.net`은 API로 라우팅되어야 한다.
|
|
2. API 설정: `CORS_ORIGINS`에 `https://vnet.18ka.net`, `FRONTEND_ORIGIN_MAP`에 `api-vnet.18ka.net=https://vnet.18ka.net`이 있어야 한다.
|
|
3. Google Cloud Console: Authorized redirect URI에 `https://api-vnet.18ka.net/auth/callback`을 추가해야 한다.
|
|
|
|
현재 이 저장소의 코드와 `scripts/start-public-runtime.ps1`은 2번을 회귀 테스트와 기본값으로 고정한다. 1번과 3번은 외부 콘솔/도메인 소유자 설정이다.
|
|
- **Cloudflare/Tailscale 터널**: 공인 IP 없을 때(네 PC). 단 **음성 SSE/WSS는 버퍼링 충돌**이 있어 Caddyfile에서 `flush_interval -1`로 흘려보냄(red team F-07 반영). 터널도 SSE 무버퍼 경로 분리 권장.
|
|
|
|
## 5. 스케일업 / 이전
|
|
|
|
- **수직**: compose 그대로, 호스트 사양만 키움.
|
|
- **수평**: `docker compose up --scale api=3` (api 무상태 설계 전제, 세션은 DB/Redis). proxy가 라운드로빈.
|
|
- **이전**: `pgdata`·`ragmodels` 볼륨만 새 호스트로 옮기고 `.env` 채워 `up`. (rag 모델 캐시 볼륨 덕에 재다운로드 0)
|
|
- **클라우드**: 동일 compose. `ENGINE_MODE=claude_api`와 게이트웨이 주소를 지정하고 게이트웨이 호스트에 `ANTHROPIC_API_KEY`를 주입한다.
|
|
|
|
## 6. 데이터 주권 / 보안
|
|
|
|
- DB는 NAS PostgreSQL(국내). 미성년 사례데이터는 repo·이미지에 절대 미포함(`.gitignore`).
|
|
- 외부 LLM 전송 전 PII 마스킹 미들웨어 통과(red team F-03).
|
|
- proxy 인증 게이트 뒤에서만 SSE/WSS 노출(무인증 IDOR 차단, F-20).
|
|
|
|
> 현 단계: 구성 골격(compose·Dockerfile·Caddy) 완비. 앱 코드(apps/web, apps/api) 채워지면 그대로 빌드된다.
|