⏱️ وقت القراءة المقدر: 9 دقائق

سجّلت Ollama 52 مليون تنزيل شهرياً في الربع الأول من 2026. تخطّى استخدامها حدود التجريب لتصبح بنية تحتية على مستوى الفريق في حالات كثيرة. التشغيل المحلي بأمر ollama run على Mac يختلف اختلافاً جوهرياً في التصميم عن تشغيلها طبقة تقديم للفريق بأكمله على كتلة Kubernetes. هذا المقال يتناول الحالة الثانية.

لماذا Ollama: الفرق بينها وبين vLLM

تركز vLLM على تحسين الإنتاجية: PagedAttention، continuous batching، استدلال FP8 لأقصى استغلال لموارد GPU. في المقابل، تتميز Ollama بسهولة التثبيت وإدارة النماذج. أمر واحد ollama pull llama3:70b يُنزّل النموذج ويُشغّل خادم API متوافق مع OpenAI تلقائياً.

الأداتان ليستا متنافستين بل في طبقتين مختلفتين. نقاط الاستدلال العامة ذات الإنتاجية العالية تحتاج vLLM، بينما أدوات مساعدة الكود للفرق الداخلية أو روبوتات الدردشة الخاصة الصغيرة تستفيد من بساطة تشغيل Ollama.

النشر الأساسي على Kubernetes

مساحة الأسماء وRBAC

kubectl create namespace ollama
kubectl label namespace ollama kueue.x-k8s.io/team=internal-tools

PersistentVolumeClaim للـ GPU

ملفات النماذج تتراوح بين عشرات وئات الجيجابايت. بدون PVC يُعاد تنزيل النموذج في كل إعادة تشغيل للـ Pod، وهو كارثة تشغيلية.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ollama-models
  namespace: ollama
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: nfs-retain    # استخدام StorageClass المناسب للكتلة
  resources:
    requests:
      storage: 500Gi

إن احتاج عدة Pods مشاركة نفس وحدة تخزين النماذج، يلزم StorageClass يدعم ReadWriteMany كـ NFS أو CephFS أو Azure Files. مع ReadWriteOnce لا يمكن ربط الوحدة إلا بـ Pod واحد.

Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ollama
  namespace: ollama
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ollama
  template:
    metadata:
      labels:
        app: ollama
    spec:
      tolerations:
      - key: nvidia.com/gpu
        operator: Equal
        value: present
        effect: NoSchedule
      containers:
      - name: ollama
        image: ollama/ollama:latest
        ports:
        - containerPort: 11434
        env:
        - name: OLLAMA_MODELS
          value: "/models"
        - name: OLLAMA_NUM_PARALLEL
          value: "4"         # عدد الطلبات المعالجة في آن واحد
        - name: OLLAMA_MAX_LOADED_MODELS
          value: "2"         # الحد الأقصى للنماذج في الذاكرة
        volumeMounts:
        - name: models
          mountPath: /models
        resources:
          limits:
            nvidia.com/gpu: "1"
            memory: "32Gi"
          requests:
            nvidia.com/gpu: "1"
            memory: "16Gi"
      volumes:
      - name: models
        persistentVolumeClaim:
          claimName: ollama-models

OLLAMA_NUM_PARALLEL يُحدد عدد الطلبات المعالجة في وقت واحد. ذاكرة GPU غير الكافية تحول دون المعالجة المتزامنة. إبقاء القيمة الافتراضية (1) يعني معالجة الطلبات بالتسلسل ويُطيل أوقات الاستجابة.

Service

apiVersion: v1
kind: Service
metadata:
  name: ollama
  namespace: ollama
spec:
  selector:
    app: ollama
  ports:
  - port: 11434
    targetPort: 11434
  type: ClusterIP

للوصول من خارج الكتلة أضف Ingress أو غيّر النوع إلى LoadBalancer. بما أن Ollama تفتقر إلى طبقة مصادقة، يجب وضع بروكسي مصادقة أمامها عند الكشف الخارجي.

إعداد نماذج مخصصة بـ Modelfile

Modelfile في Ollama أداة لإنشاء نماذج مخصصة من نموذج أساسي بتثبيت system prompt وضبط المعاملات وطول السياق.

FROM llama3:8b

SYSTEM """
أنت مساعد مراجعة الكود الداخلي لـ ThakiCloud.
متخصص في كود Go و Kubernetes YAML و Python.
تراجع بالترتيب: الثغرات الأمنية، مشاكل الأداء، أسلوب الكود.
"""

PARAMETER temperature 0.1      # temperature منخفض أفضل لمراجعة الكود
PARAMETER num_ctx 8192          # سياق كافٍ لمعالجة الملفات الطويلة
PARAMETER num_predict 2048

طريقتان لبناء Modelfile ونشره:

الطريقة الأولى: تحميل مسبق للنموذج عبر InitContainer

