docker-compose.yml
Rama main · réplica de lectura del repositorio original.
# Lively 배포 스택.
#
# 기본 토폴로지 = Option 2 (배포 설계 결정):
# · store(pgvector) = 도커(이 compose)
# · gateway(게이트웨이 = 컨트롤플레인 + 중앙박스 러너) = 호스트 네이티브(systemd/launchd, deploy/ 참조)
# 네이티브 게이트웨이가 호스트 docker 를 그대로 쓰므로 중앙박스(웹터미널) 세션의 DinD 함정을 피한다.
# (근거: knowledge_get central-box-design)
#
# 사용:
# docker compose up -d # items-db(pgvector) 만 = Option 2 의 도커 파트
# docker compose --profile embeddings up -d # + Ollama 임베딩 사이드카(#172, 4GB 박스엔 비권장 — t4g.large+)
# docker compose --profile gateway up -d # + 게이트웨이까지 컨테이너로(full-docker / Option 1 미리보기)
#
# 시크릿은 .env(PGPASSWORD 등)에서 읽는다. deploy/install.sh 가 .env 를 생성한다(deploy/lib/common.sh).
# ⚠ compose 프로젝트명은 레포명과 별개로 고정한다 — 바꾸면 named volume 이름(items-db-data)이 달라져
# 기존 박스의 DB 가 빈 볼륨으로 새로 생성된다(데이터 유실). 레포명이 lively 로 바뀐 뒤에도 이 값은 유지.
name: context-ontology
# ⚠ 컨테이너 로그 상한(#813) — 도커 기본 json-file 드라이버는 **상한이 없다**(무제한 증가).
# 박스 수명은 수년이고 고객 박스는 우리가 들여다보지 못하므로, 방치하면 로그만으로 디스크가 찬다
# (디스크가 차면 Postgres 가 죽어 전 기능이 500 — 2026-07-13 사고). 모든 서비스에 앵커로 상속시킨다.
# 게이트웨이 자신의 로그(logs/gateway.log)는 in-process 재니터가 관리한다(관리탭 '저장소·로그').
x-logging: &default-logging
driver: json-file
options:
max-size: ${DOCKER_LOG_MAX_SIZE:-10m}
max-file: "${DOCKER_LOG_MAX_FILE:-3}"
services:
# ── store: 조직 지식(knowledge)·v6·도메인맵·임베딩이 사는 쓰기 DB. ──
# ⚠ 불변식: 이미지는 반드시 pgvector/pgvector — plain postgres 로 재생성 금지(#172 벡터검색).
# (knowledge_get items-db-pgvector-image-invariant)
items-db:
image: pgvector/pgvector:pg18
environment:
POSTGRES_USER: ${PGUSER:-lively}
POSTGRES_PASSWORD: ${PGPASSWORD:?PGPASSWORD 를 .env 에 설정하세요 (deploy/install.sh 가 생성)}
POSTGRES_DB: ${PGDATABASE:-items}
ports:
# ⚠ 127.0.0.1 바인딩 — DB 를 외부에 노출하지 않는다(네이티브 게이트웨이가 localhost 로 접근).
- "127.0.0.1:${ITEMS_DB_PORT:-5432}:5432"
volumes:
# ⚠ pg18+ 이미지는 단일 마운트 /var/lib/postgresql (데이터는 그 아래 버전 서브디렉). /data 마운트는 거부됨.
- items-db-data:/var/lib/postgresql
- ./deploy/initdb:/docker-entrypoint-initdb.d:ro # 최초 init 1회: domainmap DB 생성
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${PGUSER:-lively} -d ${PGDATABASE:-items}"]
interval: 5s
timeout: 5s
retries: 30
logging: *default-logging
restart: unless-stopped
# ── 임베딩 사이드카(선택, profile=embeddings) — OpenAI-compatible /v1/embeddings(Ollama, CPU). ──
# 스왑: 다른 모델=EMBEDDINGS_MODEL + ollama pull; 다른 런타임/외부 API=EMBEDDINGS_BASE_URL 교체.
# ⚠ 판을 고정한다 — latest 면 박스마다 설치 시점의 판이 깔린다. 올릴 땐 아래 두 줄을 같은 판으로(deploy/enable-embeddings.test.mjs).
embeddings:
image: ollama/ollama:0.40.13
profiles: ["embeddings"]
ports:
- "127.0.0.1:${EMBEDDINGS_PORT:-11434}:11434" # 네이티브 게이트웨이가 localhost 로 접근
volumes:
- ollama-models:/root/.ollama
logging: *default-logging
restart: unless-stopped
embeddings-init: # 최초 1회 모델 pull(멱등). store 의 임베딩 호출 전에 모델 준비.
image: ollama/ollama:0.40.13
profiles: ["embeddings"]
depends_on: [embeddings]
environment:
OLLAMA_HOST: embeddings:11434
entrypoint: ["/bin/sh","-c","until ollama list >/dev/null 2>&1; do sleep 1; done; ollama pull ${EMBEDDINGS_MODEL:-bge-m3}"]
logging: *default-logging
restart: "no"
# ── gateway(선택, profile=gateway) — full-docker(Option 1) 미리보기. 파일럿(Option 2)은 미사용. ──
# ⚠ 컨테이너 안에서 중앙박스 세션을 띄우면 DinD 함정. 중앙박스(웹터미널)를 쓸 거면 네이티브로(deploy/).
gateway:
build: .
profiles: ["gateway"]
env_file: [.env]
environment:
# 컨테이너 네트워크 안에서는 호스트가 'items-db'. (네이티브 경로의 localhost 와 분리)
ITEMS_DATABASE_URL: postgres://${PGUSER:-lively}:${PGPASSWORD}@items-db:5432/${PGDATABASE:-items}
EMBEDDINGS_BASE_URL: ${EMBEDDINGS_BASE_URL_COMPOSE:-http://embeddings:11434}
LANG: C.UTF-8
LC_ALL: C.UTF-8
depends_on:
items-db:
condition: service_healthy
ports:
- "${PORT:-8080}:8080"
logging: *default-logging
restart: unless-stopped
# ── caddy(선택, profile=proxy) — 자동 HTTPS 리버스 프록시(Let's Encrypt). TLS 종단 → localhost:8080. ──
# network_mode: host → 호스트 80/443 바인딩 + 네이티브 게이트웨이(localhost:8080)로 프록시. WS Upgrade 자동 통과.
# 도메인 필요(LIVELY_DOMAIN — A레코드가 이 호스트를 향해야 인증서 발급). 인증서는 caddy-data 볼륨에 영속.
caddy:
image: caddy:2
profiles: ["proxy"]
network_mode: host
logging: *default-logging
restart: unless-stopped
environment:
# 기본 빈 값(:-) — 프로필 미지정(items-db/gateway) up 시에도 파싱되게. compose 는 프로필 필터 전에
# 파일 전체를 interpolate 하므로 :? 면 TLS 안 쓰는 설치도 막힌다. 도메인 검증은 proxy_up(common.sh).
LIVELY_DOMAIN: ${LIVELY_DOMAIN:-}
LIVELY_UPSTREAM: ${LIVELY_UPSTREAM:-localhost:8080}
volumes:
- ./deploy/Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
- caddy-config:/config
volumes:
items-db-data: # ⚠ 조직 지식 전체. 백업 대상(pg_dump / 볼륨 스냅샷). -v 로 날리지 말 것.
ollama-models:
caddy-data: # ⚠ TLS 인증서·ACME 계정. 삭제 시 재발급(LE rate-limit 주의).
caddy-config: