# 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 set -eux; \ for source_file in /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources; do \ if [ -f "$source_file" ]; then \ sed -i 's|deb.debian.org|mirrors.aliyun.com|g' "$source_file"; \ sed -i 's|security.debian.org|mirrors.aliyun.com|g' "$source_file"; \ fi; \ done; \ apt-get update; \ apt-get install -y --no-install-recommends \ postgresql-client \ curl; \ rm -rf /var/lib/apt/lists/* # Copy Python dependencies COPY pyproject.toml ./ RUN pip install --no-cache-dir --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple && \ pip install --no-cache-dir -e . -i https://pypi.tuna.tsinghua.edu.cn/simple # 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"]