一、開頭
兄弟們,不知道你們有沒有這樣的經歷:想試個新AI模型,結果光環境配置就搞了半天。Python版本不對、依賴衝突、CUDA版本不匹配...每次部署都像在拆炸彈,不知道哪步會炸。 直到我在openEuler上發現了雲原生的正確打開方式——現在部署AI模型就跟點外賣一樣簡單:選模型、點部署、等上菜。今天我就帶你整一個AI模型商店,讓你體驗一下什麼叫"科技改變生活"。
二、先整個基礎框架 - 模型商店的門面
2.1 模型註冊中心 - 就像餐廳的菜單
# model_registry.py
from typing import Dict, List, Optional
from dataclasses import dataclass
import yaml
import json
@dataclass
class ModelInfo:
"""模型信息,就像菜單上的菜品描述"""
name: str # 模型名
version: str # 版本號
description: str # 描述
image: str # 容器鏡像地址
framework: str # 框架類型
inputs: List[str] # 輸入格式
outputs: List[str] # 輸出格式
def to_dict(self):
return {
'name': self.name,
'version': self.version,
'description': self.description,
'image': self.image,
'framework': self.frame work,
'inputs': self.inputs,
'outputs': self.outputs
}
class ModelRegistry:
"""模型註冊中心 - 管理所有可用的模型"""
def __init__(self):
self.models: Dict[str, ModelInfo] = {}
self._load_default_models()
def _load_default_models(self):
"""預加載一些常用模型,就像餐廳的招牌菜"""
default_models = [
ModelInfo(
name="sentiment-analysis",
version="1.0",
description="情感分析模型,能判斷文本情感傾向",
image="registry.example.com/sentiment:v1.0",
framework="pytorch",
inputs=["text"],
outputs=["sentiment", "confidence"]
),
ModelInfo(
name="image-classification",
version="2.1",
description="圖像分類模型,支持1000個類別",
image="registry.example.com/classification:v2.1",
framework="tensorflow",
inputs=["image"],
outputs=["class", "confidence"]
),
ModelInfo(
name="text-generation",
version="1.5",
description="文本生成模型,能寫文章、對話",
image="registry.example.com/gpt:v1.5",
framework="pytorch",
inputs=["prompt"],
outputs=["generated_text"]
)
]
for model in default_models:
key = f"{model.name}-{model.version}"
self.models[key] = model
def list_models(self) -> List[dict]:
"""列出所有可用模型"""
return [model.to_dict() for model in self.models.values()]
def get_model(self, name: str, version: str) -> Optional[ModelInfo]:
"""根據名稱和版本獲取模型信息"""
key = f"{name}-{version}"
return self.models.get(key)
def register_model(self, model_info: ModelInfo):
"""註冊新模型"""
key = f"{model_info.name}-{model_info.version}"
self.models[key] = model_info
print(f"✅ 模型註冊成功: {model_info.name} v{model_info.version}")
# 初始化模型商店
model_store = ModelRegistry()
這個模型註冊中心就像餐廳的菜單,記錄了所有可用的AI模型。每個模型都有詳細的描述,讓用户知道這個模型能做什麼、需要什麼輸入、會輸出什麼。
2.2 一鍵部署器 - 後廚自動化系統
# deployer.py
import subprocess
import tempfile
import os
from typing import Dict, Any
class ModelDeployer:
"""模型部署器 - 負責把模型部署到Kubernetes"""
def __init__(self, namespace: str = "ai-models"):
self.namespace = namespace
self._ensure_namespace()
def _ensure_namespace(self):
"""確保命名空間存在"""
try:
subprocess.run([
"kubectl", "create", "namespace", self.namespace
], capture_output=True, check=False)
print(f"📁 使用命名空間: {self.namespace}")
except Exception as e:
print(f"⚠️ 命名空間檢查失敗: {e}")
def generate_deployment_yaml(self, model_info, deployment_name: str) -> str:
"""生成Kubernetes部署文件"""
deployment = {
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": deployment_name,
"namespace": self.namespace,
"labels": {
"app": model_info.name,
"version": model_info.version
}
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"app": model_info.name
}
},
"template": {
"metadata": {
"labels": {
"app": model_info.name
}
},
"spec": {
"containers": [{
"name": model_info.name,
"image": model_info.image,
"ports": [{
"containerPort": 8080
}],
"env": [
{
"name": "MODEL_NAME",
"value": model_info.name
},
{
"name": "MODEL_VERSION",
"value": model_info.version
}
],
"resources": {
"requests": {
"memory": "512Mi",
"cpu": "250m"
},
"limits": {
"memory": "1Gi",
"cpu": "500m"
}
},
"livenessProbe": {
"httpGet": {
"path": "/health",
"port": 8080
},
"initialDelaySeconds": 30,
"periodSeconds": 10
},
"readinessProbe": {
"httpGet": {
"path": "/health",
"port": 8080
},
"initialDelaySeconds": 5,
"periodSeconds": 5
}
}]
}
}
}
}
service = {
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": f"{deployment_name}-service",
"namespace": self.namespace
},
"spec": {
"selector": {
"app": model_info.name
},
"ports": [{
"port": 80,
"targetPort": 8080
}],
"type": "ClusterIP"
}
}
return yaml.dump_all([deployment, service], default_flow_style=False)
def deploy_model(self, model_info, deployment_name: str) -> bool:
"""部署模型到Kubernetes"""
try:
print(f"🚀 開始部署模型: {model_info.name} v{model_info.version}")
# 生成部署文件
yaml_content = self.generate_deployment_yaml(model_info, deployment_name)
# 創建臨時文件並應用
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
f.write(yaml_content)
temp_file = f.name
# 執行部署命令
result = subprocess.run([
"kubectl", "apply", "-f", temp_file
], capture_output=True, text=True, check=True)
# 清理臨時文件
os.unlink(temp_file)
print(f"✅ 模型部署成功: {deployment_name}")
print(f"📊 部署狀態: {result.stdout}")
return True
except subprocess.CalledProcessError as e:
print(f"❌ 部署失敗: {e.stderr}")
return False
except Exception as e:
print(f"💥 部署過程出錯: {e}")
return False
def check_deployment_status(self, deployment_name: str) -> Dict[str, Any]:
"""檢查部署狀態"""
try:
# 檢查Deployment狀態
result = subprocess.run([
"kubectl", "get", "deployment", deployment_name,
"-n", self.namespace, "-o", "json"
], capture_output=True, text=True, check=True)
status = json.loads(result.stdout)
# 檢查Pod狀態
pods_result = subprocess.run([
"kubectl", "get", "pods",
"-n", self.namespace,
"-l", f"app={deployment_name}",
"-o", "json"
], capture_output=True, text=True, check=True)
pods_status = json.loads(pods_result.stdout)
return {
"deployment": status,
"pods": pods_status
}
except Exception as e:
return {"error": str(e)}
# 初始化部署器
deployer = ModelDeployer()
這個部署器就是我們的"自動化後廚",你點個菜(模型),它就能自動準備食材(容器鏡像)、開火烹飪(部署服務)、擺盤上菜(暴露服務)。
三、整個Web界面 - 讓點菜變得更簡單
# app.py
from flask import Flask, render_template, request, jsonify, session
import uuid
import time
app = Flask(__name__)
app.secret_key = 'your-secret-key-here'
@app.route('/')
def index():
"""模型商店首頁"""
models = model_store.list_models()
return render_template('index.html', models=models)
@app.route('/api/models')
def list_models_api():
"""獲取模型列表API"""
models = model_store.list_models()
return jsonify({"models": models})
@app.route('/model/<name>/<version>')
def model_detail(name, version):
"""模型詳情頁面"""
model = model_store.get_model(name, version)
if not model:
return "Model not found", 404
return render_template('model_detail.html', model=model.to_dict())
@app.route('/api/deploy', methods=['POST'])
def deploy_model():
"""部署模型API"""
data = request.json
model_name = data.get('name')
model_version = data.get('version')
deployment_name = data.get('deployment_name', f"{model_name}-{str(uuid.uuid4())[:8]}")
# 獲取模型信息
model = model_store.get_model(model_name, model_version)
if not model:
return jsonify({"error": "Model not found"}), 404
# 執行部署
success = deployer.deploy_model(model, deployment_name)
if success:
return jsonify({
"success": True,
"deployment_name": deployment_name,
"message": "模型部署成功"
})
else:
return jsonify({
"success": False,
"message": "模型部署失敗"
}), 500
@app.route('/api/status/<deployment_name>')
def get_deployment_status(deployment_name):
"""獲取部署狀態"""
status = deployer.check_deployment_status(deployment_name)
return jsonify(status)
@app.route('/api/test/<model_name>')
def test_model(model_name):
"""測試模型API(簡化版)"""
# 這裏應該是實際的模型調用邏輯
# 為了演示,我們返回模擬結果
test_results = {
"sentiment-analysis": {
"input": "這個產品真的很棒,我非常喜歡!",
"output": {
"sentiment": "positive",
"confidence": 0.95
}
},
"image-classification": {
"input": "cat_image.jpg",
"output": {
"class": "cat",
"confidence": 0.89
}
},
"text-generation": {
"input": "請寫一段關於AI的短文",
"output": {
"generated_text": "人工智能正在改變世界..."
}
}
}
result = test_results.get(model_name, {"error": "Test not available"})
return jsonify(result)
if __name__ == '__main__':
print("🎉 AI模型商店啓動成功!")
print("📍 訪問地址: http://localhost:5000")
print("📚 可用模型:", len(model_store.list_models()))
app.run(host='0.0.0.0', port=5000, debug=True)
四、整個簡單的前端界面
<!-- templates/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>AI模型商店 - 像點外賣一樣部署模型</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.model-card {
border: 1px solid #ddd;
padding: 20px;
margin: 10px;
border-radius: 8px;
display: inline-block;
width: 300px;
vertical-align: top;
}
.model-card h3 { color: #333; margin-top: 0; }
.btn {
background: #007bff;
color: white;
padding: 10px 15px;
border: none;
border-radius: 4px;
cursor: pointer;
text-decoration: none;
display: inline-block;
}
.btn:hover { background: #0056b3; }
.status { padding: 5px 10px; border-radius: 3px; }
.status-deploying { background: #fff3cd; color: #856404; }
.status-running { background: #d1ecf1; color: #0c5460; }
</style>
</head>
<body>
<h1>🤖 AI模型商店</h1>
<p>選擇你需要的AI模型,一鍵部署到openEuler雲原生環境</p>
<div id="models-container">
{% for model in models %}
<div class="model-card">
<h3>{{ model.name }} v{{ model.version }}</h3>
<p>{{ model.description }}</p>
<p><strong>框架:</strong> {{ model.framework }}</p>
<p><strong>輸入:</strong> {{ model.inputs | join(', ') }}</p>
<p><strong>輸出:</strong> {{ model.outputs | join(', ') }}</p>
<div style="margin-top: 15px;">
<button class="btn" onclick="deployModel('{{ model.name }}', '{{ model.version }}')">
🚀 一鍵部署
</button>
<a href="/model/{{ model.name }}/{{ model.version }}" class="btn" style="background: #6c757d;">
📖 查看詳情
</a>
</div>
<div id="status-{{ model.name }}-{{ model.version }}" style="margin-top: 10px;"></div>
</div>
{% endfor %}
</div>
<script>
async function deployModel(name, version) {
const statusDiv = document.getElementById(`status-${name}-${version}`);
statusDiv.innerHTML = '<div class="status status-deploying">部署中...</div>';
try {
const response = await fetch('/api/deploy', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: name,
version: version
})
});
const result = await response.json();
if (result.success) {
statusDiv.innerHTML = '<div class="status status-running">✅ 部署成功!</div>';
// 可以在這裏添加更多交互,比如查看服務狀態、測試模型等
setTimeout(() => {
testModel(name);
}, 2000);
} else {
statusDiv.innerHTML = '<div style="color: red;">❌ 部署失敗: ' + result.message + '</div>';
}
} catch (error) {
statusDiv.innerHTML = '<div style="color: red;">💥 請求失敗: ' + error + '</div>';
}
}
async function testModel(name) {
try {
const response = await fetch(`/api/test/${name}`);
const result = await response.json();
console.log('測試結果:', result);
alert(`模型測試完成!\n輸入: ${result.input}\n輸出: ${JSON.stringify(result.output)}`);
} catch (error) {
console.error('測試失敗:', error);
}
}
</script>
</body>
</html>
五、實際運行效果
當你運行這個系統時,會看到這樣的輸出:打開瀏覽器訪問 http://localhost:5000,你會看到一個漂亮的模型商店界面,裏面有各種AI模型卡片。
六、進階功能 - 讓商店更智能
# 添加模型監控和自動擴縮
class SmartModelManager:
"""智能模型管理器"""
def __init__(self):
self.deployments = {}
def setup_auto_scaling(self, deployment_name: str):
"""設置自動擴縮容"""
hpa_yaml = f"""
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {deployment_name}-hpa
namespace: ai-models
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {deployment_name}
minReplicas: 1
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
"""
# 應用HPA配置
with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml') as f:
f.write(hpa_yaml)
f.flush()
subprocess.run(["kubectl", "apply", "-f", f.name], check=True)
print(f"📈 已為 {deployment_name} 設置自動擴縮容")
def setup_monitoring(self, deployment_name: str):
"""設置監控"""
# 添加Prometheus監控註解
subprocess.run([
"kubectl", "annotate", "deployment", deployment_name,
"-n", "ai-models",
"prometheus.io/scrape=true",
"prometheus.io/port=8080"
], check=True)
print(f"📊 已為 {deployment_name} 設置監控")
# 使用智能管理器
smart_manager = SmartModelManager()
七、總結
通過這個AI模型商店,你會發現:
傳統部署 vs 雲原生部署
- ❌ 傳統:配環境、裝依賴、調參數、手動部署
- ✅ 雲原生:點按鈕、等部署、直接用
在openEuler上的優勢
- 🚀 性能優化:容器運行時經過深度優化
- 🔒 安全可靠:內置安全增強特性
- 📦 生態完善:豐富的雲原生工具鏈
- 🎯 簡單易用:K3s讓Kubernetes變得親民
現在部署AI模型真的就像點外賣一樣簡單:
- 瀏覽菜單(查看可用模型)
- 選擇菜品(點擊部署按鈕)
- 等待配送(自動部署過程)
- 享受美食(使用模型服務)
最重要的是,這一切都是在openEuler這個自主創新的平台上實現的,既保證了技術先進性,又確保了系統安全可控。
所以,別再手動折騰環境配置了,試試這個雲原生AI模型商店,你會發現部署AI模型原來可以這麼輕鬆愉快!
如果您正在尋找面向未來的開源操作系統,不妨看看DistroWatch 榜單中快速上升的 openEuler: https://distrowatch.com/table-mobile.php?distribution=openeuler,一個由開放原子開源基金會孵化、支持“超節點”場景的Linux 發行版。openEuler官網:https://www.openeuler.openatom.cn/zh/