services: # ---------------------------------------- # 1. Frontend (Nginx 정적 호스팅) # ---------------------------------------- frontend: container_name: ${PROJECT_NAME}-frontend build: context: ./${FRONTEND_DIR} dockerfile: Dockerfile args: - BUILD_MODE=${BUILD_MODE} - VITE_API_BASE_URL=${BACKEND_API_URL} - VITE_AI_TIMEOUT_MS=${AI_TIMEOUT_MS} # 브라우저가 접속할 LiveKit WebSocket URL - VITE_LIVEKIT_URL=${LIVEKIT_WS_URL} expose: - "80" environment: - NODE_ENV=${APP_ENV} restart: unless-stopped networks: - app-network - proxy depends_on: - backend healthcheck: # localhost 는 일부 이미지에서 IPv6(::1) 로 먼저 풀려 IPv4 전용 바인딩에 연결 실패 → 127.0.0.1 고정 test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:80/ || exit 1"] interval: 30s timeout: 5s retries: 5 start_period: 10s deploy: resources: limits: cpus: '0.5' memory: 512m # ---------------------------------------- # 2. Backend (HTTP API & WebSocket 통합) # ---------------------------------------- backend: container_name: ${PROJECT_NAME}-backend build: context: ./${BACKEND_DIR} dockerfile: Dockerfile expose: - "${BACKEND_PORT}" - "${WEBSOCKET_PORT}" env_file: - ./${BACKEND_DIR}/.env.${APP_ENV} environment: - NODE_ENV=${APP_ENV} - PORT=${BACKEND_PORT} - WEBSOCKET_PORT=${WEBSOCKET_PORT} - CORS_ORIGIN=${CORS_ORIGIN} - DB_HOST=db - DB_PORT=5432 - DB_USER=${DB_USER} - DB_PASSWORD=${DB_PASSWORD} - DB_NAME=${DB_NAME} - REDIS_HOST=redis - REDIS_PORT=6379 - REDIS_PASSWORD=${REDIS_PASSWORD} # AI 요청 타임아웃(ms) — 프론트(VITE_AI_TIMEOUT_MS)와 동일 값을 루트 .env 에서 공급 - AI_TIMEOUT_MS=${AI_TIMEOUT_MS} # 화상회의(LiveKit) — 토큰 발급에 키/시크릿, 서버 API 호출에 내부 URL 사용 - LIVEKIT_API_KEY=${LIVEKIT_API_KEY} - LIVEKIT_API_SECRET=${LIVEKIT_API_SECRET} - LIVEKIT_URL=${LIVEKIT_URL} restart: unless-stopped networks: - app-network - proxy depends_on: db: condition: service_healthy redis: condition: service_healthy healthcheck: # API 는 전역 프리픽스 /api 하위에 마운트됨 — 루트(/)는 404 라 /api/health 를 프로브. # localhost→IPv6(::1) 회피를 위해 127.0.0.1 고정. test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:${BACKEND_PORT}/api/health || exit 1"] interval: 30s timeout: 5s retries: 5 start_period: 30s deploy: resources: limits: cpus: '1.0' memory: 1g # ---------------------------------------- # 3. Database (PostgreSQL) — 내부 네트워크 전용 # ---------------------------------------- db: container_name: ${PROJECT_NAME}-db image: ${DB_IMAGE} expose: - "5432" environment: POSTGRES_USER: ${DB_USER} POSTGRES_PASSWORD: ${DB_PASSWORD} POSTGRES_DB: ${DB_NAME} volumes: - ${DB_DATA_DIR}:/var/lib/postgresql/data restart: always networks: - app-network healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"] interval: 10s timeout: 5s retries: 5 start_period: 10s deploy: resources: limits: cpus: '0.5' memory: 512m labels: - "com.centurylinklabs.watchtower.enable=true" # ---------------------------------------- # 4. Redis — 내부 네트워크 전용 # ---------------------------------------- redis: container_name: ${PROJECT_NAME}-redis image: ${REDIS_IMAGE} command: redis-server --requirepass ${REDIS_PASSWORD} expose: - "6379" volumes: - ${REDIS_DATA_DIR}:/data restart: always networks: - app-network healthcheck: test: ["CMD-SHELL", "redis-cli -a ${REDIS_PASSWORD} ping | grep PONG"] interval: 10s timeout: 5s retries: 5 start_period: 5s deploy: resources: limits: cpus: '0.25' memory: 256m labels: - "com.centurylinklabs.watchtower.enable=true" networks: app-network: driver: bridge proxy: external: true