Files
dpb/docker/docker-compose.yaml
T
34047007@qq.com b95053c52c init: 初始化 dpb 桃育种系统代码库
前后端 + 后端 FastAPI 全量源码、部署脚本与文档。
2026-08-06 00:17:49 +08:00

256 lines
8.6 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ============================================
# FastapiAdmin Docker Compose 配置文件
# ============================================
# 使用方式:
# 开发环境: docker compose --env-file .env up -d
# 生产环境: docker compose --env-file .env -f docker-compose.yaml up -d
# ============================================
services:
# ==================== 数据库服务(PostgreSQL 16 ====================
postgres:
container_name: postgres
image: postgres:16
restart: unless-stopped
platform: linux/amd64
environment:
TZ: "Asia/Shanghai"
POSTGRES_DB: "${DATABASE_NAME:-dpb}"
POSTGRES_USER: "${DATABASE_USER:-dpb}"
POSTGRES_PASSWORD: "${DATABASE_PASSWORD:?错误: 请设置 DATABASE_PASSWORD 环境变量}"
# 仅绑定本机回环:数据库不应暴露到公网/局域网,只允许后端容器与运维本机访问
ports:
- "127.0.0.1:${DATABASE_PORT:-5432}:5432"
volumes:
- pg_data:/var/lib/postgresql/data
- /etc/localtime:/etc/localtime:ro
networks:
- app_network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DATABASE_USER:-dpb}"]
interval: 10s
timeout: 10s
retries: 10
start_period: 30s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
memory: 1g
reservations:
memory: 256m
# ==================== Redis 服务 ====================
redis:
container_name: redis
image: redis:7-alpine
restart: unless-stopped
platform: linux/amd64
environment:
TZ: "Asia/Shanghai"
# 仅绑定本机回环:Redis 不应暴露到公网/局域网
ports:
- "127.0.0.1:${REDIS_PORT:-6379}:6379"
volumes:
- redis_data:/data
# 挂载自定义 redis.conf(若存在则覆盖默认配置)
- ./redis/conf/redis.conf:/usr/local/etc/redis/redis.conf:ro
command: >
redis-server /usr/local/etc/redis/redis.conf
--requirepass ${REDIS_PASSWORD:?错误: 请设置 REDIS_PASSWORD 环境变量}
networks:
- app_network
healthcheck:
test:
["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
memory: 512m
reservations:
memory: 128m
# ==================== 后端服务 ====================
backend:
container_name: backend
build:
context: ../
dockerfile: ./docker/backend/Dockerfile
args:
DEPLOY_ENV: "${DEPLOY_ENV:-prod}"
image: "backend:${BACKEND_IMAGE_TAG:-3.0.0}"
restart: unless-stopped
platform: linux/amd64
# 以非 root 运行(与 Dockerfile USER app 一致),降权容器内进程
user: "1001:1001"
# 纵深防御:禁止提权、丢弃全部 capabilitiesuvicorn 绑 8001 端口无需特权)
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
tmpfs:
- /tmp
environment:
TZ: "Asia/Shanghai"
# 运行环境,对应 backend/env/.env.{dev,prod}
ENVIRONMENT: "${DEPLOY_ENV:-prod}"
# PostgreSQL 连接配置(对应 backend/env/.env.prod 的 DATABASE_*
DATABASE_TYPE: "postgres"
DATABASE_HOST: "postgres"
DATABASE_PORT: "5432"
DATABASE_USER: "${DATABASE_USER:-dpb}"
DATABASE_PASSWORD: "${DATABASE_PASSWORD:?错误: 请设置 DATABASE_PASSWORD 环境变量}"
DATABASE_NAME: "${DATABASE_NAME:-dpb}"
# Redis 连接配置
REDIS_HOST: "redis"
REDIS_PORT: "6379"
REDIS_PASSWORD: "${REDIS_PASSWORD}"
REDIS_DB_NAME: "1"
REDIS_ENABLE: "true"
# JWT 签名密钥:必须通过 docker/.env 配置独立随机值(settings 会在 prod 下拒绝默认密钥)
SECRET_KEY: "${SECRET_KEY:?错误: 请设置 SECRET_KEY 环境变量(生产 JWT 密钥,勿用默认值)}"
# ── 应用层配置:镜像已排除 backend/env,以下全部由 docker/.env 注入(勿再依赖 .env.prod)──
# CORS 白名单:生产必须配置具体域名,为空时后端 prod 校验将拒绝启动
PROD_CORS_ORIGINS: "${PROD_CORS_ORIGINS:-}"
# Host 头白名单(nginx 反代时后端据此校验 Host,必须配置真实域名,否则请求 403)
ALLOWED_HOSTS: "${ALLOWED_HOSTS:?错误: 请设置 ALLOWED_HOSTS(如 [\"admin.example.com\",\"*.example.com\"]}"
# 是否信任 nginx 透传的客户端 IP 头(经可信代理时必须 true)
IP_TRUST_PROXY_HEADERS: "${IP_TRUST_PROXY_HEADERS:-true}"
# 登录暴力破解防护
LOGIN_MAX_FAILURES: "${LOGIN_MAX_FAILURES:-5}"
LOGIN_FAILURE_WINDOW_SECONDS: "${LOGIN_FAILURE_WINDOW_SECONDS:-900}"
LOGIN_LOCKOUT_SECONDS: "${LOGIN_LOCKOUT_SECONDS:-900}"
# 登录验证码 / 演示模式 / 开发默认密码(生产必须保持为空)
CAPTCHA_ENABLE: "${CAPTCHA_ENABLE:-true}"
DEMO_ENABLE: "${DEMO_ENABLE:-false}"
DEV_DEFAULT_PASSWORD: "${DEV_DEFAULT_PASSWORD:-}"
# SMTP 邮件
SMTP_HOST: "${SMTP_HOST:-}"
SMTP_PORT: "${SMTP_PORT:-465}"
SMTP_USER: "${SMTP_USER:-}"
SMTP_PASSWORD: "${SMTP_PASSWORD:-}"
SMTP_FROM: "${SMTP_FROM:-}"
SMTP_FROM_NAME: "${SMTP_FROM_NAME:-客户服务}"
SMTP_TLS: "${SMTP_TLS:-true}"
EMAIL_CODE_EXPIRE_SECONDS: "${EMAIL_CODE_EXPIRE_SECONDS:-300}"
# 大模型
OPENAI_BASE_URL: "${OPENAI_BASE_URL:-https://api.deepseek.com}"
OPENAI_API_KEY: "${OPENAI_API_KEY:-}"
OPENAI_MODEL: "${OPENAI_MODEL:-deepseek-chat}"
# 日志级别
LOGGER_LEVEL: "${LOGGER_LEVEL:-INFO}"
# 非 root 容器下禁止写 __pycache__/home 已 chown 可写,此处避免 import 时缓存字节码)
PYTHONDONTWRITEBYTECODE: "1"
# 仅绑定本机回环:后端只经 nginx 对外,避免 8001 直连暴露(否则可绕过 Host 头/CORS/HTTPS 约束)
ports:
- "127.0.0.1:${BACKEND_PORT:-8001}:8001"
# volumes:
# ── 注意 ──────────────────────────────────
# 生产环境禁用代码挂载:镜像已自包含(见 Dockerfile COPY ./backend/)。
# 仅本地开发需要热更新时取消注释下面这行(宿主机代码覆盖容器内代码)。
# ─────────────────────────────────────────
# - ../backend:/home
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- app_network
healthcheck:
test:
[
"CMD-SHELL",
"python -c 'import urllib.request; urllib.request.urlopen(\"http://localhost:8001/common/health/check\")' || exit 1",
]
interval: 15s
timeout: 10s
retries: 5
start_period: 40s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
memory: 1g
cpus: "1.0"
reservations:
memory: 256m
# ==================== Nginx 服务 ====================
nginx:
container_name: nginx
image: nginx:1.25-alpine
restart: unless-stopped
platform: linux/amd64
environment:
TZ: "Asia/Shanghai"
ports:
- "${HTTP_PORT:-80}:80"
- "${HTTPS_PORT:-443}:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/web:/usr/share/nginx/html/web:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
# 按需启用(取消注释):
- ./nginx/app:/usr/share/nginx/html/app:ro
- ./nginx/docs:/usr/share/nginx/html/docs:ro
depends_on:
backend:
condition: service_started
networks:
- app_network
healthcheck:
test: ["CMD", "nginx", "-t"]
interval: 30s
timeout: 5s
retries: 3
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
memory: 256m
cpus: "0.5"
reservations:
memory: 64m
# ==================== 持久化卷 ====================
volumes:
pg_data:
driver: local
driver_opts:
type: none
device: ./postgres/data
o: bind
redis_data:
driver: local
driver_opts:
type: none
device: ./redis/data
o: bind
# ==================== 网络 ====================
networks:
app_network:
driver: bridge