From 2ab6aafc6f5a83db5f2f6d330bd75c2ec07ce870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E6=9D=B0=20Jie=20Zhao=20=EF=BC=88=E9=9B=84?= =?UTF-8?q?=E7=8B=AE=E6=B1=BD=E8=BD=A6=E7=A7=91=E6=8A=80=EF=BC=89?= <00061074@chery.local> Date: Sun, 2 Nov 2025 23:55:54 +0800 Subject: [PATCH] feat: add Docker support for containerized deployment --- .dockerignore | 64 +++++++++++++ Dockerfile | 48 ++++++++++ Dockerfile.dev | 38 ++++++++ README_DOCKER.md | 213 +++++++++++++++++++++++++++++++++++++++++ docker-compose.dev.yml | 29 ++++++ docker-compose.yml | 32 +++++++ 6 files changed, 424 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 Dockerfile.dev create mode 100644 README_DOCKER.md create mode 100644 docker-compose.dev.yml create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9c87c0c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,64 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +*.egg-info/ +dist/ +build/ +*.egg + +# 虚拟环境 +venv/ +env/ +ENV/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# 日志文件 +*.log +logs/*.log + +# 数据库文件(会通过volume挂载) +data/*.db +data/*.pkl + +# Git +.git/ +.gitignore + +# Docker +Dockerfile +docker-compose.yml +.dockerignore + +# 文档 +*.md +!README.md + +# 测试文件 +test_*.py +*_test.py + +# 临时文件 +*.tmp +*.bak +.DS_Store +Thumbs.db + +# 环境配置(敏感信息) +.env +.env.local + +# 模型文件(会通过volume挂载) +models/*.pkl + +# PDF和其他大文件 +*.pdf + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..bd7286f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# 使用Python 3.11官方镜像作为基础镜像 +FROM python:3.11-slim + +# 设置工作目录 +WORKDIR /app + +# 设置环境变量 +ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + FLASK_APP=web_app.py \ + FLASK_ENV=production + +# 安装系统依赖(用于OCR等功能) +RUN apt-get update && apt-get install -y \ + tesseract-ocr \ + tesseract-ocr-chi-sim \ + tesseract-ocr-eng \ + libgl1-mesa-glx \ + libglib2.0-0 \ + && rm -rf /var/lib/apt/lists/* + +# 复制requirements文件 +COPY requirements.txt . + +# 安装Python依赖(排除GUI相关依赖,Docker中不需要) +RUN pip install --no-cache-dir -r requirements.txt && \ + pip install --no-cache-dir gunicorn + +# 复制应用代码 +COPY . . + +# 创建必要的目录 +RUN mkdir -p templates static/css static/js logs data models + +# 设置权限 +RUN chmod +x start_web.py + +# 暴露端口 +EXPOSE 5000 + +# 健康检查 +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD python -c "import requests; requests.get('http://localhost:5000/health')" || exit 1 + +# 使用gunicorn启动应用(生产环境) +CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "2", "--timeout", "120", "--access-logfile", "-", "--error-logfile", "-", "web_app:app"] + diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 0000000..2a7670a --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# 开发环境Dockerfile +FROM python:3.11-slim + +WORKDIR /app + +ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + FLASK_APP=web_app.py \ + FLASK_ENV=development + +# 安装系统依赖 +RUN apt-get update && apt-get install -y \ + tesseract-ocr \ + tesseract-ocr-chi-sim \ + tesseract-ocr-eng \ + libgl1-mesa-glx \ + libglib2.0-0 \ + && rm -rf /var/lib/apt/lists/* + +# 复制requirements文件 +COPY requirements.txt . + +# 安装Python依赖 +RUN pip install --no-cache-dir -r requirements.txt + +# 复制应用代码 +COPY . . + +# 创建必要的目录 +RUN mkdir -p templates static/css static/js logs data models + +# 暴露端口 +EXPOSE 5000 + +# 开发模式:使用Flask开发服务器 +CMD ["python", "start_web.py"] + diff --git a/README_DOCKER.md b/README_DOCKER.md new file mode 100644 index 0000000..0a97952 --- /dev/null +++ b/README_DOCKER.md @@ -0,0 +1,213 @@ +# Docker 部署指南 + +本文档说明如何使用Docker部署个性化饮食推荐助手Web应用。 + +## 📋 前置要求 + +- Docker Engine 20.10+ +- Docker Compose 2.0+ + +## 🚀 快速开始 + +### 方式一:使用 Docker Compose(推荐) + +#### 生产环境 + +```bash +# 构建并启动容器 +docker-compose up -d + +# 查看日志 +docker-compose logs -f + +# 停止容器 +docker-compose down +``` + +#### 开发环境(支持代码热重载) + +```bash +# 使用开发配置启动 +docker-compose -f docker-compose.dev.yml up -d + +# 查看日志 +docker-compose -f docker-compose.dev.yml logs -f + +# 停止容器 +docker-compose -f docker-compose.dev.yml down +``` + +### 方式二:使用 Docker 命令 + +```bash +# 构建镜像 +docker build -t diet-recommendation-app . + +# 运行容器 +docker run -d \ + --name diet_recommendation_app \ + -p 5000:5000 \ + -v $(pwd)/data:/app/data \ + -v $(pwd)/logs:/app/logs \ + -v $(pwd)/models:/app/models \ + diet-recommendation-app + +# 查看日志 +docker logs -f diet_recommendation_app + +# 停止容器 +docker stop diet_recommendation_app +docker rm diet_recommendation_app +``` + +## 🌐 访问应用 + +容器启动后,访问: +- **主页**: http://localhost:5000 +- **背诵排序**: http://localhost:5000/recitation +- **数据采集**: http://localhost:5000/data-collection +- **智能推荐**: http://localhost:5000/recommendation +- **营养分析**: http://localhost:5000/analysis +- **健康检查**: http://localhost:5000/health + +## 📁 数据持久化 + +以下目录会自动挂载到容器中,确保数据不丢失: + +- `./data` - 用户数据和数据库 +- `./logs` - 日志文件 +- `./models` - 训练好的模型文件 + +## 🔧 配置说明 + +### 环境变量 + +可以通过 `docker-compose.yml` 中的 `environment` 部分或 `.env` 文件配置: + +```yaml +environment: + - FLASK_ENV=production + - QWEN_API_KEY=your_api_key_here +``` + +### 端口配置 + +默认端口为 `5000`,如需修改: + +```yaml +ports: + - "8080:5000" # 将主机的8080端口映射到容器的5000端口 +``` + +## 🐛 故障排除 + +### 查看容器日志 + +```bash +# Docker Compose +docker-compose logs -f web + +# Docker +docker logs -f diet_recommendation_app +``` + +### 进入容器调试 + +```bash +# Docker Compose +docker-compose exec web bash + +# Docker +docker exec -it diet_recommendation_app bash +``` + +### 重启容器 + +```bash +# Docker Compose +docker-compose restart + +# Docker +docker restart diet_recommendation_app +``` + +### 重新构建镜像 + +```bash +# Docker Compose +docker-compose build --no-cache + +# Docker +docker build --no-cache -t diet-recommendation-app . +``` + +## 📊 健康检查 + +容器包含健康检查功能,可以通过以下方式查看状态: + +```bash +# Docker Compose +docker-compose ps + +# Docker +docker ps +``` + +健康检查端点:`http://localhost:5000/health` + +## 🔒 安全建议 + +1. **生产环境**: + - 使用反向代理(Nginx/Traefik) + - 配置HTTPS + - 限制端口访问 + - 使用环境变量管理敏感信息 + +2. **数据备份**: + - 定期备份 `data` 目录 + - 备份 `models` 目录中的模型文件 + +## 🚢 生产部署示例 + +### 使用 Nginx 作为反向代理 + +```nginx +server { + listen 80; + server_name your-domain.com; + + location / { + proxy_pass http://localhost:5000; + 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; + } +} +``` + +## 📝 注意事项 + +1. **OCR功能**:Docker镜像已包含Tesseract OCR支持 +2. **内存限制**:建议至少分配1GB内存给容器 +3. **文件权限**:确保挂载的目录有适当的读写权限 +4. **时区设置**:如需修改时区,在Dockerfile中添加: + ```dockerfile + ENV TZ=Asia/Shanghai + RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + ``` + +## 🔄 更新应用 + +```bash +# 停止容器 +docker-compose down + +# 拉取最新代码 +git pull + +# 重新构建并启动 +docker-compose build --no-cache +docker-compose up -d +``` + diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..2420749 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,29 @@ +version: '3.8' + +services: + web: + build: + context: . + dockerfile: Dockerfile.dev + container_name: diet_recommendation_app_dev + ports: + - "5000:5000" + environment: + - FLASK_ENV=development + - FLASK_DEBUG=1 + - PYTHONUNBUFFERED=1 + volumes: + # 代码热重载 + - .:/app + # 持久化数据 + - ./data:/app/data + - ./logs:/app/logs + - ./models:/app/models + restart: unless-stopped + networks: + - app-network + +networks: + app-network: + driver: bridge + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6423bf9 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,32 @@ +version: '3.8' + +services: + web: + build: + context: . + dockerfile: Dockerfile + container_name: diet_recommendation_app + ports: + - "5000:5000" + environment: + - FLASK_ENV=production + - PYTHONUNBUFFERED=1 + volumes: + # 持久化数据目录 + - ./data:/app/data + - ./logs:/app/logs + - ./models:/app/models + restart: unless-stopped + networks: + - app-network + healthcheck: + test: ["CMD", "python", "-c", "import requests; requests.get('http://localhost:5000/health')"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 10s + +networks: + app-network: + driver: bridge +