diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..57de429f4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,68 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual Environment +venv/ +ENV/ +env/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Environment +.env +.env.local +.env.*.local + +# Database +*.db +*.sqlite3 + +# Logs +logs/ +*.log + +# Testing +.pytest_cache/ +.coverage +htmlcov/ +.tox/ + +# Docker +.dockerignore + +# OS +.DS_Store +Thumbs.db + +# Temporary +tmp/ +temp/ +*.tmp + +# Backup +*.bak +*.backup diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..955556ee4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +# 小虾 SaaS - Python 后端 +FROM python:3.12-slim + +# 设置工作目录 +WORKDIR /app + +# 安装系统依赖 +RUN apt-get update && apt-get install -y \ + gcc \ + postgresql-client \ + && rm -rf /var/lib/apt/lists/* + +# 复制依赖文件 +COPY requirements.txt . + +# 安装 Python 依赖 +RUN pip install --no-cache-dir -r requirements.txt + +# 复制应用代码 +COPY packages/ ./packages/ +COPY apps/ ./apps/ +COPY migrations/ ./migrations/ + +# 暴露端口 +EXPOSE 8000 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ + CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1 + +# 启动命令 +CMD ["uvicorn", "apps.api.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..1b414d07a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,73 @@ +version: '3.8' + +services: + # PostgreSQL 数据库 + postgres: + image: postgres:16-alpine + container_name: xiaoxia-postgres + environment: + POSTGRES_DB: xiaoxia_saas + POSTGRES_USER: xiaoxia_user + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeme} + volumes: + - postgres_data:/var/lib/postgresql/data + - ./migrations:/docker-entrypoint-initdb.d:ro + ports: + - "5432:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U xiaoxia_user"] + interval: 10s + timeout: 5s + retries: 5 + restart: unless-stopped + + # Redis 缓存 + redis: + image: redis:7-alpine + container_name: xiaoxia-redis + ports: + - "6379:6379" + volumes: + - redis_data:/data + command: redis-server --appendonly yes + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 3s + retries: 5 + restart: unless-stopped + + # 小虾 SaaS API + api: + build: . + container_name: xiaoxia-api + environment: + DATABASE_URL: postgresql://xiaoxia_user:${POSTGRES_PASSWORD:-changeme}@postgres:5432/xiaoxia_saas + REDIS_URL: redis://redis:6379/0 + JWT_SECRET_KEY: ${JWT_SECRET_KEY:-your-secret-key-change-in-production} + SMTP_HOST: ${SMTP_HOST:-smtp.gmail.com} + SMTP_PORT: ${SMTP_PORT:-587} + SMTP_USER: ${SMTP_USER} + SMTP_PASSWORD: ${SMTP_PASSWORD} + BASE_URL: ${BASE_URL:-http://localhost:3000} + ENVIRONMENT: ${ENVIRONMENT:-production} + ports: + - "8000:8000" + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + volumes: + - ./logs:/app/logs + restart: unless-stopped + +volumes: + postgres_data: + driver: local + redis_data: + driver: local + +networks: + default: + name: xiaoxia-network diff --git a/docs/DOCKER-DEPLOYMENT.md b/docs/DOCKER-DEPLOYMENT.md new file mode 100644 index 000000000..dfb6e6878 --- /dev/null +++ b/docs/DOCKER-DEPLOYMENT.md @@ -0,0 +1,276 @@ +# 小虾 SaaS Docker 部署指南 + +## 🐳 快速启动 + +### 1. 准备环境变量 + +```bash +# 创建 .env 文件 +cat > .env << EOF +# PostgreSQL +POSTGRES_PASSWORD=your_secure_password + +# JWT +JWT_SECRET_KEY=$(openssl rand -base64 32) + +# Email (Gmail example) +SMTP_HOST=smtp.gmail.com +SMTP_PORT=587 +SMTP_USER=your-email@gmail.com +SMTP_PASSWORD=your-app-password + +# App +BASE_URL=https://yourdomain.com +ENVIRONMENT=production +EOF +``` + +### 2. 启动所有服务 + +```bash +# 启动(首次会自动构建镜像) +docker-compose up -d + +# 查看日志 +docker-compose logs -f api + +# 查看状态 +docker-compose ps +``` + +### 3. 验证部署 + +```bash +# 健康检查 +curl http://localhost:8000/health + +# API 文档 +open http://localhost:8000/docs +``` + +--- + +## 🔧 常用命令 + +### 服务管理 + +```bash +# 启动所有服务 +docker-compose up -d + +# 停止所有服务 +docker-compose down + +# 重启 API +docker-compose restart api + +# 查看日志 +docker-compose logs -f [service_name] + +# 进入容器 +docker-compose exec api bash +docker-compose exec postgres psql -U xiaoxia_user xiaoxia_saas +``` + +### 数据库操作 + +```bash +# 备份数据库 +docker-compose exec postgres pg_dump -U xiaoxia_user xiaoxia_saas > backup.sql + +# 恢复数据库 +docker-compose exec -T postgres psql -U xiaoxia_user xiaoxia_saas < backup.sql + +# 查看数据库状态 +docker-compose exec postgres psql -U xiaoxia_user -c "\l" +``` + +### 更新部署 + +```bash +# 拉取最新代码 +git pull + +# 重新构建镜像 +docker-compose build api + +# 重启服务 +docker-compose up -d api +``` + +--- + +## 📦 单独构建镜像 + +```bash +# 构建 +docker build -t xiaoxia-saas:latest . + +# 运行 +docker run -d \ + --name xiaoxia-api \ + -p 8000:8000 \ + --env-file .env \ + xiaoxia-saas:latest + +# 推送到仓库 +docker tag xiaoxia-saas:latest your-registry/xiaoxia-saas:latest +docker push your-registry/xiaoxia-saas:latest +``` + +--- + +## 🚀 生产环境部署 + +### 1. 使用外部数据库 + +修改 `docker-compose.yml`,注释掉 postgres 和 redis 服务,直接使用云数据库: + +```yaml +services: + api: + environment: + DATABASE_URL: postgresql://user:pass@your-rds.amazonaws.com:5432/xiaoxia_saas + REDIS_URL: redis://your-elasticache.amazonaws.com:6379/0 +``` + +### 2. 反向代理(Nginx) + +```nginx +server { + listen 80; + server_name api.yourdomain.com; + + location / { + proxy_pass http://localhost:8000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +### 3. SSL 证书(Let's Encrypt) + +```bash +# 安装 certbot +apt-get install certbot python3-certbot-nginx + +# 获取证书 +certbot --nginx -d api.yourdomain.com +``` + +### 4. 自动重启(systemd) + +创建 `/etc/systemd/system/xiaoxia-api.service`: + +```ini +[Unit] +Description=小虾 SaaS API +Requires=docker.service +After=docker.service + +[Service] +Type=oneshot +RemainAfterExit=yes +WorkingDirectory=/opt/xiaoxia-saas +ExecStart=/usr/bin/docker-compose up -d +ExecStop=/usr/bin/docker-compose down +TimeoutStartSec=0 + +[Install] +WantedBy=multi-user.target +``` + +启用: +```bash +systemctl enable xiaoxia-api +systemctl start xiaoxia-api +``` + +--- + +## 📊 监控和日志 + +### 日志管理 + +```bash +# 实时查看日志 +docker-compose logs -f --tail=100 api + +# 日志轮转(在 docker-compose.yml 中配置) +logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" +``` + +### 资源监控 + +```bash +# 查看资源使用 +docker stats + +# 查看容器详情 +docker inspect xiaoxia-api +``` + +--- + +## 🔒 安全建议 + +1. **修改默认密码** + - PostgreSQL 密码 + - JWT Secret Key + +2. **限制端口暴露** + - 只暴露必要的端口 + - 使用防火墙规则 + +3. **定期备份** + - 数据库自动备份 + - 代码版本控制 + +4. **更新依赖** + - 定期更新 Docker 镜像 + - 更新 Python 依赖包 + +--- + +## 🐛 故障排查 + +### API 启动失败 + +```bash +# 查看详细日志 +docker-compose logs api + +# 检查数据库连接 +docker-compose exec api python -c "import psycopg2; psycopg2.connect('$DATABASE_URL')" +``` + +### 数据库连接失败 + +```bash +# 检查 PostgreSQL 状态 +docker-compose ps postgres + +# 测试连接 +docker-compose exec postgres psql -U xiaoxia_user -c "SELECT 1" +``` + +### 性能问题 + +```bash +# 增加 worker 数量 +CMD ["uvicorn", "apps.api.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"] + +# 启用 Gunicorn(更适合生产) +CMD ["gunicorn", "apps.api.main:app", "--workers", "4", "--worker-class", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:8000"] +``` + +--- + +**支持联系:** xiaoxia@example.com