Ollama: نشر الإنتاج
نشر الإنتاج هو القفزة النهائية للذكاء الاصطناعي المحلي من المختبر إلى ساحة المعركة — متاحًا بشكل عالٍ، وقابلًا للتوسع، ومقاومًا للكوارث.
💡 نصيحة: وكيل Nginx العكسي + موازنة الحمل هو البنية القياسية لنشر الإنتاج — Nginx يتولى إنهاء SSL ومصادقة API Key وتحديد المعدل وتوزيع الحركة، بينما تحتاج عقد Ollama فقط الربط بـ 127.0.0.1. لعنقات متعددة، استراتيجية
least_conn (أقل اتصالات) مُوصى بها لأن مدة طلبات الاستنتاج تتفاوت بشكل كبير.
📋 المتطلبات المسبقة: يجب أن تتقن أولاً ما يلي
- الدرس 15: النشر الحاوي باستخدام دوكر
- الدرس 20: تعزيز الأمان
1. ما ستتعلمه
- تصميم بنية الإنتاج: موازنة الحمل + مجموعة عقد متعددة
- التوافر العالي: فحوصات الصحة + التحويل التلقائي
- استراتيجيات التوسع: التوسع الأفقي القائم على الصفوف
- نشر Kubernetes: Helm Charts وجدولة GPU
- التعافي من الكوارث والاسترجاع: إدارة إصدارات النماذج والبنية ككود
2. قصة حقيقية من رائدة أعمال SaaS
💡 نصيحة: في بيئات الإنتاج، يجب أن تستخدم موازنة حمل Nginx استراتيجية
least_conn (أقل اتصالات) بدلاً من round_robin الافتراضي. مدة طلبات استنتاج Ollama تتفاوت بشكل كبير (الأسئلة القصيرة تستغرق ثانية واحدة، النصوص الطويلة تستغرق 30 ثانية)، وleast_conn يوزع الحمل بشكل أكثر تساويًا.
ℹ️ معلومة: Ollama لا يدعم وضع المجموعة بشكل أصلي (بدون مزامنة رئيسي-تابع، بدون استنتاج موزع). اتساق النماذج وارتباط الجلسة لمجموعات العقد المتعددة يجب تنفيذه في الطبقة العليا (Nginx/FastAPI). هذا ينطبق أيضًا على نشر Kubernetes.
(1) المشكلة: نقطة الفشل الواحدة تسبب انقطاع الخدمة الكلي
يعمل SupportBot الخاص بـ Alice على خادم Ollama واحد. صيانة الخادم أو OOM في GPU يتسبب في انقطاع الخدمة، مما يوقف نظام خدمة العملاء لمدة ساعتين ويؤثر على 500+ عميل.
(2) الحل: مجموعة عقد متعددة عالية التوافر
نشر مجموعة Ollama من 3 عقد + موازن حمل Nginx، مع تحويل تلقائي عند تعطل أي عقدة:
flowchart TD
A[موازن حمل Nginx] --> B[عقدة Ollama 1<br/>GPU 1]
A --> C[عقدة Ollama 2<br/>GPU 2]
A --> D[عقدة Ollama 3<br/>GPU 3]
3. تصميم بنية الإنتاج
⚠️ تحذير: في مجموعة العقد المتعددة، تدير كل عقدة Ollama نماذجها وحالتها بشكل مستقل — لا يوجد نسخ متماثل رئيسي-تابع كما في قواعد البيانات. النموذج المسحوب على العقدة A لن يتزامن تلقائيًا مع العقدة B. يجب ضمان اتساق النماذج عبر جميع العقد من خلال نص تهيئة موحد أو تخزين مشترك.
(1) عقدة واحدة مقابل عقد متعددة
| البُعد | عقدة واحدة | مجموعة عقد متعددة |
|---|---|---|
| التوافر | نقطة فشل واحدة | تحمل N-1 أعطال |
| الإنتاجية | محدودة | توسع خطي |
| التكلفة | منخفضة | عالية (3x+) |
| تعقيد التشغيل | منخفض | متوسط |
| حالة الاستخدام | تطوير/نطاق صغير | الإنتاج |
(2) نظرة عامة على بنية الإنتاج
flowchart TD
A[الإنترنت] --> B[WAF / CDN]
B --> C[Nginx<br/>SSL + مصادقة + موازنة حمل]
C --> D[عقدة Ollama 1<br/>GPU + نموذج]
C --> E[عقدة Ollama 2<br/>GPU + نموذج]
C --> F[عقدة Ollama 3<br/>GPU + نموذج]
D --> G[NFS / S3<br/>تخزين نماذج مشترك]
E --> G
F --> G
D --> H[مجموعة Chroma]
E --> H
F --> H
I[Prometheus] --> D
I --> E
I --> F
I --> J[لوحة Grafana]
(3) قائمة المكونات
| المكون | العدد | المواصفات | الغرض |
|---|---|---|---|
| موازن حمل Nginx | 1 | 2 vCPU، 4 جيجابايت RAM | موازنة الحمل + SSL |
| عقدة Ollama | 3 | 8 vCPU، 16 جيجابايت RAM، 1x RTX 4090 | استنتاج النموذج |
| Chroma | 1 | 4 vCPU، 8 جيجابايت RAM، SSD | التخزين المتجهي |
| NFS/S3 | 1 | 500 جيجابايت+ | تخزين نماذج مشترك |
| Prometheus | 1 | 2 vCPU، 4 جيجابايت RAM | المراقبة |
4. التوافر العالي
⚠️ ملاحظة: إعدادات شهادة SSL إلزامية للإنتاج — HTTPS لا يشفر النقل فحسب بل هو أيضًا شرط مسبق لمصادقة API Key (إرسال مفاتيح API بنص عادي عبر HTTP يعني عدم وجود أمان على الإطلاق). استخدم certbot لشهادات Let's Encrypt المجانية، أو Caddy لـ HTTPS التلقائي.
(1) فحوصات الصحة والتحويل
| الآلية | طريقة الفحص | الفاصل | المهلة |
|---|---|---|---|
| فحص Nginx السلبي | وضع علامة غير متاح عند فشل الطلب | كل طلب | 5 ثوانٍ |
| فحص صحة نشط | GET دوري /api/tags | 10 ثوانٍ | 3 ثوانٍ |
| فحص طبقة التطبيق | اختبار استنتاج مخصص | 30 ثانية | 10 ثوانٍ |
(1) ▶ مثال: إعدادات موازن حمل Nginx
NGINX
# /etc/nginx/conf.d/ollama-lb.conf
upstream ollama_cluster {
least_conn; # Route to least busy node
server ollama-node1:11434 max_fails=3 fail_timeout=30s;
server ollama-node2:11434 max_fails=3 fail_timeout=30s;
server ollama-node3:11434 max_fails=3 fail_timeout=30s;
}
server {
listen 443 ssl;
server_name ai.example.com;
ssl_certificate /etc/ssl/certs/ai.example.com.crt;
ssl_certificate_key /etc/ssl/private/ai.example.com.key;
location /v1/ {
# API Key authentication
if ($http_x_api_key != "your-secret-key") {
return 401 '{"error": "Unauthorized"}';
}
proxy_pass http://ollama_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_connect_timeout 5s;
proxy_read_timeout 120s;
# Rate limiting
limit_req zone=api burst=20 nodelay;
}
# Health check endpoint
location /health {
proxy_pass http://ollama_cluster/api/tags;
}
}
الإخراج:
TEXT
// Execution successful
(2) ▶ مثال: نص تحويل تلقائي
BASH
#!/bin/bash
# Ollama cluster health monitor
NODES=("ollama-node1:11434" "ollama-node2:11434" "ollama-node3:11434")
HEALTH_URL="/api/tags"
ALERT_EMAIL="ops@example.com"
check_node() {
local node=$1
if curl -sf --connect-timeout 3 "http://$node$HEALTH_URL" > /dev/null; then
echo "UP"
else
echo "DOWN"
fi
}
while true; do
for node in "${NODES[@]}"; do
status=$(check_node "$node")
if [ "$status" = "DOWN" ]; then
echo "ALERT: $node is DOWN at $(date)" >> /var/log/ollama_health.log
# Send alert
echo "Ollama node $node is DOWN" | mail -s "OLLAMA ALERT" "$ALERT_EMAIL" 2>/dev/null
fi
done
sleep 10
done
الإخراج:
TEXT
NAME ID SIZE
llama3.2:latest a80... 2.0 GB
mistral:latest 61... 4.1 GB
5. استراتيجيات التوسع
(1) شروط تشغيل التوسع
| المقياس | عتبة التوسع للأعلى | عتبة التوسع للأسفل | وقت الانتظار |
|---|---|---|---|
| زمن انتقال الطلبات P95 | > 5 ثوانٍ | < 2 ثانية | 5 دقائق |
| الاتصالات المتزامنة | > 80% من السعة | < 30% من السعة | 5 دقائق |
| استخدام GPU | > 85% | < 40% | 10 دقائق |
| طول الصف | > 10 | = 0 | 3 دقائق |
(2) مقارنة طرق التوسع
| الطريقة | السرعة | التكلفة | التعقيد |
|---|---|---|---|
| توسع يدوي | بطيء (ساعات) | قابل للتحكم | منخفض |
| نصوص تلقائية | متوسط (دقائق) | قابل للتحكم | متوسط |
| K8s HPA | سريع (ثوانٍ) | تلقائي | عالي |
(3) ▶ مثال: توسع تلقائي قائم على زمن الانتقال
PYTHON
import subprocess
import time
from typing import Optional
class AutoScaler:
def __init__(self, scale_up_threshold: float = 5.0,
scale_down_threshold: float = 2.0,
cooldown: int = 300):
self.scale_up_threshold = scale_up_threshold
self.scale_down_threshold = scale_down_threshold
self.cooldown = cooldown
self.last_scale_time = 0
def get_avg_latency(self) -> Optional[float]:
try:
result = subprocess.run(
["curl", "-sf", "http://localhost:11434/api/chat", "-d",
'{"model":"qwen2.5","messages":[{"role":"user","content":"hi"}],"stream":false}'],
capture_output=True, text=True, timeout=10
)
if result.returncode == 0:
import json
data = json.loads(result.stdout)
duration_ns = data.get("total_duration", 0)
return duration_ns / 1e9
except Exception:
pass
return None
def check_and_scale(self):
latency = self.get_avg_latency()
if latency is None:
return
now = time.time()
if now - self.last_scale_time < self.cooldown:
return
if latency > self.scale_up_threshold:
print(f"High latency ({latency:.1f}s), scaling up...")
self._scale_up()
self.last_scale_time = now
elif latency < self.scale_down_threshold:
print(f"Low latency ({latency:.1f}s), scaling down...")
self._scale_down()
self.last_scale_time = now
def _scale_up(self):
# Add new Ollama node (e.g., via Docker or cloud API)
print("Adding Ollama node...")
def _scale_down(self):
# Remove idle Ollama node
print("Removing idle Ollama node...")
# Usage
# scaler = AutoScaler()
# while True:
# scaler.check_and_scale()
# time.sleep(60)
الإخراج:
TEXT
Adding Ollama node...
Removing idle Ollama node...
6. نشر Kubernetes
(1) بنية نشر K8s
flowchart TD
A[Ingress<br/>nginx-ingress] --> B[Service<br/>ollama-svc]
B --> C[Deployment<br/>ollama-deploy<br/>3 نسخ]
C --> D[Pod 1<br/>GPU + نموذج]
C --> E[Pod 2<br/>GPU + نموذج]
C --> F[Pod 3<br/>GPU + نموذج]
G[PVC<br/>model-storage] --> D
G --> E
G --> F
(2) إعدادات جدولة GPU الرئيسية
| المورد | الإعدادات | الوصف |
|---|---|---|
| nvidia.com/gpu (requests) | طلب المورد | 1 GPU لكل Pod |
| nvidia.com/gpu (limits) | حد المورد | حد أقصى 1 GPU |
| nodeSelector | اختيار عقدة GPU | تحديد عقد GPU |
| tolerations | تحمل تلوث GPU | السماح بالجدولة على عقد GPU |
(4) ▶ مثال: نشر Ollama على K8s
YAML
# ollama-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ollama
labels:
app: ollama
spec:
replicas: 3
selector:
matchLabels:
app: ollama
template:
metadata:
labels:
app: ollama
spec:
nodeSelector:
gpu: "true"
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
containers:
- name: ollama
image: ollama/ollama
ports:
- containerPort: 11434
resources:
requests:
nvidia.com/gpu: 1
memory: "8Gi"
limits:
nvidia.com/gpu: 1
memory: "16Gi"
env:
- name: OLLAMA_HOST
value: "0.0.0.0:11434"
- name: OLLAMA_NUM_PARALLEL
value: "4"
- name: OLLAMA_KEEP_ALIVE
value: "30m"
volumeMounts:
- name: model-storage
mountPath: /root/.ollama
livenessProbe:
httpGet:
path: /api/tags
port: 11434
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /api/tags
port: 11434
initialDelaySeconds: 10
periodSeconds: 5
volumes:
- name: model-storage
persistentVolumeClaim:
claimName: ollama-models-pvc
---
apiVersion: v1
kind: Service
metadata:
name: ollama-svc
spec:
selector:
app: ollama
ports:
- port: 11434
targetPort: 11434
type: ClusterIP
الإخراج:
TEXT
K8s Deployment created successfully, Pods running normally
الإخراج:
TEXT
HPA auto-scaling configured successfully, cluster resource monitoring enabled
(5) ▶ مثال: توسع تلقائي HPA لـ K8s
YAML
# ollama-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ollama-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ollama
minReplicas: 2
maxReplicas: 6
metrics:
- type: Resource
resource:
name: nvidia.com/gpu
target:
type: Utilization
averageUtilization: 80
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Pods
value: 1
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 300
الإخراج:
TEXT
# HPA created successfully
kubectl get hpa ollama-hpa
# NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
# ollama-hpa Deployment/ollama 45%/80% 2 6 3 5m
7. التعافي من الكوارث والاسترجاع
(1) استراتيجيات التعافي من الكوارث
| الاستراتيجية | RTO | RPO | التكلفة |
|---|---|---|---|
| نشط-سلبي | 5-15 دقيقة | 0 | مضاعفة الأجهزة |
| نشط-نشط | 0 (تحويل تلقائي) | 0 | 3 أضعاف الأجهزة |
| استعداد بارد | 1-4 ساعات | مع فقدان | 1x + تخزين |
(2) البنية ككود
| المورد | طريقة إدارة الإصدارات |
|---|---|
| Modelfile | مستودع Git |
| Docker Compose | مستودع Git |
| K8s Manifests | Git + ArgoCD |
| إعدادات Nginx | مستودع Git |
| إصدارات النماذج | وسوم Ollama + توثيق |
8. مثال شامل: قائمة فحص نشر الإنتاج
PYTHON
# ============================================
# Comprehensive: Production deployment checklist
# Full verification before going live
# ============================================
PRODUCTION_CHECKLIST = {
"infrastructure": [
("Ollama nodes: 3+ replicas running", "CRITICAL"),
("GPU drivers: installed and verified", "CRITICAL"),
("Model storage: shared NFS/S3 mounted", "CRITICAL"),
("Network: internal VLAN for Ollama traffic", "HIGH"),
("DNS: ai.example.com resolves to LB", "HIGH"),
],
"security": [
("Ollama bound to 127.0.0.1 on each node", "CRITICAL"),
("Nginx SSL certificate valid", "CRITICAL"),
("API Key authentication enabled", "CRITICAL"),
("Rate limiting configured (60 req/min)", "HIGH"),
("WAF rules in place", "MEDIUM"),
],
"high_availability": [
("Health checks configured (Nginx + app layer)", "CRITICAL"),
("Failover tested: kill 1 node, service continues", "CRITICAL"),
("Load balancer: least_conn algorithm", "HIGH"),
("Session affinity: disabled (stateless)", "HIGH"),
],
"monitoring": [
("Prometheus scraping all nodes", "HIGH"),
("Grafana dashboards created", "HIGH"),
("Alert rules: GPU OOM, high latency, service down", "CRITICAL"),
("Log aggregation: Loki or ELK", "MEDIUM"),
],
"disaster_recovery": [
("Config in Git (Modelfile, Compose, K8s)", "HIGH"),
("Model backup: GGUF files on S3/NFS", "HIGH"),
("Chroma data backup: daily snapshot", "HIGH"),
("Recovery drill: tested within last 30 days", "MEDIUM"),
],
"performance": [
("Baseline benchmark recorded", "HIGH"),
("OLLAMA_NUM_PARALLEL configured", "HIGH"),
("OLLAMA_KEEP_ALIVE=30m set", "MEDIUM"),
("num_ctx per endpoint optimized", "MEDIUM"),
]
}
def run_checklist() -> str:
report = ["# Production Deployment Checklist\n"]
total = 0
checked = 0
for category, items in PRODUCTION_CHECKLIST.items():
report.append(f"\n## {category.replace('_', ' ').title()}")
for item, priority in items:
total += 1
report.append(f"- [ ] [{priority}] {item}")
report.append(f"\n---\nTotal items: {total}")
return "\n".join(report)
print(run_checklist())
❓ أسئلة شائعة
س ما هو الحد الأدنى لوحدات GPU لمجموعة 3 عقد؟
ج الحد الأدنى 3 (واحدة لكل عقدة). إذا كان الميزانية محدودة، إعداد عقدتين (1 رئيسية + 1 احتياطية) يعمل، لكن الإنتاجية تنخفض للنصف أثناء التحويل.
س هل كل آلة تحتاج سحب ملفات النماذج؟
ج إذا استخدمت تخزينًا مشتركًا (NFS)، اسحب مرة واحدة فقط. إذا استخدمت تخزينًا محليًا، كل آلة تحتاج السحب. NFS مشترك + تخزين مؤقت محلي مُوصى به.
س هل أختار Kubernetes أم Docker Compose؟
ج Docker Compose لـ < 5 عقد (أبسط). Kubernetes لـ > 5 عقد أو عند الحاجة للتوسع التلقائي. Docker Compose يكفي لمعظم السيناريوهات.
س كيف أختبر التحويل؟
ج أوقف عقدة Ollama يدويًا (docker stop أو systemctl stop)، وتحقق أن Nginx يوجه الحركة تلقائيًا إلى العقد الأخرى بدون تأثير على المستخدم.
س هل لدى Ollama وضع مجموعة مدمج؟
ج لا. Ollama خدمة أحادية المثيل؛ المجموعات تتطلب تركيبة موازن حمل خارجي. كل مثيل Ollama يعمل بشكل مستقل؛ Nginx يتولى توزيع الطلبات.
س كيف أدير إصدارات النماذج؟
ج استخدم Modelfile + Git لإدارة الإعدادات. ملفات النماذج تستخدم وسومًا (qwen2.5:v1.0) لتحديد الإصدار. في الإنتاج، استخدم وسومًا ثابتة، وليس :latest.
📖 ملخص
- بنية الإنتاج: موازن حمل Nginx + عقد Ollama متعددة + تخزين مشترك + Chroma
- التوافر العالي: Nginx least_conn + فحوصات صحة + تحويل تلقائي
- التوسع: مُطلق بزمن الانتقال/استخدام GPU؛ Docker Compose يدوي أو K8s HPA تلقائي
- Kubernetes: جدولة GPU + ثبات PVC + توسع تلقائي HPA
- التعافي من الكوارث: البنية ككود (Git) + نسخ احتياطي للنماذج (NFS/S3) + تدريبات دورية
- قائمة فحص الإنتاج تغطي 6 مجالات: البنية التحتية، الأمان، التوافر العالي، المراقبة، التعافي من الكوارث، الأداء
📝 تمارين
- أساسي (⭐): صمم خطة نشر إنتاج بآلة واحدة — Nginx + عقدة Ollama واحدة + Chroma. ارسم مخطط بنية واكتب إعدادات Docker Compose.
- متوسط (⭐⭐): إعداد مجموعة Ollama من عقدتين + موازن حمل Nginx، واختبر التحويل اليدوي.
- متقدم (⭐⭐⭐): اكتب وثيقة نشر إنتاج كاملة — مخطط بنية، إعدادات Docker Compose/K8s، تعزيز الأمان، المراقبة والتنبيه، خطة التعافي من الكوارث — وأكمل تمرين تحويل.