chore: split Dockerfile into runtime+e2e stages, add healthchecks

- Split Dockerfile: runtime stage (no Playwright) + e2e stage (adds Chromium)
- Add healthcheck to backend and frontend in docker-compose.prod.yml
- Fix REDIS_URL default to empty string (no hardcoded password)
- Add RATE_LIMIT_BACKEND=redis to production env example
- Remove deprecated version field from docker-compose.prod.yml
This commit is contained in:
chiguyong 2026-06-04 14:04:11 +08:00
parent 331f6bce80
commit ee8578c3d7
4 changed files with 45 additions and 17 deletions

View File

@ -7,7 +7,9 @@
# ============================================================ # ============================================================
# Database (MUST use strong password in production) # Database (MUST use strong password in production)
# ============================================================ # ============================================================
POSTGRES_USER=postgres
POSTGRES_PASSWORD=CHANGE_ME_strong_pg_password_32chars! POSTGRES_PASSWORD=CHANGE_ME_strong_pg_password_32chars!
POSTGRES_DB=geo_platform
DATABASE_URL=postgresql+asyncpg://postgres:CHANGE_ME_strong_pg_password_32chars!@db:5432/geo_platform DATABASE_URL=postgresql+asyncpg://postgres:CHANGE_ME_strong_pg_password_32chars!@db:5432/geo_platform
# ============================================================ # ============================================================
@ -55,6 +57,7 @@ DOUBAO_ENDPOINT_ID=
# Rate Limiting # Rate Limiting
# ============================================================ # ============================================================
API_RATE_LIMIT_RPM=10 API_RATE_LIMIT_RPM=10
RATE_LIMIT_BACKEND=redis
# ============================================================ # ============================================================
# Payment / Distribution / Email (set to real mode in production) # Payment / Distribution / Email (set to real mode in production)
@ -62,3 +65,14 @@ API_RATE_LIMIT_RPM=10
PAYMENT_MODE=mock PAYMENT_MODE=mock
DISTRIBUTION_MODE=mock DISTRIBUTION_MODE=mock
EMAIL_MODE=mock EMAIL_MODE=mock
# ============================================================
# Monitoring
# ============================================================
SENTRY_DSN=
ENVIRONMENT=production
# ============================================================
# Playwright (for E2E testing only, not needed in production)
# ============================================================
PLAYWRIGHT_BROWSERS_PATH=/ms-playwright

View File

@ -20,6 +20,20 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload
FROM base AS runtime FROM base AS runtime
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
CMD ["gunicorn", "app.main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", \
"--bind", "0.0.0.0:8000", "--timeout", "120", "--access-logfile", "-"]
FROM runtime AS e2e
RUN apt-get update && apt-get install -y --no-install-recommends \ RUN apt-get update && apt-get install -y --no-install-recommends \
wget \ wget \
gnupg \ gnupg \
@ -40,17 +54,5 @@ 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/*
RUN pip install --no-cache-dir -r requirements.txt
RUN playwright install chromium RUN playwright install chromium
RUN playwright install-deps 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
CMD ["gunicorn", "app.main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", \
"--bind", "0.0.0.0:8000", "--timeout", "120", "--access-logfile", "-"]

View File

@ -13,8 +13,6 @@
# 5. 使用 docker compose -f docker-compose.prod.yml up -d 启动 # 5. 使用 docker compose -f docker-compose.prod.yml up -d 启动
# ============================================================ # ============================================================
version: "3.9"
services: services:
db: db:
image: pgvector/pgvector:pg15 image: pgvector/pgvector:pg15
@ -75,6 +73,7 @@ services:
build: build:
context: ./backend context: ./backend
dockerfile: Dockerfile dockerfile: Dockerfile
target: runtime
container_name: geo_backend_prod container_name: geo_backend_prod
restart: always restart: always
expose: expose:
@ -87,6 +86,12 @@ services:
condition: service_healthy condition: service_healthy
redis: redis:
condition: service_healthy condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
# 使用 Dockerfile 中定义的 gunicorn 启动命令 # 使用 Dockerfile 中定义的 gunicorn 启动命令
deploy: deploy:
resources: resources:
@ -113,6 +118,12 @@ services:
# 生产环境不挂载源代码目录 # 生产环境不挂载源代码目录
depends_on: depends_on:
- backend - backend
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/auth/session"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
deploy: deploy:
resources: resources:
limits: limits:

View File

@ -61,6 +61,7 @@ services:
environment: environment:
DATABASE_URL: postgresql+asyncpg://postgres:${POSTGRES_PASSWORD:-geo_pg_dev_2026}@db:5432/geo_platform DATABASE_URL: postgresql+asyncpg://postgres:${POSTGRES_PASSWORD:-geo_pg_dev_2026}@db:5432/geo_platform
REDIS_URL: redis://:${REDIS_PASSWORD:-geo_redis_dev_2026}@redis:6379/0 REDIS_URL: redis://:${REDIS_PASSWORD:-geo_redis_dev_2026}@redis:6379/0
RATE_LIMIT_DISABLED: ${RATE_LIMIT_DISABLED:-0}
volumes: volumes:
- ./backend:/app - ./backend:/app
depends_on: depends_on:
@ -105,10 +106,10 @@ services:
deploy: deploy:
resources: resources:
limits: limits:
memory: 256m memory: 2g
cpus: '0.5' cpus: '2.0'
reservations: reservations:
memory: 128m memory: 512m
volumes: volumes:
postgres_data: postgres_data: