注册服务

This commit is contained in:
2026-02-09 23:59:25 +08:00
parent f145df4fa6
commit 3c03777b97
11 changed files with 865 additions and 456 deletions

View File

@@ -5,6 +5,9 @@ import json
import time
import docker
import uuid
import subprocess
import signal
import psutil
from typing import Dict, Any, Optional
from docker.errors import DockerException, NotFound
@@ -12,17 +15,28 @@ from docker.errors import DockerException, NotFound
class ServiceOrchestrator:
"""服务编排服务"""
def __init__(self):
"""初始化服务编排器"""
try:
# 连接Docker客户端
self.client = docker.from_env()
# 测试连接
self.client.ping()
print("Docker连接成功")
except DockerException as e:
print(f"Docker连接失败: {e}")
def __init__(self, deployment_mode="local"):
"""初始化服务编排器
Args:
deployment_mode: 部署模式,支持"docker""local"
"""
self.deployment_mode = deployment_mode
self.processes = {} # 存储本地进程信息
if deployment_mode == "docker":
try:
# 连接Docker客户端
self.client = docker.from_env()
# 测试连接
self.client.ping()
print("Docker连接成功")
except DockerException as e:
print(f"Docker连接失败: {e}")
self.client = None
else:
self.client = None
print("使用本地进程部署模式")
def deploy_service(self, service_id: str, service_config: Dict[str, Any], project_info: Dict[str, Any]) -> Dict[str, Any]:
"""部署服务
@@ -36,44 +50,78 @@ class ServiceOrchestrator:
部署结果
"""
try:
if not self.client:
if self.deployment_mode == "docker":
if not self.client:
return {
"success": False,
"error": "Docker连接失败",
"service_id": service_id,
"container_id": None,
"status": "error",
"api_url": None
}
# 1. 构建Docker镜像
image_name = self._build_docker_image(service_id, project_info, service_config)
# 2. 启动服务容器
container_id = self._start_service_container(service_id, image_name, service_config)
# 3. 验证服务启动
if not self._verify_service_startup(container_id, service_config):
return {
"success": False,
"error": "服务启动验证失败",
"service_id": service_id,
"container_id": container_id,
"status": "error",
"api_url": None
}
# 4. 构建API URL
api_url = f"http://{service_config.get('host', 'localhost')}:{service_config.get('port', 8000)}"
return {
"success": False,
"error": "Docker连接失败",
"service_id": service_id,
"container_id": None,
"status": "error",
"api_url": None
}
# 1. 构建Docker镜像
image_name = self._build_docker_image(service_id, project_info, service_config)
# 2. 启动服务容器
container_id = self._start_service_container(service_id, image_name, service_config)
# 3. 验证服务启动
if not self._verify_service_startup(container_id, service_config):
return {
"success": False,
"error": "服务启动验证失败",
"success": True,
"service_id": service_id,
"container_id": container_id,
"status": "error",
"api_url": None
"status": "running",
"api_url": api_url,
"error": None
}
else:
# 本地进程部署
# 1. 创建服务目录
service_dir = self._create_service_directory(service_id)
# 2. 生成服务包装器
self._generate_local_service_wrapper(service_dir, project_info, service_config)
# 3. 启动服务进程
process_info = self._start_local_service_process(service_id, service_dir, project_info, service_config)
# 4. 验证服务启动
if not self._verify_local_service_startup(service_id, service_config):
return {
"success": False,
"error": "服务启动验证失败",
"service_id": service_id,
"container_id": None,
"status": "error",
"api_url": None
}
# 5. 构建API URL
api_url = f"http://{service_config.get('host', 'localhost')}:{service_config.get('port', 8000)}"
return {
"success": True,
"service_id": service_id,
"container_id": service_id, # 使用服务ID作为容器ID
"status": "running",
"api_url": api_url,
"error": None
}
# 4. 构建API URL
api_url = f"http://{service_config.get('host', 'localhost')}:{service_config.get('port', 8000)}"
return {
"success": True,
"service_id": service_id,
"container_id": container_id,
"status": "running",
"api_url": api_url,
"error": None
}
except Exception as e:
return {
"success": False,
@@ -95,35 +143,85 @@ class ServiceOrchestrator:
启动结果
"""
try:
if not self.client:
if self.deployment_mode == "docker":
if not self.client:
return {
"success": False,
"error": "Docker连接失败",
"service_id": service_id,
"status": "error"
}
# 获取容器
container = self.client.containers.get(container_id)
# 启动容器
container.start()
# 验证服务启动
if not self._verify_service_health(container_id):
return {
"success": False,
"error": "服务健康检查失败",
"service_id": service_id,
"status": "error"
}
return {
"success": False,
"error": "Docker连接失败",
"success": True,
"service_id": service_id,
"status": "error"
"status": "running",
"error": None
}
# 获取容器
container = self.client.containers.get(container_id)
# 启动容器
container.start()
# 验证服务启动
if not self._verify_service_health(container_id):
else:
# 本地进程启动
if service_id not in self.processes:
return {
"success": False,
"error": "服务不存在",
"service_id": service_id,
"status": "error"
}
process_info = self.processes[service_id]
# 检查进程是否已经在运行
if process_info.get("pid"):
try:
process = psutil.Process(process_info["pid"])
if process.is_running():
return {
"success": True,
"service_id": service_id,
"status": "running",
"error": None
}
except:
pass
# 重新启动进程
service_dir = process_info["service_dir"]
project_info = process_info["project_info"]
service_config = process_info["service_config"]
# 启动服务进程
new_process_info = self._start_local_service_process(service_id, service_dir, project_info, service_config)
# 验证服务启动
if not self._verify_local_service_startup(service_id, service_config):
return {
"success": False,
"error": "服务启动验证失败",
"service_id": service_id,
"status": "error"
}
return {
"success": False,
"error": "服务健康检查失败",
"success": True,
"service_id": service_id,
"status": "error"
"status": "running",
"error": None
}
return {
"success": True,
"service_id": service_id,
"status": "running",
"error": None
}
except NotFound:
return {
"success": False,
@@ -150,26 +248,58 @@ class ServiceOrchestrator:
停止结果
"""
try:
if not self.client:
if self.deployment_mode == "docker":
if not self.client:
return {
"success": False,
"error": "Docker连接失败",
"service_id": service_id,
"status": "error"
}
# 获取容器
container = self.client.containers.get(container_id)
# 停止容器
container.stop(timeout=30)
return {
"success": False,
"error": "Docker连接失败",
"success": True,
"service_id": service_id,
"status": "error"
"status": "stopped",
"error": None
}
else:
# 本地进程停止
if service_id not in self.processes:
return {
"success": False,
"error": "服务不存在",
"service_id": service_id,
"status": "error"
}
process_info = self.processes[service_id]
# 停止进程
if process_info.get("pid"):
try:
process = psutil.Process(process_info["pid"])
if process.is_running():
process.terminate()
process.wait(timeout=30)
except:
pass
# 更新进程状态
self.processes[service_id]["pid"] = None
return {
"success": True,
"service_id": service_id,
"status": "stopped",
"error": None
}
# 获取容器
container = self.client.containers.get(container_id)
# 停止容器
container.stop(timeout=30)
return {
"success": True,
"service_id": service_id,
"status": "stopped",
"error": None
}
except NotFound:
return {
"success": False,
@@ -196,35 +326,81 @@ class ServiceOrchestrator:
重启结果
"""
try:
if not self.client:
if self.deployment_mode == "docker":
if not self.client:
return {
"success": False,
"error": "Docker连接失败",
"service_id": service_id,
"status": "error"
}
# 获取容器
container = self.client.containers.get(container_id)
# 重启容器
container.restart(timeout=30)
# 验证服务启动
if not self._verify_service_health(container_id):
return {
"success": False,
"error": "服务健康检查失败",
"service_id": service_id,
"status": "error"
}
return {
"success": False,
"error": "Docker连接失败",
"success": True,
"service_id": service_id,
"status": "error"
"status": "running",
"error": None
}
# 获取容器
container = self.client.containers.get(container_id)
# 重启容器
container.restart(timeout=30)
# 验证服务启动
if not self._verify_service_health(container_id):
else:
# 本地进程重启
if service_id not in self.processes:
return {
"success": False,
"error": "服务不存在",
"service_id": service_id,
"status": "error"
}
process_info = self.processes[service_id]
# 停止当前进程
if process_info.get("pid"):
try:
process = psutil.Process(process_info["pid"])
if process.is_running():
process.terminate()
process.wait(timeout=30)
except:
pass
# 重新启动进程
service_dir = process_info["service_dir"]
project_info = process_info["project_info"]
service_config = process_info["service_config"]
# 启动服务进程
new_process_info = self._start_local_service_process(service_id, service_dir, project_info, service_config)
# 验证服务启动
if not self._verify_local_service_startup(service_id, service_config):
return {
"success": False,
"error": "服务启动验证失败",
"service_id": service_id,
"status": "error"
}
return {
"success": False,
"error": "服务健康检查失败",
"success": True,
"service_id": service_id,
"status": "error"
"status": "running",
"error": None
}
return {
"success": True,
"service_id": service_id,
"status": "running",
"error": None
}
except NotFound:
return {
"success": False,
@@ -252,34 +428,72 @@ class ServiceOrchestrator:
删除结果
"""
try:
if not self.client:
if self.deployment_mode == "docker":
if not self.client:
return {
"success": False,
"error": "Docker连接失败",
"service_id": service_id
}
# 停止并删除容器
if container_id:
try:
container = self.client.containers.get(container_id)
container.stop(timeout=10)
container.remove(force=True)
except NotFound:
pass
# 删除镜像
if image_name:
try:
self.client.images.remove(image_name, force=True)
except:
pass
return {
"success": False,
"error": "Docker连接失败",
"service_id": service_id
"success": True,
"service_id": service_id,
"error": None
}
# 停止并删除容器
if container_id:
else:
# 本地进程删除
if service_id not in self.processes:
return {
"success": False,
"error": "服务不存在",
"service_id": service_id
}
process_info = self.processes[service_id]
# 停止进程
if process_info.get("pid"):
try:
process = psutil.Process(process_info["pid"])
if process.is_running():
process.terminate()
process.wait(timeout=30)
except:
pass
# 删除服务目录
service_dir = process_info["service_dir"]
try:
container = self.client.containers.get(container_id)
container.stop(timeout=10)
container.remove(force=True)
except NotFound:
pass
# 删除镜像
if image_name:
try:
self.client.images.remove(image_name, force=True)
import shutil
shutil.rmtree(service_dir)
except:
pass
return {
"success": True,
"service_id": service_id,
"error": None
}
# 从进程列表中删除
del self.processes[service_id]
return {
"success": True,
"service_id": service_id,
"error": None
}
except Exception as e:
return {
"success": False,
@@ -297,34 +511,78 @@ class ServiceOrchestrator:
服务状态
"""
try:
if not self.client:
if self.deployment_mode == "docker":
if not self.client:
return {
"success": False,
"error": "Docker连接失败",
"status": "unknown",
"health": "unknown"
}
# 获取容器
container = self.client.containers.get(container_id)
# 获取容器状态
status = container.status
# 检查服务健康状态
health = "unknown"
if status == "running":
if self._verify_service_health(container_id):
health = "healthy"
else:
health = "unhealthy"
return {
"success": False,
"error": "Docker连接失败",
"status": "unknown",
"health": "unknown"
"success": True,
"status": status,
"health": health,
"error": None
}
# 获取容器
container = self.client.containers.get(container_id)
# 获取容器状态
status = container.status
# 检查服务健康状态
health = "unknown"
if status == "running":
if self._verify_service_health(container_id):
health = "healthy"
else:
# 本地进程状态查询
# 假设container_id就是service_id
service_id = container_id
if service_id not in self.processes:
return {
"success": False,
"error": "服务不存在",
"status": "not_found",
"health": "unknown"
}
process_info = self.processes[service_id]
# 检查进程状态
status = "unknown"
health = "unknown"
if process_info.get("pid"):
try:
process = psutil.Process(process_info["pid"])
if process.is_running():
status = "running"
# 检查服务健康状态
service_config = process_info["service_config"]
if self._verify_local_service_health(service_id, service_config):
health = "healthy"
else:
health = "unhealthy"
else:
status = "stopped"
except:
status = "stopped"
else:
health = "unhealthy"
return {
"success": True,
"status": status,
"health": health,
"error": None
}
status = "stopped"
return {
"success": True,
"status": status,
"health": health,
"error": None
}
except NotFound:
return {
"success": False,
@@ -351,24 +609,63 @@ class ServiceOrchestrator:
服务日志
"""
try:
if not self.client:
if self.deployment_mode == "docker":
if not self.client:
return {
"success": False,
"error": "Docker连接失败",
"logs": []
}
# 获取容器
container = self.client.containers.get(container_id)
# 获取日志
logs = container.logs(tail=lines).decode('utf-8').split('\n')
return {
"success": False,
"error": "Docker连接失败",
"logs": []
"success": True,
"logs": logs,
"error": None
}
else:
# 本地进程日志获取
# 假设container_id就是service_id
service_id = container_id
if service_id not in self.processes:
return {
"success": False,
"error": "服务不存在",
"logs": []
}
process_info = self.processes[service_id]
# 获取日志文件路径
log_file = process_info.get("log_file")
if not log_file or not os.path.exists(log_file):
return {
"success": True,
"logs": [],
"error": None
}
# 读取日志文件
try:
with open(log_file, 'r') as f:
logs = f.readlines()
# 只返回最后lines行
logs = [line.rstrip('\n') for line in logs[-lines:]]
except:
logs = []
return {
"success": True,
"logs": logs,
"error": None
}
# 获取容器
container = self.client.containers.get(container_id)
# 获取日志
logs = container.logs(tail=lines).decode('utf-8').split('\n')
return {
"success": True,
"logs": logs,
"error": None
}
except NotFound:
return {
"success": False,
@@ -960,3 +1257,135 @@ json
}
with open(os.path.join(build_context, "package.json"), "w") as f:
json.dump(package_data, f, indent=2)
def _create_service_directory(self, service_id: str) -> str:
"""创建服务目录
Args:
service_id: 服务ID
Returns:
服务目录路径
"""
service_dir = os.path.join("/tmp", f"algorithm-service-{service_id}")
os.makedirs(service_dir, exist_ok=True)
return service_dir
def _generate_local_service_wrapper(self, service_dir: str, project_info: Dict[str, Any], service_config: Dict[str, Any]):
"""生成本地服务包装器
Args:
service_dir: 服务目录
project_info: 项目信息
service_config: 服务配置
"""
# 生成服务包装器
service_wrapper_content = self._generate_service_wrapper(project_info, service_config)
wrapper_extension = ".py" if project_info["project_type"] == "python" else ".js"
with open(os.path.join(service_dir, f"service_wrapper{wrapper_extension}"), "w") as f:
f.write(service_wrapper_content)
# 创建模拟的算法文件
algorithm_content = """
def predict(data):
return {"result": "Prediction result", "input": data}
def run(data):
return {"result": "Run result", "input": data}
def main(data):
return {"result": "Main result", "input": data}
"""
with open(os.path.join(service_dir, "algorithm.py"), "w") as f:
f.write(algorithm_content)
def _start_local_service_process(self, service_id: str, service_dir: str, project_info: Dict[str, Any], service_config: Dict[str, Any]) -> Dict[str, Any]:
"""启动本地服务进程
Args:
service_id: 服务ID
service_dir: 服务目录
project_info: 项目信息
service_config: 服务配置
Returns:
进程信息
"""
# 创建日志文件
log_file = os.path.join(service_dir, f"service_{service_id}.log")
# 构建启动命令
if project_info["project_type"] == "python":
cmd = ["python", f"service_wrapper.py"]
else:
cmd = ["node", f"service_wrapper.js"]
# 设置环境变量
env = os.environ.copy()
env["HOST"] = service_config.get("host", "0.0.0.0")
env["PORT"] = str(service_config.get("port", 8000))
env["TIMEOUT"] = str(service_config.get("timeout", 30))
# 启动进程
process = subprocess.Popen(
cmd,
cwd=service_dir,
env=env,
stdout=open(log_file, "a"),
stderr=subprocess.STDOUT,
start_new_session=True
)
# 保存进程信息
process_info = {
"pid": process.pid,
"service_dir": service_dir,
"log_file": log_file,
"project_info": project_info,
"service_config": service_config
}
self.processes[service_id] = process_info
return process_info
def _verify_local_service_startup(self, service_id: str, service_config: Dict[str, Any]) -> bool:
"""验证本地服务启动
Args:
service_id: 服务ID
service_config: 服务配置
Returns:
是否启动成功
"""
# 等待服务启动
time.sleep(5)
# 验证服务健康状态
return self._verify_local_service_health(service_id, service_config)
def _verify_local_service_health(self, service_id: str, service_config: Dict[str, Any]) -> bool:
"""验证本地服务健康状态
Args:
service_id: 服务ID
service_config: 服务配置
Returns:
是否健康
"""
try:
import requests
# 构建健康检查URL
host = service_config.get("host", "localhost")
port = service_config.get("port", 8000)
health_check_url = f"http://{host}:{port}/health"
# 发送健康检查请求
response = requests.get(health_check_url, timeout=10)
return response.status_code == 200
except:
return False