From 9d50a2bae858227a82f5ccedde95007fc8d38475 Mon Sep 17 00:00:00 2001 From: aaron <> Date: Sun, 28 Dec 2025 10:28:18 +0800 Subject: [PATCH] update --- .dockerignore | 87 +++++++++++++ .env.docker | 17 +++ Dockerfile.backend | 40 ++++++ Dockerfile.frontend | 37 ++++++ README.md | 196 ++++++++++++++++++++++++++++-- docker-compose.external-redis.yml | 60 +++++++++ docker-compose.prod.yml | 139 +++++++++++++++++++++ docker-compose.yml | 86 +++++++++++++ nginx/nginx.conf | 119 ++++++++++++++++++ 9 files changed, 771 insertions(+), 10 deletions(-) create mode 100644 .dockerignore create mode 100644 .env.docker create mode 100644 Dockerfile.backend create mode 100644 Dockerfile.frontend create mode 100644 docker-compose.external-redis.yml create mode 100644 docker-compose.prod.yml create mode 100644 docker-compose.yml create mode 100644 nginx/nginx.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..fffeea9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,87 @@ +# 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 environments +venv/ +env/ +ENV/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Git +.git/ +.gitignore + +# Docker +Dockerfile* +docker-compose*.yml +.dockerignore + +# Logs +logs/ +*.log + +# Environment files +.env +.env.local +.env.development +.env.test +.env.production + +# Cache directories +.cache/ +.pytest_cache/ + +# Coverage reports +htmlcov/ +.coverage +.coverage.* +coverage.xml + +# Documentation +docs/_build/ + +# Node modules (if any) +node_modules/ + +# Database files +*.db +*.sqlite +*.sqlite3 + +# Temporary files +tmp/ +temp/ + +# Test files +.tox/ +.coverage +.pytest_cache/ \ No newline at end of file diff --git a/.env.docker b/.env.docker new file mode 100644 index 0000000..51c3c80 --- /dev/null +++ b/.env.docker @@ -0,0 +1,17 @@ +# Tushare API配置 +TUSHARE_TOKEN=your_tushare_token_here + +# Redis配置 +REDIS_HOST=redis +REDIS_PORT=6379 +REDIS_DB=0 + +# API配置 +API_HOST=0.0.0.0 +API_PORT=8000 + +# 数据库配置(可选) +# DATABASE_URL=sqlite:///./stockagent.db + +# 日志级别 +# LOG_LEVEL=INFO \ No newline at end of file diff --git a/Dockerfile.backend b/Dockerfile.backend new file mode 100644 index 0000000..202fa03 --- /dev/null +++ b/Dockerfile.backend @@ -0,0 +1,40 @@ +# 使用官方Python 3.9运行时作为基础镜像 +FROM python:3.9-slim + +# 设置工作目录 +WORKDIR /app + +# 设置环境变量 +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + PYTHONPATH=/app + +# 安装系统依赖 +RUN apt-get update && apt-get install -y \ + gcc \ + g++ \ + && rm -rf /var/lib/apt/lists/* + +# 复制requirements文件 +COPY requirements.txt . + +# 安装Python依赖 +RUN pip install --no-cache-dir -r requirements.txt + +# 复制项目文件 +COPY . . + +# 创建非root用户 +RUN useradd --create-home --shell /bin/bash app \ + && chown -R app:app /app +USER app + +# 暴露端口 +EXPOSE 8000 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:8000/ || exit 1 + +# 启动命令 +CMD ["python", "main.py"] \ No newline at end of file diff --git a/Dockerfile.frontend b/Dockerfile.frontend new file mode 100644 index 0000000..9e0e1e8 --- /dev/null +++ b/Dockerfile.frontend @@ -0,0 +1,37 @@ +# 使用官方Python 3.9运行时作为基础镜像 +FROM python:3.9-slim + +# 设置工作目录 +WORKDIR /app + +# 设置环境变量 +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + FLASK_APP=app.py \ + FLASK_ENV=production + +# 安装系统依赖 +RUN apt-get update && apt-get install -y \ + curl \ + && rm -rf /var/lib/apt/lists/* + +# 安装Flask和相关依赖 +RUN pip install --no-cache-dir flask requests + +# 复制web目录 +COPY web/ . + +# 创建非root用户 +RUN useradd --create-home --shell /bin/bash app \ + && chown -R app:app /app +USER app + +# 暴露端口 +EXPOSE 5001 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:5001/ || exit 1 + +# 启动命令 +CMD ["python", "app.py"] \ No newline at end of file diff --git a/README.md b/README.md index fa522d8..136054f 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,74 @@ ## 快速开始 -### 1. 环境配置 +### 方法一:Docker部署 (推荐) + +使用Docker Compose可以一键部署整个应用,包括前端、后端和Redis缓存。 + +#### 1. 环境准备 +```bash +# 确保已安装Docker和Docker Compose +docker --version +docker-compose --version + +# 克隆项目 +git clone +cd StockAgent +``` + +#### 2. 配置环境变量 +```bash +# 复制环境变量模板 +cp .env.docker .env + +# 编辑环境变量文件,设置你的tushare token +vim .env # 或使用其他编辑器 +``` + +在 `.env` 文件中设置: +```bash +TUSHARE_TOKEN=your_tushare_token_here +``` + +#### 3. 启动服务 +```bash +# 一键启动所有服务 +docker-compose up -d + +# 查看服务状态 +docker-compose ps + +# 查看日志 +docker-compose logs -f +``` + +#### 4. 访问应用 +- **Web界面**: http://localhost:5001 +- **API文档**: http://localhost:8000/docs +- **Redis管理**: localhost:6379 + +#### 5. 管理命令 +```bash +# 停止服务 +docker-compose down + +# 重启服务 +docker-compose restart + +# 更新应用 +docker-compose down +docker-compose build --no-cache +docker-compose up -d + +# 清理数据 +docker-compose down -v # 警告:会删除Redis数据 +``` + +### 方法二:本地开发部署 + +适合开发和调试环境。 + +#### 1. 环境配置 ```bash # 创建虚拟环境 @@ -39,14 +106,14 @@ cp .env.example .env # 编辑 .env 文件,设置你的 tushare token ``` -### 2. 配置 tushare token +#### 2. 配置 tushare token 在 `.env` 文件中设置: ``` TUSHARE_TOKEN=your_tushare_token_here ``` -### 3. 启动服务 +#### 3. 启动服务 ```bash # 启动后端 API 服务 @@ -56,7 +123,7 @@ python main.py cd web && python app.py ``` -### 4. 访问应用 +#### 4. 访问应用 - **Web界面**: http://localhost:5001 (主要入口) - **API文档**: http://localhost:8000/docs (后端API) @@ -208,11 +275,120 @@ print(f"综合评分: {comprehensive_score}") - **止损建议**: 基于ATR、布林带等技术指标动态计算 - **仓位管理**: 根据风险评级提供合理的仓位建议 -### ⚡ 性能优化 -- **缓存机制**: Redis缓存减少重复计算 -- **批量处理**: 限制处理数量避免超时 -- **防重复提交**: 前端防重复点击,后端缓存复用 +## 部署说明 -## 许可证 +### 🐳 Docker部署架构 -MIT License \ No newline at end of file +``` +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ +│ Frontend │ │ Backend │ │ Redis Cache │ +│ (Flask) │────│ (FastAPI) │────│ (Redis) │ +│ Port: 5001 │ │ Port: 8000 │ │ Port: 6379 │ +└─────────────────┘ └─────────────────┘ └─────────────────┘ + │ │ │ + └────────────────────────┼────────────────────────┘ + │ + Docker Network: stockagent-network +``` + +### 🔧 生产环境优化 + +对于生产环境部署,可以使用以下优化配置: + +#### 1. 创建生产环境Docker Compose文件 +```bash +# 创建生产环境配置 +cp docker-compose.yml docker-compose.prod.yml +``` + +#### 2. 生产环境配置优化 +- 使用nginx反向代理 +- 添加SSL证书支持 +- 配置日志轮转 +- 设置资源限制 +- 添加监控和告警 + +### 🔍 故障排除 + +#### 常见问题及解决方案 + +**1. Tushare Token配置问题** +```bash +# 检查环境变量 +docker-compose exec backend env | grep TUSHARE_TOKEN + +# 如果未设置,停止服务并重新配置 +docker-compose down +vim .env # 设置正确的token +docker-compose up -d +``` + +**2. Redis连接问题** +```bash +# 检查Redis服务状态 +docker-compose exec redis redis-cli ping + +# 查看Redis日志 +docker-compose logs redis +``` + +**3. 服务启动失败** +```bash +# 查看详细日志 +docker-compose logs backend +docker-compose logs frontend + +# 重新构建镜像 +docker-compose build --no-cache +docker-compose up -d +``` + +**4. 端口冲突** +```bash +# 检查端口占用 +netstat -tlnp | grep :5001 +netstat -tlnp | grep :8000 + +# 修改docker-compose.yml中的端口映射 +``` + +### 📊 监控和维护 + +#### 1. 服务监控 +```bash +# 查看服务状态 +docker-compose ps + +# 查看资源使用情况 +docker stats $(docker-compose ps -q) + +# 查看实时日志 +docker-compose logs -f --tail=100 +``` + +#### 2. 数据备份 +```bash +# 备份Redis数据 +docker-compose exec redis redis-cli BGSAVE +docker cp stockagent-redis:/data/dump.rdb ./backup/redis-$(date +%Y%m%d).rdb + +# 备份配置文件 +tar -czf backup/config-$(date +%Y%m%d).tar.gz config/ .env +``` + +#### 3. 更新和维护 +```bash +# 拉取最新代码 +git pull + +# 停止服务 +docker-compose down + +# 重新构建并启动 +docker-compose build --no-cache +docker-compose up -d + +# 验证服务正常 +curl http://localhost:5001 +curl http://localhost:8000/docs +``` \ No newline at end of file diff --git a/docker-compose.external-redis.yml b/docker-compose.external-redis.yml new file mode 100644 index 0000000..178f3c3 --- /dev/null +++ b/docker-compose.external-redis.yml @@ -0,0 +1,60 @@ +version: '3.8' + +services: + # 后端API服务 - 使用外部Redis + backend: + build: + context: . + dockerfile: Dockerfile.backend + container_name: stockagent-backend + restart: unless-stopped + ports: + - "8000:8000" + environment: + - TUSHARE_TOKEN=${TUSHARE_TOKEN} + - REDIS_HOST=host.docker.internal # 连接到宿主机的Redis + - REDIS_PORT=6379 + - REDIS_DB=0 # 可以使用不同的数据库编号避免冲突 + - API_HOST=0.0.0.0 + - API_PORT=8000 + volumes: + - ./logs:/app/logs + - ./config:/app/config + networks: + - stockagent-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + extra_hosts: + - "host.docker.internal:host-gateway" + + # 前端Web服务 + frontend: + build: + context: . + dockerfile: Dockerfile.frontend + container_name: stockagent-frontend + restart: unless-stopped + ports: + - "5001:5001" + environment: + - API_BASE_URL=http://backend:8000/api + depends_on: + - backend + networks: + - stockagent-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5001/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + +# 网络配置 +networks: + stockagent-network: + driver: bridge + name: stockagent-network \ No newline at end of file diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..ee2bcc6 --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,139 @@ +version: '3.8' + +services: + # Nginx反向代理 + nginx: + image: nginx:alpine + container_name: stockagent-nginx + restart: unless-stopped + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - ./nginx/ssl:/etc/nginx/ssl:ro + - ./logs/nginx:/var/log/nginx + depends_on: + - frontend + - backend + networks: + - stockagent-network + + # Redis缓存服务 + redis: + image: redis:7-alpine + container_name: stockagent-redis + restart: unless-stopped + ports: + - "127.0.0.1:6379:6379" # 只绑定到本地 + volumes: + - redis_data:/data + - ./redis/redis.conf:/usr/local/etc/redis/redis.conf:ro + command: redis-server /usr/local/etc/redis/redis.conf + networks: + - stockagent-network + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 3s + retries: 3 + deploy: + resources: + limits: + memory: 512M + reservations: + memory: 256M + + # 后端API服务 + backend: + build: + context: . + dockerfile: Dockerfile.backend + container_name: stockagent-backend + restart: unless-stopped + expose: + - "8000" + environment: + - TUSHARE_TOKEN=${TUSHARE_TOKEN} + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_DB=0 + - API_HOST=0.0.0.0 + - API_PORT=8000 + - LOG_LEVEL=INFO + volumes: + - ./logs:/app/logs + - ./config:/app/config + depends_on: + redis: + condition: service_healthy + networks: + - stockagent-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + deploy: + resources: + limits: + memory: 1G + cpus: '0.5' + reservations: + memory: 512M + cpus: '0.25' + + # 前端Web服务 + frontend: + build: + context: . + dockerfile: Dockerfile.frontend + container_name: stockagent-frontend + restart: unless-stopped + expose: + - "5001" + environment: + - API_BASE_URL=http://backend:8000/api + - FLASK_ENV=production + depends_on: + backend: + condition: service_healthy + networks: + - stockagent-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5001/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + deploy: + resources: + limits: + memory: 256M + cpus: '0.25' + reservations: + memory: 128M + cpus: '0.1' + + # 日志收集器(可选) + # logrotate: + # image: tutum/logrotate + # container_name: stockagent-logrotate + # restart: unless-stopped + # volumes: + # - ./logs:/logs + # environment: + # - LOGS_DIRECTORIES=/logs + +# 网络配置 +networks: + stockagent-network: + driver: bridge + name: stockagent-network + +# 数据卷配置 +volumes: + redis_data: + driver: local + name: stockagent-redis-data \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..fc18376 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,86 @@ +version: '3.8' + +services: + # Redis缓存服务 + redis: + image: redis:7-alpine + container_name: stockagent-redis + restart: unless-stopped + ports: + - "6379:6379" + volumes: + - redis_data:/data + command: redis-server --appendonly yes + networks: + - stockagent-network + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 3s + retries: 3 + + # 后端API服务 + backend: + build: + context: . + dockerfile: Dockerfile.backend + container_name: stockagent-backend + restart: unless-stopped + ports: + - "8000:8000" + environment: + - TUSHARE_TOKEN=${TUSHARE_TOKEN} + - REDIS_HOST=redis + - REDIS_PORT=6379 + - REDIS_DB=0 + - API_HOST=0.0.0.0 + - API_PORT=8000 + volumes: + - ./logs:/app/logs + - ./config:/app/config + depends_on: + redis: + condition: service_healthy + networks: + - stockagent-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + # 前端Web服务 + frontend: + build: + context: . + dockerfile: Dockerfile.frontend + container_name: stockagent-frontend + restart: unless-stopped + ports: + - "5001:5001" + environment: + - API_BASE_URL=http://backend:8000/api + depends_on: + backend: + condition: service_healthy + networks: + - stockagent-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:5001/"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + +# 网络配置 +networks: + stockagent-network: + driver: bridge + name: stockagent-network + +# 数据卷配置 +volumes: + redis_data: + driver: local + name: stockagent-redis-data \ No newline at end of file diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..196a8e8 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,119 @@ +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + # Gzip压缩 + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types + text/plain + text/css + text/xml + text/javascript + application/javascript + application/xml+rss + application/json; + + # 限制请求速率 + limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; + limit_req_zone $binary_remote_addr zone=web:10m rate=30r/s; + + # 上游服务器配置 + upstream backend { + server frontend:5001; + } + + upstream api { + server backend:8000; + } + + # HTTP服务器配置 + server { + listen 80; + server_name localhost; + + # 静态文件缓存 + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + add_header X-Content-Type-Options nosniff; + } + + # API路由 + location /api/ { + limit_req zone=api burst=20 nodelay; + + proxy_pass http://api; + 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; + + # 超时设置 + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 300s; + } + + # Web应用路由 + location / { + limit_req zone=web burst=50 nodelay; + + proxy_pass http://backend; + 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; + + # 超时设置 + proxy_connect_timeout 30s; + proxy_send_timeout 30s; + proxy_read_timeout 30s; + } + + # 健康检查 + location /health { + access_log off; + return 200 "healthy\n"; + add_header Content-Type text/plain; + } + } + + # HTTPS服务器配置(可选) + # server { + # listen 443 ssl http2; + # server_name your-domain.com; + # + # ssl_certificate /etc/nginx/ssl/cert.pem; + # ssl_certificate_key /etc/nginx/ssl/key.pem; + # ssl_session_timeout 1d; + # ssl_session_cache shared:SSL:50m; + # ssl_protocols TLSv1.2 TLSv1.3; + # ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; + # ssl_prefer_server_ciphers off; + # + # # 其他配置同HTTP服务器... + # } +} \ No newline at end of file