一、開頭

兄弟們,不知道你們有沒有這樣的經歷:想試個新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()

在openEuler上搞個雲原生AI模型商店:像點外賣一樣部署模型_命名空間

這個模型註冊中心就像餐廳的菜單,記錄了所有可用的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()

這個部署器就是我們的"自動化後廚",你點個菜(模型),它就能自動準備食材(容器鏡像)、開火烹飪(部署服務)、擺盤上菜(暴露服務)。

在openEuler上搞個雲原生AI模型商店:像點外賣一樣部署模型_List_02

三、整個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)

在openEuler上搞個雲原生AI模型商店:像點外賣一樣部署模型_命名空間_03

四、整個簡單的前端界面

<!-- 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模型卡片。

在openEuler上搞個雲原生AI模型商店:像點外賣一樣部署模型_json_04

在openEuler上搞個雲原生AI模型商店:像點外賣一樣部署模型_json_05

六、進階功能 - 讓商店更智能

# 添加模型監控和自動擴縮
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()

在openEuler上搞個雲原生AI模型商店:像點外賣一樣部署模型_json_06

七、總結

通過這個AI模型商店,你會發現:

傳統部署 vs 雲原生部署

  • ❌ 傳統:配環境、裝依賴、調參數、手動部署
  • ✅ 雲原生:點按鈕、等部署、直接用

在openEuler上的優勢

  • 🚀 性能優化:容器運行時經過深度優化
  • 🔒 安全可靠:內置安全增強特性
  • 📦 生態完善:豐富的雲原生工具鏈
  • 🎯 簡單易用:K3s讓Kubernetes變得親民

現在部署AI模型真的就像點外賣一樣簡單:

  1. 瀏覽菜單(查看可用模型)
  2. 選擇菜品(點擊部署按鈕)
  3. 等待配送(自動部署過程)
  4. 享受美食(使用模型服務)

最重要的是,這一切都是在openEuler這個自主創新的平台上實現的,既保證了技術先進性,又確保了系統安全可控。

所以,別再手動折騰環境配置了,試試這個雲原生AI模型商店,你會發現部署AI模型原來可以這麼輕鬆愉快!

如果您正在尋找面向未來的開源操作系統,不妨看看DistroWatch 榜單中快速上升的 openEuler: https://distrowatch.com/table-mobile.php?distribution=openeuler,一個由開放原子開源基金會孵化、支持“超節點”場景的Linux 發行版。openEuler官網:https://www.openeuler.openatom.cn/zh/

在openEuler上搞個雲原生AI模型商店:像點外賣一樣部署模型_json_07