From 09065f2ce75f1e392325f9f8b97ab7b92208c1c8 Mon Sep 17 00:00:00 2001 From: rjb <263303411@qq.com> Date: Sun, 24 Aug 2025 23:40:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90Gunicorn=E5=90=AF=E5=8A=A8?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=E7=9A=84=E6=8C=87=E5=8D=97=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E5=92=8C=E5=BF=AB=E9=80=9F=E5=90=AF=E5=8A=A8=E5=81=9C?= =?UTF-8?q?=E6=AD=A2=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy-k8s.sh | 63 +++++++ docker-compose.simple.yml | 77 ++++++++ docs/deployment/Gunicorn快速参考.md | 56 ++++++ docs/deployment/Gunicorn服务管理指南.md | 241 ++++++++++++++++++++++++ k8s/simple-deployment.yaml | 71 +++++++ scripts/deploy.sh | 0 scripts/restart_gunicorn.sh | 39 ++++ scripts/start_gunicorn.sh | 27 +++ scripts/status_gunicorn.sh | 80 ++++++++ scripts/stop_gunicorn.sh | 48 +++++ start_production_simple.sh | 29 +++ 11 files changed, 731 insertions(+) create mode 100755 deploy-k8s.sh create mode 100644 docker-compose.simple.yml create mode 100644 docs/deployment/Gunicorn快速参考.md create mode 100644 docs/deployment/Gunicorn服务管理指南.md create mode 100644 k8s/simple-deployment.yaml mode change 100644 => 100755 scripts/deploy.sh create mode 100755 scripts/restart_gunicorn.sh create mode 100755 scripts/start_gunicorn.sh create mode 100755 scripts/status_gunicorn.sh create mode 100755 scripts/stop_gunicorn.sh create mode 100755 start_production_simple.sh diff --git a/deploy-k8s.sh b/deploy-k8s.sh new file mode 100755 index 0000000..b6fc63e --- /dev/null +++ b/deploy-k8s.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +echo "🚀 开始Docker+K8s部署..." + +# 检查Docker是否运行 +if ! docker info > /dev/null 2>&1; then + echo "❌ Docker未运行,请先启动Docker" + exit 1 +fi + +# 检查Kubernetes集群状态 +if ! kubectl cluster-info > /dev/null 2>&1; then + echo "❌ Kubernetes集群未连接,请先启动Minikube" + echo "运行: minikube start --driver=docker" + exit 1 +fi + +echo "✅ Docker和Kubernetes状态正常" + +# 构建Docker镜像 +echo "🔨 构建Docker镜像..." +docker build -t flask-prompt-master:latest . + +if [ $? -ne 0 ]; then + echo "❌ Docker镜像构建失败" + exit 1 +fi + +echo "✅ Docker镜像构建成功" + +# 部署到Kubernetes +echo "📦 部署到Kubernetes..." +kubectl apply -f k8s/simple-deployment.yaml + +if [ $? -ne 0 ]; then + echo "❌ Kubernetes部署失败" + exit 1 +fi + +echo "✅ Kubernetes部署成功" + +# 等待Pod启动 +echo "⏳ 等待Pod启动..." +kubectl wait --for=condition=ready pod -l app=flask-prompt-master --timeout=300s + +if [ $? -ne 0 ]; then + echo "❌ Pod启动超时" + exit 1 +fi + +echo "✅ Pod启动成功" + +# 显示服务状态 +echo "📊 服务状态:" +kubectl get pods -l app=flask-prompt-master +kubectl get services -l app=flask-prompt-master + +# 获取访问地址 +echo "🌐 访问地址:" +echo "本地访问: http://localhost:$(kubectl get service flask-prompt-master-service -o jsonpath='{.spec.ports[0].nodePort}')" +echo "负载均衡器: $(kubectl get service flask-prompt-master-loadbalancer -o jsonpath='{.status.loadBalancer.ingress[0].ip}')" + +echo "🎉 部署完成!" diff --git a/docker-compose.simple.yml b/docker-compose.simple.yml new file mode 100644 index 0000000..87209c2 --- /dev/null +++ b/docker-compose.simple.yml @@ -0,0 +1,77 @@ +version: '3.3' + +services: + # Flask应用服务 + app: + build: + context: . + dockerfile: Dockerfile + image: flask-prompt-master:latest + container_name: flask-prompt-master-app + restart: unless-stopped + environment: + - FLASK_ENV=production + - DATABASE_URL=mysql+pymysql://root:${MYSQL_ROOT_PASSWORD}@mysql:3306/${MYSQL_DATABASE}?charset=utf8mb4 + - REDIS_URL=redis://redis:6379/0 + - SECRET_KEY=${SECRET_KEY} + - LLM_API_KEY=${LLM_API_KEY} + depends_on: + - mysql + - redis + volumes: + - ./logs:/app/logs + - ./uploads:/app/uploads + networks: + - app-network + + # MySQL数据库 + mysql: + image: mysql:8.0 + container_name: flask-prompt-master-mysql + restart: unless-stopped + environment: + - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} + - MYSQL_DATABASE=${MYSQL_DATABASE} + - MYSQL_USER=${MYSQL_USER} + - MYSQL_PASSWORD=${MYSQL_PASSWORD} + volumes: + - mysql_data:/var/lib/mysql + networks: + - app-network + + # Redis缓存 + redis: + image: redis:7-alpine + container_name: flask-prompt-master-redis + restart: unless-stopped + command: redis-server --appendonly yes + volumes: + - redis_data:/data + networks: + - app-network + + # Nginx反向代理 + nginx: + image: nginx:alpine + container_name: flask-prompt-master-nginx + restart: unless-stopped + ports: + - "80:80" + - "443:443" + volumes: + - ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf + - ./logs/nginx:/var/log/nginx + depends_on: + - app + networks: + - app-network + +volumes: + mysql_data: + driver: local + redis_data: + driver: local + +networks: + app-network: + driver: bridge diff --git a/docs/deployment/Gunicorn快速参考.md b/docs/deployment/Gunicorn快速参考.md new file mode 100644 index 0000000..57dd37e --- /dev/null +++ b/docs/deployment/Gunicorn快速参考.md @@ -0,0 +1,56 @@ +# Gunicorn快速参考 + +## 🚀 一键操作命令 + +### 启动服务 +```bash +./scripts/start_gunicorn.sh +``` + +### 停止服务 +```bash +./scripts/stop_gunicorn.sh +``` + +### 重启服务 +```bash +./scripts/restart_gunicorn.sh +``` + +### 查看状态 +```bash +./scripts/status_gunicorn.sh +``` + +## 📋 常用命令 + +| 操作 | 命令 | +|------|------| +| 启动 | `./scripts/start_gunicorn.sh` | +| 停止 | `./scripts/stop_gunicorn.sh` | +| 重启 | `./scripts/restart_gunicorn.sh` | +| 状态 | `./scripts/status_gunicorn.sh` | +| 查看日志 | `tail -f logs/gunicorn_access.log` | +| 测试访问 | `curl http://localhost:5002/` | + +## 🌐 访问信息 + +- **本地访问**: http://localhost:5002 +- **外网访问**: http://101.43.95.130:5002 +- **服务端口**: 5002 +- **Python环境**: 3.12.7 (myenv) + +## 📁 重要文件 + +- **配置文件**: `gunicorn.conf.py` +- **PID文件**: `logs/gunicorn.pid` +- **访问日志**: `logs/gunicorn_access.log` +- **错误日志**: `logs/gunicorn_error.log` +- **管理脚本**: `scripts/` + +## ⚠️ 注意事项 + +1. 确保在项目目录下执行命令 +2. 确保conda环境已激活 +3. 确保5002端口未被占用 +4. 确保防火墙已开放5002端口 diff --git a/docs/deployment/Gunicorn服务管理指南.md b/docs/deployment/Gunicorn服务管理指南.md new file mode 100644 index 0000000..e373af5 --- /dev/null +++ b/docs/deployment/Gunicorn服务管理指南.md @@ -0,0 +1,241 @@ +# Gunicorn服务管理指南 + +## 概述 + +本文档介绍如何使用Gunicorn管理Flask提示词大师应用的生产环境服务。 + +## 环境信息 + +- **Python版本**: 3.12.7 +- **Conda环境**: myenv +- **项目路径**: /home/renjianbo/aitsc +- **服务端口**: 5002 +- **外网地址**: http://101.43.95.130:5002 + +## 快速启动命令 + +### 一键启动脚本 + +```bash +# 进入项目目录 +cd /home/renjianbo/aitsc + +# 激活conda环境并启动服务 +eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && gunicorn -c gunicorn.conf.py run_dev:app +``` + +### 后台启动 + +```bash +# 后台启动服务 +cd /home/renjianbo/aitsc +eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && nohup gunicorn -c gunicorn.conf.py run_dev:app > logs/gunicorn.log 2>&1 & +``` + +## 服务管理命令 + +### 1. 启动服务 + +```bash +# 方法1: 直接启动 +cd /home/renjianbo/aitsc +eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && gunicorn -c gunicorn.conf.py run_dev:app + +# 方法2: 后台启动 +cd /home/renjianbo/aitsc +eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && nohup gunicorn -c gunicorn.conf.py run_dev:app > logs/gunicorn.log 2>&1 & +``` + +### 2. 停止服务 + +```bash +# 方法1: 使用PID文件停止 +kill -TERM $(cat logs/gunicorn.pid) + +# 方法2: 强制停止 +kill -9 $(cat logs/gunicorn.pid) + +# 方法3: 查找进程并停止 +ps aux | grep gunicorn | grep -v grep | awk '{print $2}' | xargs kill -TERM +``` + +### 3. 重启服务 + +```bash +# 方法1: 优雅重启(推荐) +kill -HUP $(cat logs/gunicorn.pid) + +# 方法2: 停止后重新启动 +kill -TERM $(cat logs/gunicorn.pid) && sleep 3 && eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && gunicorn -c gunicorn.conf.py run_dev:app +``` + +### 4. 查看服务状态 + +```bash +# 查看进程状态 +ps aux | grep gunicorn | grep -v grep + +# 查看端口监听状态 +ss -tlnp | grep :5002 + +# 查看PID文件 +cat logs/gunicorn.pid +``` + +### 5. 查看日志 + +```bash +# 查看访问日志 +tail -f logs/gunicorn_access.log + +# 查看错误日志 +tail -f logs/gunicorn_error.log + +# 查看应用日志 +tail -f logs/app.log + +# 查看实时日志 +tail -f logs/gunicorn.log +``` + +## 服务配置 + +### Gunicorn配置文件 + +配置文件位置: `gunicorn.conf.py` + +主要配置项: +- **端口**: 5002 +- **工作进程数**: CPU核心数 × 2 + 1 +- **每个进程连接数**: 1000 +- **超时时间**: 30秒 +- **日志级别**: info + +### 环境变量 + +```bash +# 设置环境变量 +export FLASK_ENV=production +export SECRET_KEY="your-production-secret-key" +export LLM_API_KEY="your-api-key" +``` + +## 故障排除 + +### 1. 服务无法启动 + +```bash +# 检查端口是否被占用 +ss -tlnp | grep :5002 + +# 检查日志文件 +cat logs/gunicorn_error.log + +# 检查Python环境 +python --version +pip list | grep gunicorn +``` + +### 2. 服务响应慢 + +```bash +# 检查系统资源 +top +free -h +df -h + +# 检查进程状态 +ps aux | grep gunicorn +``` + +### 3. 端口访问失败 + +```bash +# 检查防火墙 +sudo firewall-cmd --list-ports + +# 开放端口 +sudo firewall-cmd --add-port=5002/tcp --permanent +sudo firewall-cmd --reload +``` + +## 性能监控 + +### 1. 系统资源监控 + +```bash +# CPU和内存使用情况 +top -p $(cat logs/gunicorn.pid) + +# 网络连接数 +ss -s | grep tcp +``` + +### 2. 应用性能监控 + +```bash +# 查看请求统计 +tail -f logs/gunicorn_access.log | grep -E "(GET|POST)" + +# 查看响应时间 +tail -f logs/gunicorn_access.log | awk '{print $NF}' +``` + +## 自动化脚本 + +### 启动脚本 (start_gunicorn.sh) + +```bash +#!/bin/bash +cd /home/renjianbo/aitsc +eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" +conda activate myenv +export FLASK_ENV=production +gunicorn -c gunicorn.conf.py run_dev:app +``` + +### 停止脚本 (stop_gunicorn.sh) + +```bash +#!/bin/bash +cd /home/renjianbo/aitsc +kill -TERM $(cat logs/gunicorn.pid) +echo "Gunicorn服务已停止" +``` + +### 重启脚本 (restart_gunicorn.sh) + +```bash +#!/bin/bash +cd /home/renjianbo/aitsc +kill -TERM $(cat logs/gunicorn.pid) +sleep 3 +eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" +conda activate myenv +export FLASK_ENV=production +gunicorn -c gunicorn.conf.py run_dev:app +``` + +## 常用命令速查 + +| 操作 | 命令 | +|------|------| +| 启动服务 | `eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" && conda activate myenv && gunicorn -c gunicorn.conf.py run_dev:app` | +| 停止服务 | `kill -TERM $(cat logs/gunicorn.pid)` | +| 重启服务 | `kill -HUP $(cat logs/gunicorn.pid)` | +| 查看状态 | `ps aux | grep gunicorn \| grep -v grep` | +| 查看端口 | `ss -tlnp \| grep :5002` | +| 查看日志 | `tail -f logs/gunicorn_access.log` | +| 测试访问 | `curl http://localhost:5002/` | + +## 注意事项 + +1. **环境激活**: 每次操作前必须激活conda环境 +2. **端口冲突**: 确保5002端口未被其他服务占用 +3. **权限问题**: 确保有logs目录的写入权限 +4. **防火墙**: 确保5002端口在防火墙中开放 +5. **日志轮转**: 定期清理日志文件避免磁盘空间不足 + +## 联系信息 + +如有问题,请查看日志文件或联系系统管理员。 diff --git a/k8s/simple-deployment.yaml b/k8s/simple-deployment.yaml new file mode 100644 index 0000000..008bf53 --- /dev/null +++ b/k8s/simple-deployment.yaml @@ -0,0 +1,71 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: flask-prompt-master + labels: + app: flask-prompt-master +spec: + replicas: 2 + selector: + matchLabels: + app: flask-prompt-master + template: + metadata: + labels: + app: flask-prompt-master + spec: + containers: + - name: app + image: flask-prompt-master:latest + ports: + - containerPort: 5000 + env: + - name: FLASK_ENV + value: "production" + - name: SECRET_KEY + value: "your-secret-key-here" + resources: + requests: + memory: "256Mi" + cpu: "250m" + limits: + memory: "512Mi" + cpu: "500m" + livenessProbe: + httpGet: + path: / + port: 5000 + initialDelaySeconds: 30 + periodSeconds: 10 + readinessProbe: + httpGet: + path: / + port: 5000 + initialDelaySeconds: 5 + periodSeconds: 5 +--- +apiVersion: v1 +kind: Service +metadata: + name: flask-prompt-master-service +spec: + selector: + app: flask-prompt-master + ports: + - protocol: TCP + port: 80 + targetPort: 5000 + type: NodePort +--- +apiVersion: v1 +kind: Service +metadata: + name: flask-prompt-master-loadbalancer +spec: + selector: + app: flask-prompt-master + ports: + - protocol: TCP + port: 5002 + targetPort: 5000 + type: LoadBalancer diff --git a/scripts/deploy.sh b/scripts/deploy.sh old mode 100644 new mode 100755 diff --git a/scripts/restart_gunicorn.sh b/scripts/restart_gunicorn.sh new file mode 100755 index 0000000..bae8ddd --- /dev/null +++ b/scripts/restart_gunicorn.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +echo "🔄 重启Gunicorn服务..." +echo "==========================================" + +# 进入项目目录 +cd /home/renjianbo/aitsc + +# 停止服务 +echo "🛑 停止现有服务..." +if [ -f "logs/gunicorn.pid" ]; then + PID=$(cat logs/gunicorn.pid) + if ps -p $PID > /dev/null; then + kill -TERM $PID + sleep 3 + fi +fi + +# 激活conda环境 +echo "🔧 激活环境..." +eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" +conda activate myenv + +# 设置环境变量 +export FLASK_ENV=production +export SECRET_KEY="your-production-secret-key-must-be-very-secure" +export LLM_API_KEY="sk-your-production-api-key" + +# 创建必要目录 +mkdir -p logs uploads + +echo "✅ 环境已激活: Python $(python --version)" +echo "🌐 服务端口: 5002" +echo "🔗 访问地址: http://101.43.95.130:5002" +echo "==========================================" + +# 启动服务 +echo "🚀 启动新服务..." +gunicorn -c gunicorn.conf.py run_dev:app diff --git a/scripts/start_gunicorn.sh b/scripts/start_gunicorn.sh new file mode 100755 index 0000000..bdd0c8e --- /dev/null +++ b/scripts/start_gunicorn.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +echo "🚀 启动Gunicorn服务..." +echo "==========================================" + +# 进入项目目录 +cd /home/renjianbo/aitsc + +# 激活conda环境 +eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" +conda activate myenv + +# 设置环境变量 +export FLASK_ENV=production +export SECRET_KEY="your-production-secret-key-must-be-very-secure" +export LLM_API_KEY="sk-your-production-api-key" + +# 创建必要目录 +mkdir -p logs uploads + +echo "✅ 环境已激活: Python $(python --version)" +echo "🌐 服务端口: 5002" +echo "🔗 访问地址: http://101.43.95.130:5002" +echo "==========================================" + +# 启动Gunicorn服务 +gunicorn -c gunicorn.conf.py run_dev:app diff --git a/scripts/status_gunicorn.sh b/scripts/status_gunicorn.sh new file mode 100755 index 0000000..e247efe --- /dev/null +++ b/scripts/status_gunicorn.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +echo "📊 Gunicorn服务状态检查" +echo "==========================================" + +# 进入项目目录 +cd /home/renjianbo/aitsc + +# 检查进程状态 +echo "🔍 检查进程状态..." +PROCESSES=$(ps aux | grep gunicorn | grep -v grep) +if [ -n "$PROCESSES" ]; then + echo "✅ Gunicorn进程正在运行:" + echo "$PROCESSES" +else + echo "❌ 未找到运行中的Gunicorn进程" +fi + +echo "" + +# 检查端口监听 +echo "🔍 检查端口监听状态..." +PORT_STATUS=$(ss -tlnp | grep :5002) +if [ -n "$PORT_STATUS" ]; then + echo "✅ 端口5002正在监听:" + echo "$PORT_STATUS" +else + echo "❌ 端口5002未在监听" +fi + +echo "" + +# 检查PID文件 +echo "🔍 检查PID文件..." +if [ -f "logs/gunicorn.pid" ]; then + PID=$(cat logs/gunicorn.pid) + echo "📋 PID文件存在: $PID" + if ps -p $PID > /dev/null; then + echo "✅ PID对应的进程正在运行" + else + echo "⚠️ PID对应的进程不存在" + fi +else + echo "⚠️ PID文件不存在" +fi + +echo "" + +# 检查日志文件 +echo "🔍 检查日志文件..." +if [ -f "logs/gunicorn_access.log" ]; then + echo "✅ 访问日志文件存在" + echo "📄 最后10行访问日志:" + tail -10 logs/gunicorn_access.log +else + echo "⚠️ 访问日志文件不存在" +fi + +echo "" + +if [ -f "logs/gunicorn_error.log" ]; then + echo "✅ 错误日志文件存在" + echo "📄 最后10行错误日志:" + tail -10 logs/gunicorn_error.log +else + echo "⚠️ 错误日志文件不存在" +fi + +echo "" + +# 测试服务响应 +echo "🔍 测试服务响应..." +RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5002/ 2>/dev/null) +if [ "$RESPONSE" = "200" ]; then + echo "✅ 服务响应正常 (HTTP $RESPONSE)" +else + echo "❌ 服务响应异常 (HTTP $RESPONSE)" +fi + +echo "==========================================" diff --git a/scripts/stop_gunicorn.sh b/scripts/stop_gunicorn.sh new file mode 100755 index 0000000..495bfbb --- /dev/null +++ b/scripts/stop_gunicorn.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +echo "🛑 停止Gunicorn服务..." +echo "==========================================" + +# 进入项目目录 +cd /home/renjianbo/aitsc + +# 检查PID文件是否存在 +if [ -f "logs/gunicorn.pid" ]; then + PID=$(cat logs/gunicorn.pid) + echo "📋 找到Gunicorn进程PID: $PID" + + # 检查进程是否存在 + if ps -p $PID > /dev/null; then + echo "🔄 正在停止进程..." + kill -TERM $PID + + # 等待进程停止 + sleep 3 + + # 检查是否成功停止 + if ps -p $PID > /dev/null; then + echo "⚠️ 进程仍在运行,强制停止..." + kill -9 $PID + fi + + echo "✅ Gunicorn服务已停止" + else + echo "⚠️ 进程不存在,可能已经停止" + fi +else + echo "⚠️ 未找到PID文件,尝试查找进程..." + + # 查找Gunicorn进程 + PIDS=$(ps aux | grep gunicorn | grep -v grep | awk '{print $2}') + + if [ -n "$PIDS" ]; then + echo "📋 找到Gunicorn进程: $PIDS" + echo $PIDS | xargs kill -TERM + sleep 3 + echo "✅ Gunicorn服务已停止" + else + echo "ℹ️ 未找到运行中的Gunicorn进程" + fi +fi + +echo "==========================================" diff --git a/start_production_simple.sh b/start_production_simple.sh new file mode 100755 index 0000000..4b72172 --- /dev/null +++ b/start_production_simple.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +echo "🚀 Flask 提示词大师 - 简化生产环境部署" +echo "==========================================" + +# 激活conda环境 +eval "$(/home/renjianbo/miniconda3/bin/conda shell.bash hook)" +conda activate myenv + +# 设置环境变量 +export FLASK_ENV=production +export SECRET_KEY="your-production-secret-key-must-be-very-secure" +export LLM_API_KEY="sk-your-production-api-key" + +# 创建必要目录 +mkdir -p logs uploads + +# 安装依赖 +echo "📦 安装Python依赖..." +pip install -r requirements.txt + +# 启动Gunicorn服务 +echo "🌐 启动Gunicorn服务..." +echo "访问地址: http://101.43.95.130:5002" +echo "按 Ctrl+C 停止服务" +echo "==========================================" + +# 使用Gunicorn启动 +gunicorn -c gunicorn.conf.py run_dev:app