initContainers:
- name: model-puller
  image: ollama/ollama:latest
  command:
  - sh
  - -c
  - |
    ollama serve &
    sleep 5
    ollama pull llama3:8b
    # تثبيت Modelfile من ConfigMap ثم البناء
    ollama create code-reviewer -f /modelfiles/Modelfile
    kill %1
  volumeMounts:
  - name: models
    mountPath: /models
  - name: modelfiles
    mountPath: /modelfiles

الطريقة الثانية: تشغيل Job منفصل

تشغيل Job منفصل لسحب النموذج وبناء Modelfile بعد تشغيل Pod. يكفي تشغيله مرة واحدة أثناء النشر الأولي.

المخرجات المنظمة (Structured Output)

تتيح Ollama إجبار مخرجات JSON عبر معامل format:

curl http://ollama:11434/api/generate -d '{
  "model": "llama3:8b",
  "prompt": "ابحث عن ثغرات أمنية في الكود التالي وأعدها بصيغة JSON:",
  "format": "json",
  "stream": false
}'

يمكن أيضاً تثبيت تنسيق المخرجات عبر system prompt في Modelfile:

SYSTEM """
أعد دائماً الردود بصيغة JSON التالية:
{"issues": [{"severity": "high|medium|low", "line": number, "description": string}]}
لا تُضمّن أي نص خارج هيكل JSON.
"""

في العمل الفعلي، قد لا يلتزم النموذج بالمخطط التام حتى مع تفعيل format: "json"، لذا تلزم طبقة تحقق من الـ schema بعد تحليل الاستجابة.

مراقبة Prometheus

تكشف Ollama مقاييس Prometheus عبر نقطة /metrics:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: ollama
  namespace: ollama
spec:
  selector:
    matchLabels:
      app: ollama
  endpoints:
  - port: http
    path: /metrics
    interval: 30s

المقاييس الرئيسية:

# عدد الطلبات قيد المعالجة
ollama_request_duration_seconds_count

# متوسط وقت المعالجة
rate(ollama_request_duration_seconds_sum[5m])
/ rate(ollama_request_duration_seconds_count[5m])

# عدد النماذج المحملة
ollama_loaded_model_count

التوسع التلقائي HPA

يعتمد HPA القائم على GPU على مقاييس معدل استخدام GPU. جمع معدل استخدام GPU عبر Prometheus من خلال DCGM Exporter من NVIDIA يُتيح استخدامه كمقياس مخصص في HPA.

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: ollama
  namespace: ollama
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: ollama
  minReplicas: 1
  maxReplicas: 4
  metrics:
  - type: Pods
    pods:
      metric:
        name: ollama_queue_depth    # عدد الطلبات المنتظرة (مقياس مخصص)
      target:
        type: AverageValue
        averageValue: "10"

إن نقصت عقد GPU، يحاول HPA التوسع لكن Pod تبقى في حالة Pending. يلزم الجمع مع Cluster Autoscaler أو Karpenter للتوسع على مستوى العقدة.

نمط بروكسي المصادقة

تفتقر Ollama إلى ميزة مصادقة ذاتية. حتى للخدمات الداخلية، الكشف بدون مصادقة يتيح للجميع استخدام النماذج. OAuth2 Proxy أو التحقق من مفتاح API عبر Nginx حل مناسب.

# مثال على ConfigMap لـ Nginx
nginx.conf: |
  location / {
    if ($http_x_api_key != "your-team-key") {
      return 401;
    }
    proxy_pass http://ollama:11434;
  }

التكامل مع موفر هوية كـ Keycloak يُتيح إدارة صلاحيات الوصول على مستوى الفريق.

نصائح تشغيلية

جدولة تحديثات النماذج عبر Job منفصل. يمكن تشغيل ollama pull مع Pod قيد التشغيل، لكن نقص المساحة أثناء التحديث قد يُعيد تشغيل الـ Pod. الجدولة عبر Job في وقت الصيانة أكثر أماناً.

ضبط OLLAMA_MAX_LOADED_MODELS وفق ذاكرة GPU. تحميل نموذجين بحجم 70B في وقت واحد يستنزف VRAM. احسب حجم النماذج مقارنةً بـ VRAM الفعلية وضع القيمة وفقاً لذلك.

تقليل مستوى السجلات. بالإعدادات الافتراضية تُسجّل Ollama تفاصيل لكل طلب. OLLAMA_DEBUG=false يُخفف سجلات الإنتاج.

خلاصة

التشغيل السليم لـ Ollama على Kubernetes يتطلب أربعة عناصر: PVC للنماذج، toleration لـ GPU، بروكسي مصادقة، والمراقبة. Modelfile يُتيح إنشاء نماذج خاصة بالفريق مع إدارة إصدارات لـ system prompt والمعاملات. حيث تكون بساطة التشغيل أهم من الإنتاجية، Ollama خيار فعّال لتقديم الأدوات الداخلية بتكلفة إعداد معقولة.