fix: Docker deployment optimization

- Replace postgres:15-alpine with pgvector/pgvector:pg15 (built-in vector extension)
- Remove init-db.sh (pgvector image includes extension, SQL init script instead)
- Add multi-stage Dockerfile for backend (development/runtime targets)
- Add development stage to frontend Dockerfile
- Update .env.example with correct passwords and Docker-internal URLs
- Add POSTGRES_PASSWORD/REDIS_PASSWORD to .env for Docker Compose
- Use named volume for frontend node_modules
- Add backend healthcheck to docker-compose.yml
This commit is contained in:
chiguyong 2026-06-01 23:10:29 +08:00
parent 33aecc0cb1
commit 218ece564d
6 changed files with 68 additions and 57 deletions

View File

@ -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

View File

@ -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

View File

@ -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 ==="

View File

@ -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:

View File

@ -0,0 +1 @@
CREATE EXTENSION IF NOT EXISTS vector;

View File

@ -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