chore: add production environment configuration system

This commit is contained in:
Xiaoxia AI
2026-06-15 18:32:05 +08:00
parent 0f16fa600f
commit 36126b47d7
8 changed files with 552 additions and 31 deletions
+80 -6
View File
@@ -1,11 +1,85 @@
# Environment example
APP_ENV=development
# =======================
# 应用基础配置
# =======================
APP_ENV=development # development / staging / production
APP_NAME=xiaoxia-saas
APP_VERSION=0.1.0
DEBUG=true
# =======================
# API 服务配置
# =======================
API_HOST=0.0.0.0
API_PORT=8000
API_PREFIX=/api/v1
# =======================
# Web 前端配置
# =======================
WEB_PORT=3000
POSTGRES_URL=postgresql+psycopg://postgres:postgres@localhost:5432/xiaoxia_saas
WEB_URL=http://localhost:3000
# =======================
# 数据库配置
# =======================
DATABASE_URL=postgresql+psycopg://postgres:postgres@localhost:5432/xiaoxia_saas
DATABASE_POOL_SIZE=20
DATABASE_MAX_OVERFLOW=40
DATABASE_POOL_TIMEOUT=30
DATABASE_POOL_RECYCLE=3600
# =======================
# Redis 配置
# =======================
REDIS_URL=redis://localhost:6379/0
OBJECT_STORAGE_PROVIDER=minio
OBJECT_STORAGE_ENDPOINT=http://localhost:9000
OBJECT_STORAGE_BUCKET=xiaoxia-saas
REDIS_MAX_CONNECTIONS=50
# =======================
# Celery Worker 配置
# =======================
CELERY_BROKER_URL=redis://localhost:6379/0
CELERY_RESULT_BACKEND=redis://localhost:6379/1
CELERY_WORKER_CONCURRENCY=4
CELERY_WORKER_MAX_TASKS_PER_CHILD=1000
# =======================
# MinIO 对象存储配置
# =======================
MINIO_ENDPOINT=localhost:9000
MINIO_ACCESS_KEY=CHANGE_ME
MINIO_SECRET_KEY=CHANGE_ME
MINIO_BUCKET=xiaoxia-assets
MINIO_SECURE=false
MINIO_PUBLIC_URL=http://localhost:9000
# =======================
# 日志配置
# =======================
LOG_LEVEL=INFO # DEBUG / INFO / WARNING / ERROR / CRITICAL
LOG_FORMAT=json # json / text
LOG_FILE=/var/log/xiaoxia-saas/app.log
# =======================
# CORS 配置
# =======================
CORS_ORIGINS=http://localhost:3000,http://localhost:8000
CORS_ALLOW_CREDENTIALS=true
# =======================
# 文件上传限制
# =======================
MAX_UPLOAD_SIZE_MB=1000
ALLOWED_FILE_TYPES=video/mp4,video/quicktime,video/x-msvideo,audio/mpeg,audio/wav,image/jpeg,image/png,image/gif
# =======================
# 安全配置
# =======================
SECRET_KEY=change-me-in-production-to-a-random-string-at-least-32-chars
ACCESS_TOKEN_EXPIRE_MINUTES=60
REFRESH_TOKEN_EXPIRE_DAYS=7
# =======================
# 监控与追踪(可选)
# =======================
# SENTRY_DSN=
# PROMETHEUS_PORT=9090
+85
View File
@@ -0,0 +1,85 @@
# =======================
# Staging 环境配置
# =======================
APP_ENV=staging
APP_NAME=xiaoxia-saas
APP_VERSION=0.1.0
DEBUG=true
# =======================
# API 服务配置
# =======================
API_HOST=0.0.0.0
API_PORT=8000
API_PREFIX=/api/v1
# =======================
# Web 前端配置
# =======================
WEB_PORT=3000
WEB_URL=http://47.98.113.167:3001
# =======================
# 数据库配置
# =======================
DATABASE_URL=postgresql+psycopg://postgres:postgres@postgres:5432/xiaoxia_saas_staging
DATABASE_POOL_SIZE=20
DATABASE_MAX_OVERFLOW=40
DATABASE_POOL_TIMEOUT=30
DATABASE_POOL_RECYCLE=3600
# =======================
# Redis 配置
# =======================
REDIS_URL=redis://redis:6379/1
REDIS_MAX_CONNECTIONS=50
# =======================
# Celery Worker 配置
# =======================
CELERY_BROKER_URL=redis://redis:6379/1
CELERY_RESULT_BACKEND=redis://redis:6379/2
CELERY_WORKER_CONCURRENCY=4
CELERY_WORKER_MAX_TASKS_PER_CHILD=1000
# =======================
# MinIO 对象存储配置
# =======================
MINIO_ENDPOINT=47.98.113.167:9000
MINIO_ACCESS_KEY=CHANGE_ME_STAGING
MINIO_SECRET_KEY=CHANGE_ME_STAGING
MINIO_BUCKET=xiaoxia-assets
MINIO_SECURE=false
MINIO_PUBLIC_URL=http://47.98.113.167:9000
# =======================
# 日志配置
# =======================
LOG_LEVEL=DEBUG
LOG_FORMAT=json
LOG_FILE=/var/log/xiaoxia-saas/staging.log
# =======================
# CORS 配置
# =======================
CORS_ORIGINS=http://47.98.113.167:3001,http://47.98.113.167:8001
CORS_ALLOW_CREDENTIALS=true
# =======================
# 文件上传限制
# =======================
MAX_UPLOAD_SIZE_MB=1000
ALLOWED_FILE_TYPES=video/mp4,video/quicktime,video/x-msvideo,audio/mpeg,audio/wav,image/jpeg,image/png,image/gif
# =======================
# 安全配置
# =======================
SECRET_KEY=staging-secret-key-not-for-production
ACCESS_TOKEN_EXPIRE_MINUTES=60
REFRESH_TOKEN_EXPIRE_DAYS=7
# =======================
# 监控与追踪(可选)
# =======================
# SENTRY_DSN=
# PROMETHEUS_PORT=9090
+4 -1
View File
@@ -17,8 +17,11 @@ ruff_cache/
# Env / secrets
.env
.env.*
.env.local
.env.development
.env.production # 生产环境配置不提交(包含敏感信息)
!.env.example
!.env.staging # staging 配置可以提交
# OS / editor
.DS_Store
+120 -6
View File
@@ -1,11 +1,125 @@
from pydantic import BaseModel
from pydantic_settings import BaseSettings, SettingsConfigDict
from typing import Optional
import os
class AppSettings(BaseModel):
app_name: str = "xiaoxia-saas-api"
app_env: str = "development"
api_prefix: str = "/api"
class AppSettings(BaseSettings):
"""应用配置"""
# 基础配置
app_name: str = "xiaoxia-saas"
app_env: str = "development" # development / staging / production
app_version: str = "0.1.0"
debug: bool = True
# API 配置
api_host: str = "0.0.0.0"
api_port: int = 8000
api_prefix: str = "/api/v1"
# 数据库配置
database_url: str = "postgresql+psycopg://postgres:postgres@localhost:5432/xiaoxia_saas"
database_pool_size: int = 20
database_max_overflow: int = 40
database_pool_timeout: int = 30
database_pool_recycle: int = 3600
# Redis 配置
redis_url: str = "redis://localhost:6379/0"
redis_max_connections: int = 50
# Celery 配置
celery_broker_url: str = "redis://localhost:6379/0"
celery_result_backend: str = "redis://localhost:6379/1"
celery_worker_concurrency: int = 4
celery_worker_max_tasks_per_child: int = 1000
# MinIO 配置
minio_endpoint: str = "localhost:9000"
minio_access_key: str = "admin"
minio_secret_key: str = "xiaoxia2026"
minio_bucket: str = "xiaoxia-assets"
minio_secure: bool = False
minio_public_url: str = "http://localhost:9000"
# 日志配置
log_level: str = "INFO"
log_format: str = "json" # json / text
log_file: Optional[str] = None
# CORS 配置
cors_origins: str = "http://localhost:3000,http://localhost:8000"
cors_allow_credentials: bool = True
# 文件上传限制
max_upload_size_mb: int = 1000
allowed_file_types: str = "video/mp4,video/quicktime,video/x-msvideo,audio/mpeg,audio/wav,image/jpeg,image/png,image/gif"
# 安全配置
secret_key: str = "change-me-in-production"
access_token_expire_minutes: int = 60
refresh_token_expire_days: int = 7
# 监控配置(可选)
sentry_dsn: Optional[str] = None
prometheus_port: Optional[int] = None
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
extra="ignore",
)
@property
def cors_origins_list(self) -> list[str]:
"""解析 CORS origins 为列表"""
return [origin.strip() for origin in self.cors_origins.split(",")]
@property
def allowed_file_types_list(self) -> list[str]:
"""解析允许的文件类型为列表"""
return [ft.strip() for ft in self.allowed_file_types.split(",")]
@property
def is_production(self) -> bool:
"""是否为生产环境"""
return self.app_env == "production"
@property
def is_staging(self) -> bool:
"""是否为 staging 环境"""
return self.app_env == "staging"
@property
def is_development(self) -> bool:
"""是否为开发环境"""
return self.app_env == "development"
# 全局配置实例
_settings: Optional[AppSettings] = None
def get_settings() -> AppSettings:
return AppSettings()
"""获取配置实例(单例模式)"""
global _settings
if _settings is None:
# 根据环境加载不同的 .env 文件
env = os.getenv("APP_ENV", "development")
env_file = f".env.{env}" if env != "development" else ".env"
# 如果环境特定的配置文件存在,则使用它
if os.path.exists(env_file):
_settings = AppSettings(_env_file=env_file)
else:
_settings = AppSettings()
return _settings
def reload_settings():
"""重新加载配置(用于测试)"""
global _settings
_settings = None
return get_settings()
+13 -16
View File
@@ -3,27 +3,24 @@ from minio import Minio
from minio.error import S3Error
from typing import BinaryIO
import os
from app.core.config import get_settings
class MinIOService:
"""MinIO storage service."""
def __init__(
self,
endpoint: str = "47.98.113.167:9000",
access_key: str = "admin",
secret_key: str = "xiaoxia2026",
bucket_name: str = "xiaoxia-assets",
secure: bool = False,
):
"""Initialize MinIO client."""
def __init__(self):
"""Initialize MinIO client from settings."""
settings = get_settings()
self.client = Minio(
endpoint,
access_key=access_key,
secret_key=secret_key,
secure=secure,
settings.minio_endpoint,
access_key=settings.minio_access_key,
secret_key=settings.minio_secret_key,
secure=settings.minio_secure,
)
self.bucket_name = bucket_name
self.bucket_name = settings.minio_bucket
self.public_url = settings.minio_public_url
self._ensure_bucket()
def _ensure_bucket(self):
@@ -81,14 +78,14 @@ class MinIOService:
)
# Return public URL
return f"http://47.98.113.167:9000/{self.bucket_name}/{storage_key}"
return f"{self.public_url}/{self.bucket_name}/{storage_key}"
except S3Error as e:
raise Exception(f"Failed to upload file: {e}")
def get_url(self, storage_key: str) -> str:
"""Get public URL for a storage key."""
return f"http://47.98.113.167:9000/{self.bucket_name}/{storage_key}"
return f"{self.public_url}/{self.bucket_name}/{storage_key}"
def delete_file(self, storage_key: str):
"""Delete file from MinIO."""
+2 -2
View File
@@ -52,8 +52,8 @@ def create_app() -> FastAPI:
# CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # TODO: Configure for production
allow_credentials=True,
allow_origins=settings.cors_origins_list,
allow_credentials=settings.cors_allow_credentials,
allow_methods=["*"],
allow_headers=["*"],
)
+247
View File
@@ -0,0 +1,247 @@
# 环境配置指南
## 环境类型
小虾 SaaS 支持三种环境:
- **Development(开发环境)**:本地开发使用
- **Staging(测试环境)**:用于测试和预发布
- **Production(生产环境)**:正式生产环境
---
## 配置文件
### 1. `.env.example` - 配置模板
包含所有可配置项的示例,用于参考和初始化。
### 2. `.env` - 开发环境配置(本地)
本地开发时使用,不提交到 Git。
### 3. `.env.staging` - Staging 环境配置
测试环境配置,可以提交到 Git。
### 4. `.env.production` - 生产环境配置
生产环境配置,**敏感信息需要单独管理,不要提交到 Git**。
---
## 使用方法
### 方法 1:使用环境变量指定环境
```bash
# 开发环境(默认)
python -m uvicorn apps.api.main:app --reload
# Staging 环境
export APP_ENV=staging
python -m uvicorn apps.api.main:app --host 0.0.0.0 --port 8000
# 生产环境
export APP_ENV=production
python -m uvicorn apps.api.main:app --host 0.0.0.0 --port 8000
```
### 方法 2:直接指定配置文件
```bash
# 使用 .env.staging
cp .env.staging .env
python -m uvicorn apps.api.main:app
# 使用 .env.production
cp .env.production .env
python -m uvicorn apps.api.main:app
```
---
## 配置项说明
### 基础配置
- `APP_ENV`: 环境类型(development / staging / production
- `APP_NAME`: 应用名称
- `DEBUG`: 是否启用调试模式
### API 配置
- `API_HOST`: API 监听地址
- `API_PORT`: API 端口
- `API_PREFIX`: API 路由前缀(如 /api/v1
### 数据库配置
- `DATABASE_URL`: PostgreSQL 连接字符串
- `DATABASE_POOL_SIZE`: 连接池大小
- `DATABASE_MAX_OVERFLOW`: 最大溢出连接数
- `DATABASE_POOL_TIMEOUT`: 连接池超时时间(秒)
- `DATABASE_POOL_RECYCLE`: 连接回收时间(秒)
### Redis 配置
- `REDIS_URL`: Redis 连接字符串
- `REDIS_MAX_CONNECTIONS`: 最大连接数
### Celery 配置
- `CELERY_BROKER_URL`: Celery broker URL
- `CELERY_RESULT_BACKEND`: Celery result backend URL
- `CELERY_WORKER_CONCURRENCY`: Worker 并发数
- `CELERY_WORKER_MAX_TASKS_PER_CHILD`: 每个 worker 最大任务数
### MinIO 配置
- `MINIO_ENDPOINT`: MinIO 服务地址
- `MINIO_ACCESS_KEY`: 访问密钥
- `MINIO_SECRET_KEY`: 私密密钥
- `MINIO_BUCKET`: 存储桶名称
- `MINIO_SECURE`: 是否使用 HTTPS
- `MINIO_PUBLIC_URL`: 公开访问 URL
### 日志配置
- `LOG_LEVEL`: 日志级别(DEBUG / INFO / WARNING / ERROR / CRITICAL
- `LOG_FORMAT`: 日志格式(json / text
- `LOG_FILE`: 日志文件路径
### CORS 配置
- `CORS_ORIGINS`: 允许的跨域来源(逗号分隔)
- `CORS_ALLOW_CREDENTIALS`: 是否允许携带凭证
### 安全配置
- `SECRET_KEY`: 应用密钥(用于 JWT 签名等)
- `ACCESS_TOKEN_EXPIRE_MINUTES`: 访问令牌过期时间
- `REFRESH_TOKEN_EXPIRE_DAYS`: 刷新令牌过期天数
---
## 生产环境最佳实践
### 1. 不要硬编码敏感信息
❌ 不要这样:
```python
DATABASE_URL = "postgresql://user:password@localhost/db"
```
✅ 应该这样:
```python
from app.core.config import get_settings
settings = get_settings()
database_url = settings.database_url
```
### 2. 使用环境变量覆盖
生产环境的敏感配置应该通过环境变量注入:
```bash
export DATABASE_URL="postgresql://user:secure_password@prod-db/db"
export SECRET_KEY="very-long-random-string"
export MINIO_SECRET_KEY="another-secure-key"
```
### 3. 使用密钥管理工具
推荐使用:
- Docker Secrets
- Kubernetes Secrets
- AWS Secrets Manager
- HashiCorp Vault
### 4. 生产环境配置检查清单
- [ ] `DEBUG=false`
- [ ] `SECRET_KEY` 使用随机字符串(至少 32 字符)
- [ ] 数据库使用强密码
- [ ] MinIO 使用强密码
- [ ] `CORS_ORIGINS` 只包含信任的域名
- [ ] 日志级别设置为 `INFO``WARNING`
- [ ] 数据库连接池配置合理
- [ ] 启用 HTTPS`MINIO_SECURE=true`
---
## Docker 部署配置
### docker-compose.yml 中使用环境文件
```yaml
services:
api:
image: xiaoxia-saas-api:latest
env_file:
- .env.production
environment:
- DATABASE_URL=${DATABASE_URL} # 从环境变量覆盖
```
### Gitea Actions 部署脚本
`.gitea/workflows/deploy.yml` 中:
```yaml
- name: Deploy to production
run: |
# 复制环境配置
cp .env.production /var/lib/xiaoxia-saas-production/.env
# 启动服务
cd /var/lib/xiaoxia-saas-production
docker-compose up -d
```
---
## 配置验证
### 查看当前配置
```python
from app.core.config import get_settings
settings = get_settings()
print(f"Environment: {settings.app_env}")
print(f"Debug mode: {settings.debug}")
print(f"Database: {settings.database_url}")
print(f"Is production: {settings.is_production}")
```
### 配置测试脚本
```bash
# 测试开发环境配置
python -c "from app.core.config import get_settings; s=get_settings(); print(s.app_env)"
# 测试 staging 环境配置
APP_ENV=staging python -c "from app.core.config import get_settings; s=get_settings(); print(s.app_env)"
# 测试生产环境配置
APP_ENV=production python -c "from app.core.config import get_settings; s=get_settings(); print(s.app_env)"
```
---
## 常见问题
### Q: 为什么我的配置没有生效?
A: 检查:
1. 环境变量 `APP_ENV` 是否正确设置
2. 配置文件 `.env.{环境}` 是否存在
3. 环境变量名是否正确(大小写不敏感)
4. 是否重启了服务
### Q: 如何在 Docker 中使用环境配置?
A: 使用 `env_file``environment` 指定配置:
```yaml
services:
api:
env_file: .env.production
```
### Q: 生产环境如何保护敏感配置?
A:
1. 不要提交 `.env.production` 到 Git
2. 使用 Docker Secrets 或 Kubernetes Secrets
3. 通过 CI/CD 注入环境变量
4. 使用密钥管理工具(Vault, AWS Secrets Manager 等)
---
## 相关文档
- [部署文档](DEPLOYMENT.md)
- [API 文档](API.md)
- [开发指南](DEVELOPMENT.md)
+1
View File
@@ -3,6 +3,7 @@
fastapi
uvicorn
pydantic
pydantic-settings
celery
redis
sqlalchemy