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缓存 / 任务队列) # Redis缓存 / 任务队列)
# Docker 内部使用 redis:6379本地直连使用 localhost:6380
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
REDIS_URL=redis://redis:6379/0 REDIS_URL=redis://:geo_redis_dev_2026@redis:6379/0
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# JWT 认证密钥 # 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 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 DOUBAO_ENDPOINT_ID=your-doubao-endpoint-id-here
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# API 调用频率限制 # API 调用频率限制
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# 每分钟最大请求数(防止触发平台限速)
API_RATE_LIMIT_RPM=10 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 WORKDIR /app
# 安装系统依赖Playwright需要
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
curl \ 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 \ wget \
gnupg \ gnupg \
libglib2.0-0 \ libglib2.0-0 \
@ -24,20 +40,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libasound2 \ libasound2 \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
# 复制并安装Python依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
# 安装Playwright浏览器
RUN playwright install chromium RUN playwright install chromium
RUN playwright install-deps chromium RUN playwright install-deps chromium
# 复制应用代码
COPY . . COPY . .
EXPOSE 8000 EXPOSE 8000
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \ HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1 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: services:
db: db:
image: postgres:15-alpine image: pgvector/pgvector:pg15
container_name: geo_db container_name: geo_db
restart: unless-stopped restart: unless-stopped
environment: environment:
@ -11,7 +11,7 @@ services:
- "5433:5432" - "5433:5432"
volumes: volumes:
- postgres_data:/var/lib/postgresql/data - 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: healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d geo_platform"] test: ["CMD-SHELL", "pg_isready -U postgres -d geo_platform"]
interval: 5s interval: 5s
@ -48,7 +48,10 @@ services:
memory: 64m memory: 64m
backend: backend:
build: ./backend build:
context: ./backend
dockerfile: Dockerfile
target: ${BACKEND_TARGET:-runtime}
container_name: geo_backend container_name: geo_backend
restart: unless-stopped restart: unless-stopped
ports: ports:
@ -66,6 +69,12 @@ services:
redis: redis:
condition: service_healthy condition: service_healthy
command: uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload 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: deploy:
resources: resources:
limits: limits:
@ -75,16 +84,21 @@ services:
memory: 256m memory: 256m
frontend: frontend:
build: ./frontend build:
context: ./frontend
dockerfile: Dockerfile
target: ${FRONTEND_TARGET:-development}
container_name: geo_frontend container_name: geo_frontend
restart: unless-stopped restart: unless-stopped
ports: ports:
- "3000:3000" - "3000:3000"
env_file: env_file:
- .env - .env
environment:
NEXT_PUBLIC_API_URL: http://localhost:8000
volumes: volumes:
- ./frontend:/app - ./frontend:/app
- /app/node_modules - frontend_node_modules:/app/node_modules
depends_on: depends_on:
- backend - backend
command: npm run dev command: npm run dev
@ -99,3 +113,4 @@ services:
volumes: volumes:
postgres_data: postgres_data:
redis_data: redis_data:
frontend_node_modules:

View File

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

View File

@ -1,32 +1,35 @@
# ============================================================ FROM node:20-alpine AS development
# Stage 1: Builder — 构建 Next.js 生产产物
# ============================================================ WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
FROM node:20-alpine AS builder FROM node:20-alpine AS builder
WORKDIR /app WORKDIR /app
# 安装依赖(利用缓存层)
COPY package.json package-lock.json ./ COPY package.json package-lock.json ./
RUN npm ci RUN npm ci
# 复制源码并构建
COPY . . COPY . .
RUN npm run build RUN npm run build
# ============================================================
# Stage 2: Runner — 只保留运行时必要文件
# ============================================================
FROM node:20-alpine AS runner FROM node:20-alpine AS runner
WORKDIR /app WORKDIR /app
ENV NODE_ENV=production ENV NODE_ENV=production
# 创建非 root 用户运行应用
RUN addgroup --system --gid 1001 nodejs \ RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 nextjs && adduser --system --uid 1001 nextjs
# 复制 standalone 构建产物
COPY --from=builder --chown=nextjs:nodejs /app/.next/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/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/public ./public
@ -38,7 +41,6 @@ EXPOSE 3000
ENV PORT=3000 ENV PORT=3000
ENV HOSTNAME="0.0.0.0" ENV HOSTNAME="0.0.0.0"
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \ HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \
CMD wget -qO- http://localhost:3000/ || exit 1 CMD wget -qO- http://localhost:3000/ || exit 1