From cb3b98db10b6c68942cfbc0eafe1d43fc94b0e28 Mon Sep 17 00:00:00 2001 From: goulustis Date: Sun, 8 Mar 2026 12:03:58 +0800 Subject: [PATCH] moved docker files --- Dockerfile => docker/Dockerfile | 0 docker/Dockerfile.prod | 85 +++++++++++++++++++++++++++++++++ docker/docker-compose.prod.yml | 74 ++++++++++++++++++++++++++++ 3 files changed, 159 insertions(+) rename Dockerfile => docker/Dockerfile (100%) create mode 100644 docker/Dockerfile.prod create mode 100644 docker/docker-compose.prod.yml diff --git a/Dockerfile b/docker/Dockerfile similarity index 100% rename from Dockerfile rename to docker/Dockerfile diff --git a/docker/Dockerfile.prod b/docker/Dockerfile.prod new file mode 100644 index 0000000..477e746 --- /dev/null +++ b/docker/Dockerfile.prod @@ -0,0 +1,85 @@ +# Multi-stage Dockerfile for production deployment +# Stage 1: Build frontend +FROM node:20-alpine AS frontend-builder + +WORKDIR /app/frontend + +# Copy frontend files +COPY frontend/package*.json ./ +RUN npm ci + +COPY frontend/ ./ +RUN npm run build + +# Stage 2: Python backend +FROM python:3.12-slim + +WORKDIR /app + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + postgresql-client \ + curl \ + && rm -rf /var/lib/apt/lists/* + +# Copy Python dependencies +COPY pyproject.toml ./ +RUN pip install --no-cache-dir --upgrade pip && \ + pip install --no-cache-dir -e . + +# Copy application code +COPY lang_agent/ ./lang_agent/ +COPY configs/ ./configs/ +COPY scripts/ ./scripts/ +COPY assets/ ./assets/ +COPY static/ ./static/ + +# Copy built frontend from stage 1 +COPY --from=frontend-builder /app/frontend/dist ./frontend/dist + +# Set environment variables +ENV PYTHONPATH=/app +ENV PYTHONUNBUFFERED=1 + +# Expose port +EXPOSE 8500 + +# Health check +HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ + CMD curl -f http://localhost:8500/health || exit 1 + +# Create entrypoint script to wait for DB +# Uses Python to check database connection (more reliable than psql) +RUN echo '#!/bin/bash\n\ +set -e\n\ +echo "Waiting for database to be ready..."\n\ +python3 << EOF\n\ +import sys\n\ +import time\n\ +import psycopg\n\ +\n\ +max_attempts = 30\n\ +conn_str = "${CONN_STR}"\n\ +\n\ +for i in range(max_attempts):\n\ + try:\n\ + with psycopg.connect(conn_str, connect_timeout=2) as conn:\n\ + with conn.cursor() as cur:\n\ + cur.execute("SELECT 1")\n\ + print("Database is ready!")\n\ + sys.exit(0)\n\ + except Exception as e:\n\ + if i == max_attempts - 1:\n\ + print(f"Warning: Database not ready after {max_attempts * 2} seconds, continuing anyway...")\n\ + print(f"Error: {e}")\n\ + sys.exit(0)\n\ + print(f"Database is unavailable - sleeping (attempt {i+1}/{max_attempts})")\n\ + time.sleep(2)\n\ +EOF\n\ +exec "$@"' > /entrypoint.sh && chmod +x /entrypoint.sh + +ENTRYPOINT ["/entrypoint.sh"] + +# Run the combined server +CMD ["python", "-m", "uvicorn", "lang_agent.fastapi_server.combined:app", "--host", "0.0.0.0", "--port", "8500"] + diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml new file mode 100644 index 0000000..fc7d4ff --- /dev/null +++ b/docker/docker-compose.prod.yml @@ -0,0 +1,74 @@ +version: '3.8' + +services: + # PostgreSQL database + postgres: + image: postgres:16-alpine + container_name: langchain-agent-db + environment: + POSTGRES_DB: postgres + POSTGRES_USER: postgres + POSTGRES_PASSWORD: ${POSTGRES_ROOT_PASSWORD:-postgres_root_password} + # These are used by init scripts to create the app database + APP_DB_NAME: ${POSTGRES_DB:-ai_conversations} + APP_DB_USER: ${POSTGRES_USER:-myapp_user} + APP_DB_PASSWORD: ${POSTGRES_PASSWORD:-secure_password_123} + volumes: + - postgres_data:/var/lib/postgresql/data + - ./scripts/init_database:/docker-entrypoint-initdb.d + ports: + - "${POSTGRES_PORT:-5432}:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + timeout: 5s + retries: 5 + restart: unless-stopped + + # Backend API server + backend: + build: + context: . + dockerfile: Dockerfile.prod + container_name: langchain-agent-backend + environment: + - PYTHONPATH=/app + - PYTHONUNBUFFERED=1 + - CONN_STR=postgresql://${POSTGRES_USER:-myapp_user}:${POSTGRES_PASSWORD:-secure_password_123}@postgres:5432/${POSTGRES_DB:-ai_conversations} + - POSTGRES_USER=${POSTGRES_USER:-myapp_user} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-secure_password_123} + - POSTGRES_DB=${POSTGRES_DB:-ai_conversations} + ports: + - "${BACKEND_PORT:-8500}:8500" + volumes: + - ../configs:/app/configs + - ../scripts:/app/scripts + - ../assets:/app/assets + - ../static:/app/static + depends_on: + postgres: + condition: service_healthy + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8500/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + # Nginx for serving frontend (optional - can also serve via FastAPI) + nginx: + image: nginx:alpine + container_name: langchain-agent-nginx + ports: + - "${FRONTEND_PORT:-80}:80" + volumes: + - ../nginx.conf:/etc/nginx/nginx.conf:ro + - ../frontend/dist:/usr/share/nginx/html:ro + depends_on: + - backend + restart: unless-stopped + +volumes: + postgres_data: +