diff --git a/.env.example b/.env.example index eeed042..07420a6 100644 --- a/.env.example +++ b/.env.example @@ -4,14 +4,26 @@ # ============================================================================= # ----------------------------------------------------------------------------- -# 数据库(PostgreSQL) +# 数据库密码(Docker Compose 引用此变量) # ----------------------------------------------------------------------------- -DATABASE_URL=postgresql+asyncpg://postgres:postgres123@db:5432/geo_platform +POSTGRES_PASSWORD=geo_pg_dev_2026 + +# ----------------------------------------------------------------------------- +# Redis 密码(Docker Compose 引用此变量) +# ----------------------------------------------------------------------------- +REDIS_PASSWORD=geo_redis_dev_2026 + +# ----------------------------------------------------------------------------- +# 数据库(PostgreSQL + pgvector) +# Docker 内部使用 db:5432,本地直连使用 localhost:5433 +# ----------------------------------------------------------------------------- +DATABASE_URL=postgresql+asyncpg://postgres:geo_pg_dev_2026@db:5432/geo_platform # ----------------------------------------------------------------------------- # Redis(缓存 / 任务队列) +# Docker 内部使用 redis:6379,本地直连使用 localhost:6380 # ----------------------------------------------------------------------------- -REDIS_URL=redis://redis:6379/0 +REDIS_URL=redis://:geo_redis_dev_2026@redis:6379/0 # ----------------------------------------------------------------------------- # JWT 认证密钥 @@ -80,11 +92,10 @@ BAIDU_QIANFAN_API_KEY=your-baidu-qianfan-api-key-here BAIDU_QIANFAN_SECRET_KEY=your-baidu-qianfan-secret-key-here # 豆包(字节跳动) -DOUBAO_API_KEY=your-doubao-api-key-here +DOUBAO_API_KEY=your-doubbo-api-key-here DOUBAO_ENDPOINT_ID=your-doubao-endpoint-id-here # ----------------------------------------------------------------------------- # API 调用频率限制 # ----------------------------------------------------------------------------- -# 每分钟最大请求数(防止触发平台限速) API_RATE_LIMIT_RPM=10 diff --git a/backend/Dockerfile b/backend/Dockerfile index 11c8b6a..916a03e 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,10 +1,26 @@ -FROM python:3.11-slim +FROM python:3.11-slim AS base WORKDIR /app -# 安装系统依赖(Playwright需要) RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ + && rm -rf /var/lib/apt/lists/* + +COPY requirements.txt . + +FROM base AS development + +RUN pip install --no-cache-dir -r requirements.txt + +COPY . . + +EXPOSE 8000 + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] + +FROM base AS runtime + +RUN apt-get update && apt-get install -y --no-install-recommends \ wget \ gnupg \ libglib2.0-0 \ @@ -24,20 +40,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libasound2 \ && rm -rf /var/lib/apt/lists/* -# 复制并安装Python依赖 -COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt -# 安装Playwright浏览器 RUN playwright install chromium RUN playwright install-deps chromium -# 复制应用代码 COPY . . EXPOSE 8000 -# 健康检查 HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \ CMD curl -f http://localhost:8000/health || exit 1 diff --git a/backend/init-db.sh b/backend/init-db.sh deleted file mode 100755 index 63ab761..0000000 --- a/backend/init-db.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -set -e - -echo "=== Installing pgvector extension for PostgreSQL ===" - -echo "[1/5] Installing build dependencies..." -apk add --no-cache build-base git clang llvm-dev postgresql-dev - -echo "[2/5] Cloning pgvector v0.5.1..." -cd /tmp -rm -rf pgvector -git clone --branch v0.5.1 --depth 1 https://github.com/pgvector/pgvector.git - -echo "[3/5] Compiling and installing pgvector..." -cd /tmp/pgvector -make -make install - -echo "[4/5] Cleaning up build dependencies..." -cd / -rm -rf /tmp/pgvector -apk del build-base git clang llvm-dev postgresql-dev - -echo "[5/5] Creating vector extension in database..." -psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL - CREATE EXTENSION IF NOT EXISTS vector; -EOSQL - -echo "=== pgvector installation complete ===" diff --git a/docker-compose.yml b/docker-compose.yml index 1440981..3e532c4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: db: - image: postgres:15-alpine + image: pgvector/pgvector:pg15 container_name: geo_db restart: unless-stopped environment: @@ -11,7 +11,7 @@ services: - "5433:5432" volumes: - postgres_data:/var/lib/postgresql/data - - ./backend/init-db.sh:/docker-entrypoint-initdb.d/01-install-pgvector.sh + - ./docker/init-db:/docker-entrypoint-initdb.d healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres -d geo_platform"] interval: 5s @@ -48,7 +48,10 @@ services: memory: 64m backend: - build: ./backend + build: + context: ./backend + dockerfile: Dockerfile + target: ${BACKEND_TARGET:-runtime} container_name: geo_backend restart: unless-stopped ports: @@ -66,6 +69,12 @@ services: redis: condition: service_healthy command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/health"] + interval: 30s + timeout: 10s + start_period: 30s + retries: 3 deploy: resources: limits: @@ -75,16 +84,21 @@ services: memory: 256m frontend: - build: ./frontend + build: + context: ./frontend + dockerfile: Dockerfile + target: ${FRONTEND_TARGET:-development} container_name: geo_frontend restart: unless-stopped ports: - "3000:3000" env_file: - .env + environment: + NEXT_PUBLIC_API_URL: http://localhost:8000 volumes: - ./frontend:/app - - /app/node_modules + - frontend_node_modules:/app/node_modules depends_on: - backend command: npm run dev @@ -99,3 +113,4 @@ services: volumes: postgres_data: redis_data: + frontend_node_modules: diff --git a/docker/init-db/01-enable-pgvector.sql b/docker/init-db/01-enable-pgvector.sql new file mode 100644 index 0000000..0aa0fc2 --- /dev/null +++ b/docker/init-db/01-enable-pgvector.sql @@ -0,0 +1 @@ +CREATE EXTENSION IF NOT EXISTS vector; diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 85c054c..2347fc3 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,32 +1,35 @@ -# ============================================================ -# Stage 1: Builder — 构建 Next.js 生产产物 -# ============================================================ +FROM node:20-alpine AS development + +WORKDIR /app + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY . . + +EXPOSE 3000 + +CMD ["npm", "run", "dev"] + FROM node:20-alpine AS builder WORKDIR /app -# 安装依赖(利用缓存层) COPY package.json package-lock.json ./ RUN npm ci -# 复制源码并构建 COPY . . RUN npm run build -# ============================================================ -# Stage 2: Runner — 只保留运行时必要文件 -# ============================================================ FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production -# 创建非 root 用户运行应用 RUN addgroup --system --gid 1001 nodejs \ && adduser --system --uid 1001 nextjs -# 复制 standalone 构建产物 COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static COPY --from=builder --chown=nextjs:nodejs /app/public ./public @@ -38,7 +41,6 @@ EXPOSE 3000 ENV PORT=3000 ENV HOSTNAME="0.0.0.0" -# 健康检查 HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \ CMD wget -qO- http://localhost:3000/ || exit 1