# 多独立 AI 算法服务管理实施方案 ## 1. 方案概述 本方案旨在解决多 AI 算法服务的端口冲突、统一启停/监控、配置管理和运维效率问题,同时保持每个服务的独立性,避免单个服务故障影响其他服务。方案支持两种部署方式:无 Docker 的实现方式(使用 Supervisor)和 Docker 容器化实现方式,通过「标准化 + 统一管理」的方法,实现多服务的高效管理。 本方案专门为 AI 算法工程展示平台设计,支持从代码上传、服务部署到算法能力展示的完整流程,满足用户对算法工程管理和展示的核心需求。 ### 1.1 核心诉求 - **端口冲突**:为每个服务分配唯一端口,避免冲突 - **统一管理**:批量管理所有服务的启停、监控、自动重启 - **配置管理**:集中化管理公共配置,保留服务独立配置,包括 Gitea 访问配置 - **运维效率**:降低运维成本,提高服务可靠性 - **服务独立性**:单个服务故障不影响其他服务 - **代码管理**:集成 Gitea 进行代码管理和部署,支持算法工程代码上传 - **服务部署**:自动部署算法工程为 API 服务 - **算法展示**:支持使用演示数据和视频执行算法,展示算法能力 - **效果对比**:支持对比不同算法或参数的效果 ### 1.2 技术栈 - **服务运行**:Python/Node.js + FastAPI/HTTP Server - **统一管理**:Supervisor - **可选**:Nginx(API 网关) - **监控**:服务健康检查 + 日志管理 - **数据库**:PostgreSQL - **缓存**:Redis - **对象存储**:MinIO - **代码管理**:Gitea - **前端**:Vue 3 + TypeScript + Vite + Element Plus - **后端**:FastAPI ### 1.3 网站用途与工作流程 本网站的核心用途是展示和管理多个 AI 算法工程,通过以下三个步骤实现: **第一步:代码管理** - 上传 AI 算法工程代码到平台 - 将代码管理在 Gitea 仓库中 - Gitea 访问配置保存在数据库中,确保配置持久化 **第二步:服务部署与管理** - 部署上传的算法工程为可访问的 API 服务 - 支持多服务的统一管理(启动、停止、重启) - 生成标准化的 API 接口 - 监控服务健康状态和运行情况 **第三步:算法能力展示** - 使用演示数据和视频等输入执行算法 - 可视化展示算法执行结果 - 对比不同算法或参数的效果 - 向客户展示 AI 算法的能力和价值 ## 2. 项目架构分析 ### 2.1 系统架构 ``` ┌─────────────────────────────────────────────────────────┐ │ 前端层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Vue 3 │ │ TypeScript │ │ Element Plus│ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ├─────────────────────────────────────────────────────────┤ │ 后端层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ FastAPI │ │ Service │ │ Gitea │ │ │ │ │ │ Orchestrator│ │ Integration │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ├─────────────────────────────────────────────────────────┤ │ 服务层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Service-1 │ │ Service-2 │ │ Service-3 │ │ │ │ 端口: 8001 │ │ 端口: 8002 │ │ 端口: 8003 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ├─────────────────────────────────────────────────────────┤ │ 存储层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ PostgreSQL │ │ Redis │ │ MinIO │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` ### 2.2 现有系统功能 - ✅ 服务部署(支持 Docker 和本地进程) - ✅ 服务启动/停止/重启/删除 - ✅ 服务状态查询 - ✅ 服务日志获取 - ✅ 服务健康检查 - ✅ Gitea 集成(代码管理和部署) - ✅ 数据库配置管理 - ✅ 前端管理界面 ### 2.3 现有实现的优缺点 **优点**: - 支持两种部署模式,灵活性高 - 提供完整的服务生命周期管理 - 实现了服务健康检查和日志管理 - 集成了 Gitea 进行代码管理和部署 - 支持数据库配置管理 - 提供了完整的前端管理界面 **缺点**: - 本地进程模式下,服务管理依赖于 `ServiceOrchestrator` 进程,进程退出后无法自动管理服务 - 缺乏批量管理能力,每次操作需要单独处理每个服务 - 服务配置分散,缺乏集中化管理 - 端口管理依赖手动配置,容易冲突 ## 3. 方案设计 ### 3.1 整体架构 ``` ┌─────────────────────────────────────────────────────────┐ │ 管理层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Supervisor │ │ Nginx │ │ 配置管理 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ├─────────────────────────────────────────────────────────┤ │ 服务层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Service-1 │ │ Service-2 │ │ Service-3 │ │ │ │ 端口: 8001 │ │ 端口: 8002 │ │ 端口: 8003 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ├─────────────────────────────────────────────────────────┤ │ 基础设施层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 操作系统 │ │ 网络 │ │ 文件系统 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` ### 3.2 核心设计原则 1. **服务标准化**:统一目录结构、接口规范、启动方式 2. **端口独占规划**:为每个服务分配唯一端口 3. **统一管理工具**:使用 Supervisor 批量管理服务 4. **配置集中化**:抽离公共配置,保留独立配置 5. **服务独立性**:每个服务独立运行,独立管理 6. **代码管理集成**:通过 Gitea 管理服务代码和部署 ## 4. 分步实现 ### 4.1 第一步:数据库配置管理 #### 4.1.1 配置存储架构 为了支持在界面上配置并存储到数据库中,我们需要设计一个统一的配置管理架构: ``` ┌─────────────────────────────────────────────────────────┐ │ 配置管理架构 │ ├─────────────────────────────────────────────────────────┤ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 前端配置界面 │ │ 配置API层 │ │ 配置服务层 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ├─────────────────────────────────────────────────────────┤ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 配置数据库 │ │ 缓存层 │ │ 配置文件 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` #### 4.1.2 配置数据库模型 创建统一的配置存储模型: ```python # backend/app/models/models.py class ServiceConfig(Base): """服务配置模型""" __tablename__ = "service_configs" id = Column(String, primary_key=True, index=True) config_key = Column(String, nullable=False, unique=True, index=True) # 配置键 config_value = Column(JSON, nullable=False) # 配置值(JSON格式) config_type = Column(String, nullable=False) # 配置类型:system, service, user service_id = Column(String, nullable=True, index=True) # 服务ID(可为空,系统配置) description = Column(Text, default="") # 配置描述 status = Column(String, default="active") # 状态 created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) ``` #### 4.1.3 配置服务实现 ```python # backend/app/services/config_service.py class ConfigService: """配置服务""" @staticmethod def get_config(db: Session, config_key: str) -> Optional[Dict[str, Any]]: """获取配置""" config = db.query(ServiceConfig).filter_by( config_key=config_key, status="active" ).first() if config: return config.config_value return None @staticmethod def set_config(db: Session, config_key: str, config_value: Dict[str, Any], config_type: str = "system", service_id: Optional[str] = None, description: str = "") -> bool: """设置配置""" try: # 检查是否存在 existing_config = db.query(ServiceConfig).filter_by( config_key=config_key ).first() if existing_config: # 更新现有配置 existing_config.config_value = config_value existing_config.config_type = config_type existing_config.service_id = service_id existing_config.description = description existing_config.status = "active" else: # 创建新配置 new_config = ServiceConfig( id=f"config-{uuid.uuid4()}", config_key=config_key, config_value=config_value, config_type=config_type, service_id=service_id, description=description, status="active" ) db.add(new_config) db.commit() return True except Exception as e: logger.error(f"Failed to set config: {str(e)}") db.rollback() return False @staticmethod def get_service_configs(db: Session, service_id: str) -> List[Dict[str, Any]]: """获取服务的所有配置""" configs = db.query(ServiceConfig).filter_by( service_id=service_id, status="active" ).all() return [ { "key": config.config_key, "value": config.config_value, "type": config.config_type, "description": config.description } for config in configs ] ``` #### 4.1.4 配置API接口 ```python # backend/app/routes/config.py router = APIRouter(prefix="/config", tags=["config"]) @router.get("/{config_key}") async def get_config( config_key: str, db: Session = Depends(get_db), current_user: dict = Depends(get_current_active_user) ): """获取配置""" config = ConfigService.get_config(db, config_key) if not config: raise HTTPException(status_code=404, detail="配置不存在") return {"key": config_key, "value": config} @router.post("/{config_key}") async def set_config( config_key: str, config_data: Dict[str, Any], db: Session = Depends(get_db), current_user: dict = Depends(get_current_active_user) ): """设置配置""" success = ConfigService.set_config( db=db, config_key=config_key, config_value=config_data.get("value"), config_type=config_data.get("type", "system"), service_id=config_data.get("service_id"), description=config_data.get("description", "") ) if not success: raise HTTPException(status_code=400, detail="设置配置失败") return {"message": "设置配置成功"} @router.get("/service/{service_id}") async def get_service_configs( service_id: str, db: Session = Depends(get_db), current_user: dict = Depends(get_current_active_user) ): """获取服务配置""" configs = ConfigService.get_service_configs(db, service_id) return {"service_id": service_id, "configs": configs} ``` #### 4.1.5 前端配置界面 ```vue ``` ### 4.2 第二步:多服务目录标准化 #### 4.2.1 统一服务根目录 ```plaintext /opt/ai-services/ # 所有AI服务的根目录 ├── config/ # 全局配置 │ ├── common.py # 公共配置 │ └── ports.py # 端口分配配置 ├── logs/ # 所有服务的日志总目录 │ ├── service-1.log │ ├── service-2.log │ └── service-3.log ├── service-1/ # 服务1:如文本分类 │ ├── ai_algorithm.py # 服务1的AI算法逻辑 │ ├── main.py # 服务1的FastAPI接口 │ ├── requirements.txt # 服务1的依赖 │ ├── config.py # 服务1的独立配置 │ └── venv/ # 服务1的虚拟环境 ├── service-2/ # 服务2:如图像识别 │ ├── ai_algorithm.py │ ├── main.py │ ├── requirements.txt │ ├── config.py │ └── venv/ └── service-3/ # 服务3:如语音转文字 ├── ... ``` #### 4.2.2 统一接口规范 所有服务必须实现以下接口: - `POST /predict`:算法预测接口 - `GET /health`:健康检查接口 - `GET /info`:服务信息接口 #### 4.2.3 统一启动方式 所有服务使用统一的启动脚本: ```bash # /opt/ai-services/service-1/start.sh #!/bin/bash cd /opt/ai-services/service-1 source venv/bin/activate python main.py ``` ### 4.3 第三步:使用 Supervisor 统一管理服务 #### 4.3.1 安装 Supervisor ```bash # Ubuntu/Debian apt update && apt install supervisor # CentOS/RHEL yum install epel-release yum install supervisor # 启动 Supervisor 服务 systemctl start supervisor systemctl enable supervisor ``` #### 4.3.2 配置 Supervisor 创建统一的配置文件: ```ini # /etc/supervisor/conf.d/ai-services.conf [supervisord] logfile=/opt/ai-services/logs/supervisord.log logfile_maxbytes=50MB logfile_backups=10 loglevel=info pidfile=/var/run/supervisord.pid nodaemon=false minfds=1024 minprocs=200 # 服务1:文本分类(8001端口) [program:ai-service-1] name=ai-service-1 command=/opt/ai-services/service-1/start.sh directory=/opt/ai-services/service-1 user=ubuntu autostart=true autorestart=true startretries=3 stdout_logfile=/opt/ai-services/logs/service-1.log stderr_logfile=/opt/ai-services/logs/service-1_error.log stdout_logfile_maxbytes=10MB stdout_logfile_backups=5 # 服务2:图像识别(8002端口) [program:ai-service-2] name=ai-service-2 command=/opt/ai-services/service-2/start.sh directory=/opt/ai-services/service-2 user=ubuntu autostart=true autorestart=true startretries=3 stdout_logfile=/opt/ai-services/logs/service-2.log stderr_logfile=/opt/ai-services/logs/service-2_error.log stdout_logfile_maxbytes=10MB stdout_logfile_backups=5 # 服务3:语音转文字(8003端口) [program:ai-service-3] name=ai-service-3 command=/opt/ai-services/service-3/start.sh directory=/opt/ai-services/service-3 user=ubuntu autostart=true autorestart=true startretries=3 stdout_logfile=/opt/ai-services/logs/service-3.log stderr_logfile=/opt/ai-services/logs/service-3_error.log stdout_logfile_maxbytes=10MB stdout_logfile_backups=5 ``` #### 4.3.3 Supervisor 管理命令 ```bash # 重新加载配置(新增/修改服务后执行) supervisorctl reload # 启动所有AI服务 supervisorctl start ai-service-* # 启动单个服务 supervisorctl start ai-service-1 # 查看所有服务状态 supervisorctl status # 输出示例: # ai-service-1 RUNNING pid 1234, uptime 0:05:10 # ai-service-2 RUNNING pid 1235, uptime 0:05:08 # ai-service-3 RUNNING pid 1236, uptime 0:05:05 # 重启所有服务 supervisorctl restart ai-service-* # 停止单个服务 supervisorctl stop ai-service-2 # 查看某个服务的日志(快速排查问题) supervisorctl tail -f ai-service-1 ``` ### 4.4 第四步:配置集中化管理 #### 4.4.1 配置管理架构 采用三层配置管理架构: 1. **数据库配置**:存储在数据库中的动态配置,支持界面修改 2. **文件配置**:存储在文件中的静态配置,作为默认值 3. **环境变量**:优先级最高,用于覆盖其他配置 #### 4.4.2 配置加载流程 ```python # backend/app/config/settings.py from pydantic_settings import BaseSettings from typing import Optional, Dict, Any from sqlalchemy.orm import Session from app.models.database import SessionLocal from app.models.models import ServiceConfig class Settings(BaseSettings): """应用配置类""" # 应用基本配置 APP_NAME: str = "智能算法展示平台" APP_VERSION: str = "1.0.0" DEBUG: bool = True # 数据库配置 DATABASE_URL: str = "postgresql://admin:password@localhost:5432/algorithm_db" # 其他配置... # 服务管理配置 SERVICE_MANAGEMENT: Dict[str, Any] = { "mode": "supervisor", # 服务管理模式:local, docker, supervisor "service_root_dir": "/opt/ai-services", "supervisor_config_dir": "/etc/supervisor/conf.d", } class Config: env_file = ".env" case_sensitive = True extra = "allow" # 允许额外的环境变量 def get_config(self, config_key: str, default: Any = None) -> Any: """获取配置,优先级:环境变量 > 数据库 > 文件默认值""" # 1. 先从环境变量获取 env_value = getattr(self, config_key.upper().replace('.', '_'), None) if env_value is not None: return env_value # 2. 从数据库获取 db: Session = SessionLocal() try: config = db.query(ServiceConfig).filter_by( config_key=config_key, status="active" ).first() if config: return config.config_value finally: db.close() # 3. 返回默认值 return default # 创建全局配置实例 settings = Settings() ``` #### 4.4.3 配置服务集成 ```python # backend/app/services/service_orchestrator.py class ServiceOrchestrator: """服务编排服务""" def __init__(self, deployment_mode="local"): """初始化服务编排器 Args: deployment_mode: 部署模式,支持"docker"、"local"和"supervisor" """ # 从数据库获取配置 self.deployment_mode = settings.get_config("deployment.mode", deployment_mode) self.service_root_dir = settings.get_config("service.root.dir", "/opt/ai-services") # 其他初始化代码... def _get_service_config(self, service_id: str) -> Dict[str, Any]: """获取服务配置""" # 基础配置 base_config = { "host": "0.0.0.0", "port": self._get_service_port(service_id), "timeout": 30, "health_check_interval": 10, } # 从数据库获取服务特定配置 db: Session = SessionLocal() try: configs = db.query(ServiceConfig).filter_by( service_id=service_id, status="active" ).all() for config in configs: # 解析配置键,设置到相应的位置 if config.config_key == "service.port": base_config["port"] = config.config_value elif config.config_key == "service.host": base_config["host"] = config.config_value elif config.config_key == "service.timeout": base_config["timeout"] = config.config_value finally: db.close() return base_config ``` #### 4.4.4 配置管理最佳实践 1. **配置分类**: - `system`:系统级配置,影响所有服务 - `service`:服务级配置,仅影响特定服务 - `user`:用户级配置,与用户偏好相关 2. **配置命名规范**: - 使用点分隔的命名方式:`category.subcategory.setting` - 示例:`service.port`, `deployment.mode`, `logging.level` 3. **配置版本管理**: - 保留配置的历史版本 - 支持配置回滚 - 记录配置修改日志 4. **配置验证**: - 对配置值进行类型检查 - 对配置值进行范围验证 - 确保配置的完整性 5. **配置安全**: - 敏感配置加密存储 - 配置访问权限控制 - 配置变更审计 ### 4.5 第五步:可选优化 - 统一 API 网关 #### 4.5.1 安装 Nginx ```bash # Ubuntu/Debian apt update && apt install nginx # CentOS/RHEL yum install nginx # 启动 Nginx 服务 systemctl start nginx systemctl enable nginx ``` #### 4.5.2 配置 Nginx 反向代理 ```nginx # /etc/nginx/conf.d/ai-services.conf server { listen 80; server_name your-server-ip; # 替换为你的服务器IP/域名 # 服务1:文本分类(网关路径/ai/text-classify) location /ai/text-classify/ { proxy_pass http://127.0.0.1:8001/; 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_connect_timeout 30s; proxy_read_timeout 30s; } # 服务2:图像识别(网关路径/ai/image-recog) location /ai/image-recog/ { proxy_pass http://127.0.0.1:8002/; 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_connect_timeout 30s; proxy_read_timeout 30s; } # 服务3:语音转文字(网关路径/ai/speech-to-text) location /ai/speech-to-text/ { proxy_pass http://127.0.0.1:8003/; 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_connect_timeout 30s; proxy_read_timeout 30s; } } ``` #### 4.5.3 重启 Nginx 并测试 ```bash # 检查配置是否正确 nginx -t # 重启Nginx systemctl restart nginx # 测试网关调用(无需记端口,只需记路径) curl -X POST "http://your-server-ip/ai/text-classify/predict" \ -H "Content-Type: application/json" \ -d '{"input_data": ["这是一个测试文本"], "batch_id": "test_001"}' ``` ## 5. 与现有系统集成 ### 5.1 集成 ServiceOrchestrator 修改现有的 `ServiceOrchestrator` 类,使其支持 Supervisor 管理模式和数据库配置: ```python # backend/app/services/service_orchestrator.py class ServiceOrchestrator: """服务编排服务""" def __init__(self, deployment_mode="local"): """初始化服务编排器 Args: deployment_mode: 部署模式,支持"docker"、"local"和"supervisor" """ # 从数据库获取配置 self.deployment_mode = settings.get_config("deployment.mode", deployment_mode) self.service_root_dir = settings.get_config("service.root.dir", "/opt/ai-services") # 其他初始化代码... def deploy_service(self, service_id: str, service_config: Dict[str, Any], project_info: Dict[str, Any]) -> Dict[str, Any]: """部署服务""" try: if self.deployment_mode == "supervisor": # 使用 Supervisor 部署服务 return self._deploy_with_supervisor(service_id, service_config, project_info) # 其他部署模式... except Exception as e: # 错误处理... def _deploy_with_supervisor(self, service_id: str, service_config: Dict[str, Any], project_info: Dict[str, Any]) -> Dict[str, Any]: """使用 Supervisor 部署服务""" # 1. 创建服务目录 service_dir = self._create_service_directory(service_id) # 2. 生成服务配置和启动脚本 self._generate_service_config(service_dir, service_id, service_config) self._generate_start_script(service_dir, service_id) # 3. 创建 Supervisor 配置 self._create_supervisor_config(service_id, service_dir, service_config) # 4. 重新加载 Supervisor 配置 self._reload_supervisor() # 5. 启动服务 self._start_supervisor_service(service_id) # 6. 验证服务启动 if not self._verify_service_startup(service_id, service_config): return { "success": False, "error": "服务启动验证失败", "service_id": service_id, "status": "error", "api_url": None } # 7. 构建 API URL api_url = f"http://{service_config.get('host', 'localhost')}:{service_config.get('port', 8000)}" # 8. 保存服务配置到数据库 self._save_service_config_to_db(service_id, service_config) return { "success": True, "service_id": service_id, "status": "running", "api_url": api_url, "error": None } def _save_service_config_to_db(self, service_id: str, service_config: Dict[str, Any]): """保存服务配置到数据库""" db = SessionLocal() try: # 保存服务端口 ConfigService.set_config( db=db, config_key="service.port", config_value=service_config.get("port"), config_type="service", service_id=service_id, description="服务端口" ) # 保存服务主机 ConfigService.set_config( db=db, config_key="service.host", config_value=service_config.get("host", "0.0.0.0"), config_type="service", service_id=service_id, description="服务主机" ) # 保存服务超时 ConfigService.set_config( db=db, config_key="service.timeout", config_value=service_config.get("timeout", 30), config_type="service", service_id=service_id, description="服务超时时间" ) finally: db.close() # 其他方法... ``` ### 5.2 集成配置管理 修改现有配置管理,使用数据库存储配置: ```python # backend/app/config/settings.py from pydantic_settings import BaseSettings from typing import Optional, Dict, Any from sqlalchemy.orm import Session from app.models.database import SessionLocal from app.models.models import ServiceConfig class Settings(BaseSettings): """应用配置类""" # 应用基本配置 APP_NAME: str = "智能算法展示平台" APP_VERSION: str = "1.0.0" DEBUG: bool = True # 数据库配置 DATABASE_URL: str = "postgresql://admin:password@localhost:5432/algorithm_db" # 其他配置... # 服务管理配置 SERVICE_MANAGEMENT: Dict[str, Any] = { "mode": "supervisor", # 服务管理模式:local, docker, supervisor "service_root_dir": "/opt/ai-services", "supervisor_config_dir": "/etc/supervisor/conf.d", } class Config: env_file = ".env" case_sensitive = True extra = "allow" # 允许额外的环境变量 def get_config(self, config_key: str, default: Any = None) -> Any: """获取配置,优先级:环境变量 > 数据库 > 文件默认值""" # 1. 先从环境变量获取 env_value = getattr(self, config_key.upper().replace('.', '_'), None) if env_value is not None: return env_value # 2. 从数据库获取 db: Session = SessionLocal() try: config = db.query(ServiceConfig).filter_by( config_key=config_key, status="active" ).first() if config: return config.config_value finally: db.close() # 3. 返回默认值 return default # 创建全局配置实例 settings = Settings() ``` ### 5.3 集成服务状态查询 修改服务状态查询接口,支持 Supervisor 管理的服务: ```python # backend/app/routes/services.py @router.get("/status/{service_id}") async def get_service_status( service_id: str, orchestrator: ServiceOrchestrator = Depends(get_orchestrator) ): """获取服务状态""" try: # 获取服务状态 status_info = orchestrator.get_service_status(service_id) if not status_info["success"]: raise HTTPException(status_code=404, detail=status_info.get("error", "服务不存在")) return { "service_id": service_id, "status": status_info["status"], "health": status_info["health"], "message": "获取服务状态成功" } except Exception as e: raise HTTPException(status_code=500, detail=str(e)) ``` ### 5.4 集成配置 API 添加配置管理 API 接口: ```python # backend/app/routes/config.py from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from typing import Dict, Any, List, Optional from app.models.database import get_db from app.services.config_service import ConfigService from app.services.user import get_current_active_user router = APIRouter(prefix="/config", tags=["config"]) @router.get("/{config_key}") async def get_config( config_key: str, db: Session = Depends(get_db), current_user: dict = Depends(get_current_active_user) ): """获取配置""" config = ConfigService.get_config(db, config_key) if not config: raise HTTPException(status_code=404, detail="配置不存在") return {"key": config_key, "value": config} @router.post("/{config_key}") async def set_config( config_key: str, config_data: Dict[str, Any], db: Session = Depends(get_db), current_user: dict = Depends(get_current_active_user) ): """设置配置""" success = ConfigService.set_config( db=db, config_key=config_key, config_value=config_data.get("value"), config_type=config_data.get("type", "system"), service_id=config_data.get("service_id"), description=config_data.get("description", "") ) if not success: raise HTTPException(status_code=400, detail="设置配置失败") return {"message": "设置配置成功"} @router.get("/service/{service_id}") async def get_service_configs( service_id: str, db: Session = Depends(get_db), current_user: dict = Depends(get_current_active_user) ): """获取服务配置""" configs = ConfigService.get_service_configs(db, service_id) return {"service_id": service_id, "configs": configs} ``` ## 6. Gitea 集成方案 ### 6.1 Gitea 集成概述 针对所有工程都在 Gitea 上的场景,本方案提供了完整的 Gitea 集成能力,实现从代码仓库到服务部署的全流程管理。基于现有的 GiteaService 和 GiteaClient 实现,进一步完善了从代码管理到服务部署的自动化流程。 ### 6.2 现有 Gitea 集成实现 当前系统已经实现了完整的 Gitea 集成功能: - ✅ Gitea 连接配置管理 - ✅ 仓库创建、克隆、推送、拉取 - ✅ 代码上传(支持大文件处理) - ✅ 从 Gitea 部署服务 - ✅ 错误处理和重试机制 - ✅ CI/CD 集成支持 ### 6.3 Gitea 配置管理(gitea_configs) #### 6.3.1 配置存储架构 系统使用 `gitea_configs` 表存储 Gitea 连接配置,实现了配置的持久化和版本管理: ```python # backend/app/models/models.py class GiteaConfig(Base): """Gitea配置模型""" __tablename__ = "gitea_configs" id = Column(String, primary_key=True, index=True) server_url = Column(String, nullable=False) # Gitea服务器URL access_token = Column(String, nullable=False) # 访问令牌 default_owner = Column(String, nullable=False) # 默认组织/用户 repo_prefix = Column(String, default="") # 仓库前缀 status = Column(String, default="active") # 状态 created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) ``` #### 6.3.2 配置管理实现 Gitea 配置管理通过 `GiteaService` 实现,支持配置的加载、保存和使用: ```python # backend/app/gitea/service.py class GiteaService: def _load_config(self) -> Optional[Dict[str, Any]]: """加载Gitea配置""" try: db = SessionLocal() # 从数据库中获取配置(只取第一个配置) config = db.query(GiteaConfig).filter_by(status="active").first() db.close() if config: return { 'id': config.id, 'server_url': config.server_url, 'access_token': config.access_token, 'default_owner': config.default_owner, 'repo_prefix': config.repo_prefix, 'status': config.status } # 配置不存在时返回默认值 return { 'server_url': getattr(settings, 'GITEA_SERVER_URL', ''), 'access_token': getattr(settings, 'GITEA_ACCESS_TOKEN', ''), 'default_owner': getattr(settings, 'GITEA_DEFAULT_OWNER', ''), 'repo_prefix': getattr(settings, 'GITEA_REPO_PREFIX', '') } except Exception as e: logger.error(f"Failed to load Gitea config from database: {str(e)}") # 出错时返回默认配置 return { 'server_url': getattr(settings, 'GITEA_SERVER_URL', ''), 'access_token': getattr(settings, 'GITEA_ACCESS_TOKEN', ''), 'default_owner': getattr(settings, 'GITEA_DEFAULT_OWNER', ''), 'repo_prefix': getattr(settings, 'GITEA_REPO_PREFIX', '') } def save_config(self, config: Dict[str, Any]) -> bool: """保存Gitea配置""" try: db = SessionLocal() # 将所有现有配置设置为非活动状态 db.query(GiteaConfig).update({GiteaConfig.status: "inactive"}) # 检查是否已有配置 existing_config = db.query(GiteaConfig).first() if existing_config: # 更新现有配置 existing_config.server_url = config['server_url'] existing_config.access_token = config['access_token'] existing_config.default_owner = config['default_owner'] existing_config.repo_prefix = config.get('repo_prefix', '') existing_config.status = "active" else: # 创建新配置 new_config = GiteaConfig( id=f"gitea-config-{uuid.uuid4()}", server_url=config['server_url'], access_token=config['access_token'], default_owner=config['default_owner'], repo_prefix=config.get('repo_prefix', ''), status="active" ) db.add(new_config) db.commit() db.close() # 更新内存中的配置 self.config = config self.client = GiteaClient( config['server_url'], config['access_token'] ) logger.info("Gitea config saved to database successfully") return True except Exception as e: logger.error(f"Failed to save Gitea config to database: {str(e)}") return False ``` #### 6.3.3 配置使用流程 1. **配置加载**:系统启动时,`GiteaService` 会从数据库加载 Gitea 配置 2. **配置验证**:使用加载的配置初始化 `GiteaClient`,测试连接 3. **配置使用**:在仓库操作、代码上传等功能中使用配置 4. **配置更新**:通过 API 或界面更新配置,自动保存到数据库 #### 6.3.4 配置管理最佳实践 1. **配置版本控制**:系统会将旧配置标记为 `inactive`,保留配置历史 2. **配置验证**:保存配置前应测试连接,确保配置有效 3. **安全存储**:访问令牌应妥善保管,避免泄露 4. **配置备份**:定期备份 `gitea_configs` 表,防止配置丢失 #### 6.3.5 配置 API 接口 系统提供了 Gitea 配置管理的 API 接口: - `GET /api/v1/gitea/config`:获取当前 Gitea 配置 - `POST /api/v1/gitea/config`:更新 Gitea 配置 - `GET /api/v1/gitea/test-connection`:测试 Gitea 连接状态 ### 6.4 核心功能 - **配置管理**:获取、设置 Gitea 连接配置,支持环境变量和数据库存储 - **连接测试**:测试与 Gitea 服务器的连接状态 - **仓库管理**:创建、克隆、推送、拉取 Gitea 仓库 - **代码上传**:支持大量文件上传,解决 HTTP 413 错误 - **大文件处理**:支持大文件分阶段推送,优化推送性能 - **服务部署**:从 Gitea 仓库直接部署算法服务 - **算法注册**:从仓库注册算法服务到系统 ### 6.5 集成架构 ``` ┌─────────────────────────────────────────────────────────┐ │ 管理层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Supervisor │ │ Nginx │ │ Gitea服务 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ├─────────────────────────────────────────────────────────┤ │ 服务层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Service-1 │ │ Service-2 │ │ Service-3 │ │ │ │ 端口: 8001 │ │ 端口: 8002 │ │ 端口: 8003 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ├─────────────────────────────────────────────────────────┤ │ 代码层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Gitea仓库1 │ │ Gitea仓库2 │ │ Gitea仓库3 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ ├─────────────────────────────────────────────────────────┤ │ 基础设施层 │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 操作系统 │ │ 网络 │ │ 文件系统 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────┘ ``` ### 6.6 从 Gitea 部署服务的完整流程 #### 6.6.1 配置 Gitea 连接 1. **设置 Gitea 配置**: - 服务器 URL - 访问令牌 - 默认所有者 - 仓库前缀 2. **测试连接**: ```bash # 使用现有的 GiteaService 测试连接 python -c "from app.gitea.service import gitea_service; print(gitea_service.test_connection())" ``` 3. **API 接口**: ```bash # 获取 Gitea 配置 curl -X GET "http://localhost:8001/api/v1/gitea/config" -H "Authorization: Bearer " # 设置 Gitea 配置 curl -X POST "http://localhost:8001/api/v1/gitea/config" -H "Authorization: Bearer " -H "Content-Type: application/json" -d '{ "server_url": "https://gitea.example.com", "access_token": "your-token", "default_owner": "owner", "repo_prefix": "AI-" }' ``` #### 6.6.2 仓库管理流程 1. **创建仓库**: ```python from app.gitea.service import gitea_service repo = gitea_service.create_repository( algorithm_id="text-classification", algorithm_name="文本分类算法", description="基于 BERT 的文本分类算法" ) print(repo) ``` 2. **克隆仓库**: ```python success = gitea_service.clone_repository( repo_url="https://gitea.example.com/owner/text-classification.git", algorithm_id="text-classification" ) print(f"Clone success: {success}") ``` 3. **推送代码**: ```python success = gitea_service.push_to_repository( algorithm_id="text-classification", message="Update algorithm code" ) print(f"Push success: {success}") ``` 4. **上传文件**: ```bash # 使用 API 上传文件 curl -X POST "http://localhost:8001/api/v1/gitea/repos/upload" -H "Authorization: Bearer " -F "algorithm_id=text-classification" -F "files=@algorithm.py" -F "files=@model.pth" ``` #### 6.6.3 从 Gitea 部署服务 1. **通过 API 部署**: ```bash # 从 Gitea 部署服务 curl -X POST "http://localhost:8001/api/v1/services/deploy-from-gitea" -H "Authorization: Bearer " -H "Content-Type: application/json" -d '{ "algorithm_id": "text-classification", "repo_url": "https://gitea.example.com/owner/text-classification.git", "branch": "main", "service_config": { "name": "文本分类服务", "port": 8001, "host": "0.0.0.0", "timeout": 30 } }' ``` 2. **通过前端界面部署**: - 登录前端管理界面 - 进入「服务管理」页面 - 点击「从 Gitea 部署」按钮 - 填写部署信息并提交 #### 6.6.4 服务管理和监控 1. **服务状态查询**: ```bash curl -X GET "http://localhost:8001/api/v1/services/status/text-classification" -H "Authorization: Bearer " ``` 2. **服务日志查询**: ```bash curl -X GET "http://localhost:8001/api/v1/services/logs/text-classification?lines=100" -H "Authorization: Bearer " ``` 3. **服务操作**: ```bash # 启动服务 curl -X POST "http://localhost:8001/api/v1/services/start/text-classification" -H "Authorization: Bearer " # 停止服务 curl -X POST "http://localhost:8001/api/v1/services/stop/text-classification" -H "Authorization: Bearer " # 重启服务 curl -X POST "http://localhost:8001/api/v1/services/restart/text-classification" -H "Authorization: Bearer " ``` ## 7. 数据库设计与实现 ### 7.1 数据库架构 系统使用 PostgreSQL 数据库,包含以下核心表: 1. **algorithms**:算法信息表,存储算法的基本信息 2. **algorithm_versions**:算法版本表,存储算法的不同版本 3. **roles**:角色表,存储用户角色信息 4. **users**:用户表,存储用户信息 5. **algorithm_calls**:算法调用记录表,存储算法调用的历史记录 6. **gitea_configs**:Gitea配置表,存储Gitea连接配置 7. **algorithm_repositories**:算法仓库表,存储算法代码仓库信息 8. **service_groups**:服务分组表,存储服务分组信息 9. **algorithm_services**:算法服务表,存储算法服务的部署信息 10. **service_configs**:服务配置表,存储服务的配置信息 ### 7.2 数据关系 ``` ┌─────────────────┐ ┌─────────────────────┐ │ algorithms │┼──────│algorithm_versions │ └─────────────────┘ └─────────────────────┘ │ │ │ │ │ │ ┌─────────────────┐ ┌─────────────────────┐ │algorithm_calls │┼──────│ users │ └─────────────────┘ └─────────────────────┘ │ │ ┌─────────────────┐ ┌─────────────────────┐ │ gitea_configs │ │ roles │ └─────────────────┘ └─────────────────────┘ │ │ ┌─────────────────┐ ┌─────────────────────┐ │algorithm_repos │┼──────│algorithm_services │ └─────────────────┘ └─────────────────────┘ │ │ ┌─────────────────┐ ┌─────────────────────┐ │service_groups │ │ service_configs │ └─────────────────┘ └─────────────────────┘ ``` ### 7.3 数据库初始化 ```python # backend/init_db.py from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from app.models.database import Base from app.models.models import Algorithm, AlgorithmVersion, Role, User, AlgorithmCall, GiteaConfig, AlgorithmRepository, ServiceGroup, AlgorithmService, ServiceConfig # 创建数据库引擎 engine = create_engine("postgresql://admin:password@localhost:5432/algorithm_db") # 创建所有表 Base.metadata.create_all(bind=engine) # 创建会话 SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) db = SessionLocal() # 初始化默认角色 try: # 检查是否已存在角色 admin_role = db.query(Role).filter_by(name="admin").first() if not admin_role: admin_role = Role( id="role-admin", name="admin", description="管理员角色,拥有所有权限" ) db.add(admin_role) user_role = db.query(Role).filter_by(name="user").first() if not user_role: user_role = Role( id="role-user", name="user", description="普通用户角色,拥有基本权限" ) db.add(user_role) db.commit() print("默认角色初始化成功") except Exception as e: db.rollback() print(f"初始化默认角色失败: {str(e)}") # 关闭会话 db.close() ## 8. 总结与最佳实践 ### 8.1 方案总结 本方案提供了一个完整的多独立 AI 算法服务管理解决方案,解决了端口冲突、统一管理、配置管理、运维效率和服务独立性等核心诉求。通过以下关键技术实现: 1. **服务标准化**:统一目录结构、接口规范和启动方式,提高服务的一致性和可维护性 2. **Supervisor 统一管理**:批量管理所有服务的启停、监控和自动重启,减少人工干预 3. **配置集中化**:采用数据库存储配置,支持界面修改,实现配置的动态管理 4. **Gitea 集成**:实现从代码管理到服务部署的全流程自动化,提高开发和部署效率 5. **数据库配置管理**:支持在界面上配置并存储到数据库中,实现配置的版本管理和历史追踪 ### 8.2 最佳实践 1. **服务设计**: - 每个服务应保持独立,避免与其他服务产生强依赖 - 实现标准化的健康检查和服务信息接口 - 合理设置服务的超时时间和资源限制 2. **配置管理**: - 使用分层配置管理:环境变量 > 数据库配置 > 文件配置 - 为配置设置合理的命名规范,便于管理和维护 - 定期备份配置数据,防止配置丢失 3. **部署管理**: - 使用 Supervisor 管理服务,确保服务的可靠运行 - 实现服务的自动重启机制,提高服务的可用性 - 为每个服务分配唯一的端口,避免端口冲突 4. **监控与运维**: - 实现服务的健康检查和状态监控 - 集中管理服务日志,便于问题排查 - 建立服务的告警机制,及时发现和处理服务异常 5. **安全管理**: - 保护敏感配置信息,避免泄露 - 实现服务的访问控制,确保服务的安全性 - 定期更新服务依赖,修复安全漏洞 ### 8.3 后续优化方向 1. **服务发现与注册**:实现服务的自动发现和注册机制,减少手动配置 2. **负载均衡**:为高流量服务添加负载均衡机制,提高服务的并发处理能力 3. **容器化部署**:结合 Docker 容器化技术,提高服务的可移植性和一致性 4. **CI/CD 集成**:实现代码提交到服务部署的自动化流程,提高开发效率 5. **监控系统**:集成 Prometheus + Grafana 等监控系统,提供更全面的服务监控 ### 8.4 实施建议 1. **分阶段实施**:先在测试环境验证方案的可行性,再逐步推广到生产环境 2. **培训与文档**:为运维人员提供详细的培训和文档,确保方案的正确实施 3. **持续优化**:根据实际运行情况,持续优化服务管理方案 4. **风险评估**:在实施前进行充分的风险评估,制定应对措施 通过本方案的实施,您可以构建一个高效、可靠、易管理的多独立 AI 算法服务管理系统,为算法的开发、部署和运行提供有力的支持。