מדריך למשתמש במודל LLM בקוד פתוח ב-GDC עם air gap

במדריך הפריסה הזה מוסבר בפירוט איך להריץ מודלי שפה גדולים (LLM) מתקדמים באמצעות תוכנת קוד פתוח (OSS) בסביבות מבודדות של Google Distributed Cloud ‏ (GDC). במדריך הזה מפורטים כל השלבים שנדרשים להפעלת הגרסאות האחרונות של מודלי Gemma,‏ DeepSeek ו-Llama, ומוצגים בו תהליכים נפוצים להפעלת מודלים אחרים של LLM שזמינים לציבור. נשתמש בשרתי קצה עורפיים מבוססי-קונטיינר, כמו vLLM ו-Ollama, שמכסים מגוון רחב של פונקציות, רמות שונות של הגדרה ופריסה קלה.

סיכום התוכן

במדריך הזה מוסבר איך לפרוס ולהפעיל מודלי שפה גדולים (LLM) בקוד פתוח בסביבות מבודדות של Google Distributed Cloud ‏ (GDC).

מטרות ותשתית ליבה

  • המטרה: הוראות מפורטות להפעלת מודלים מתקדמים של שפה גדולה (LLM), כולל Gemma 3 (מולטימודאלי), DeepSeek-R1 ו-Llama (3.1/3.2) באמצעות עורפי קצה מותאמים כמו vLLM ו-Ollama.
  • גרסה מינימלית: גרסת תוכנה של GDC עם air gap‏ 1.15.x*.
  • דרישות חומרה: נדרש לפחות מעבד GPU אחד מסוג NVIDIA A100. מומלץ להשתמש באחסון עם ביצועים גבוהים (PVC של ‎500GiB ומעלה) כדי לשפר את זמני הטעינה של משקלי המודל מ-30 דקות לפחות מ-5 דקות.

רכיבי פריסה

רכיב תיאור
בקשות קצה של LLM ‫vLLM (מילוי בקשות עם תפוקה גבוהה באמצעות PagedAttention) ו-Ollama (ניהול מקומי פשוט ותמיכה בריבוי מודאלי)
מודלים מודלים של LLM שזמינים לציבור, כולל משפחות המודלים Gemma, ‏ DeepSeek ו-Llama
מאיצים תמיכה מלאה במעבדי GPU של NVIDIA A100 או בפרוסות של Multi-Instance GPU (MIG), בהתאם לשימוש ב-VRAM של המודל
שירותי GDC משתמש ב-GDC Container Service, Load Balancer (ELB/ILB), ‏ Harbor Container Registry

נוהלי תפעול מרכזיים

  • ניהול מודלים: קצה העורפי של ה-LLM מנהל את הטעינה והפריקה של המודלים על סמך השימוש. vLLM מצמיד מודלים לזיכרון כדי להבטיח זמן אחזור נמוך ועקבי, ואילו Ollama מאפשר טעינה דינמית של מודלים, אבל פורק את המודלים באופן אוטומטי אחרי 30 דקות של חוסר פעילות.
  • התאמה אישית: משתמשים יכולים להשתמש במודלים מועדפים של LLM על ידי משיכתם מהאינטרנט, יצירת קובצי אימג' חדשים של Docker והעלאה למאגר המקומי של Harbor.

דרישות מוקדמות

גרסה

  • ‫GDC עם air gap מגרסה 1.15.1 ואילך.

רכיבים

  • נוצר אשכול משתמשים עם מספיק משאבים (CPU, זיכרון, GPU).
  • נדרש לפחות GPU אחד מסוג NVIDIA A100.
  • מופע Harbor זמין ונגיש.
  • ממשקי ה-CLI‏ kubectl ו-gdcloud מוגדרים לגישה לאשכול המשתמשים.
  • לקוח Docker מותקן ומוגדר להעברה בדחיפה אל Harbor.
  • ההרשאות הנדרשות ב-IAM הוענקו (לדוגמה, Namespace Admin, ‏ Cluster Developer).
  • אם משתמשים במודלים עם גישה מוגבלת, צריך להגדיר חשבון ואימות ב-Hugging Face.

הקיבולת הנדרשת

משאב קיבולת
CPU ‫8 vCPU
זיכרון RAM ‫‎32 GiB
שטח אחסון זמני ‫16 Gi
יחידות GPU ‫1 NVIDIA A100 GPU
נפח אחסון מתמיד ‫*500GiB ומעלה

משאבי החומרה האלה נדרשים כדי שהעורפים (back-end) של שרתים יוכלו להריץ מודלים גדולים של שפה (LLM) עם האצת GPU. לדוגמה, סוג המכונה a2-ultragpu-1g-gdc יספק מספיק משאבים.

תרשים כללי

דיאגרמה כללית של מודל שפה גדול (LLM) עם משקלים פתוחים.

בתרשים הזה מוצג משתמש שצורך ממשקי API שנחשפים על ידי שני עורפי LLM,‏ vLLM ו-Ollama, כדי לקבל תגובות היקש ממודלים בקוד פתוח, כמו Gemma, ‏ Llama ו-DeepSeek. בהתאם לגודל המודל, שנמדד במיליארדי פרמטרים, יכול להיות שכל מודל שפה גדול יצטרך GPU מלא או חלק ממנו כדי לפעול.

תרשים של גבולות השירות והאבטחה לפריסת מודל שפה גדול (LLM)

הפתרון הזה מסתמך על השירותים הבאים שכבר כלולים בחבילת התוכנה של GDC עם air gap:

  • GDC Container Service: כדי להריץ את כל התהליכים ולהגדיל את ההיקף שלהם באמצעות HPA.
  • מאזן עומסים של GDC: באמצעות שירות Kubernetes, כדי להציג את כל הקצה העורפי בפתרון הזה ולאפשר גישה למודלים של שפה גדולה (LLM) מהרשת של הלקוח. זה נקרא ELB, קיצור של External Load Balancer (מאזן עומסים חיצוני). לעומת זאת, הלקוח יכול לבחור להשאיר את ה-LLM נגיש רק מתוך אשכול משתמשים. זה יכול להיות שימושי אם יש רק סוכן פנימי שמבקש מסקנות בתוך הפתרון שלו. זה נקרא ILB, קיצור של Internal Load Balancer (מאזן עומסים פנימי).
  • ‫GDC CI/CD: Harbor Container Registry לאחסון של קצה עורפי של LLM ומשקלים של מודלים.
  • חבילת כלי ה-Observability של GDC: לאיסוף ולחיפוש של יומני קצה עורפיים ולמתן לוחות בקרה.

מבחינת אבטחה, הגישה לפריסת ה-LLM תלויה במשתמשים שיכולים להגיע לשירות איזון העומסים שחושף את העורפים של שרת ה-LLM, שפועלים כ-pods בפרויקט או במרחב שמות של Kubernetes.

דיאגרמת ארכיטקטורה של גבולות שירות ואבטחה.

פריסה

דרישות מוקדמות

מתקינים את הכלים הבאים בתחנת עבודה שמחוברת לסביבת GDC עם air gap:

  1. docker
  2. ‫kubectl
  3. ‫gdcloud CLI

במסמך הזה מפורטים כל קוד המקור וקבצי ההגדרות שנדרשים לפריסת מודלים של שפה גדולה (LLM).

יצירת סוד למשיכת תמונות מ-Harbor

כדי להגדיר סוד למשיכת תמונה עבור עומס עבודה של קונטיינר ב-GDC עם air gap, צריך ליצור סוד של Kubernetesdocker-registry שמכיל פרטי כניסה לגישה לפרויקט Harbor הפרטי. הסוד הזה מוזכר במפרט הפריסה.

מומלץ להשתמש בחשבון רובוט של Harbor לגישה פרוגרמטית לתמונות בפרויקטים פרטיים של Harbor.

כדי להגדיר את סוד משיכת התמונה:

יצירת חשבון רובוט של Harbor:

  • עוברים לממשק המשתמש של מופע Harbor.
  • עוברים לפרויקט Harbor.
  • בוחרים בכרטיסייה חשבונות רובוט.
  • לוחצים על + חשבון רובוט חדש.
  • נותנים לו שם (לדוגמה, oss-llm-puller) ומעניקים לו את ההרשאות הנדרשות (לפחות גישת 'משיכה') עד לתאריך התפוגה.
  • שומרים בצורה מאובטחת את השם של חשבון הרובוט (לדוגמה, robot$oss-llm-puller) ואת האסימון הסודי שסופק.

אימות Docker ב-Harbor:

במחשב שבו מותקן Docker ויש גישה לרשת למאגר Harbor, נכנסים באמצעות פרטי הכניסה של חשבון הרובוט:

export INSTANCE_URL="your-harbor-instance-url"
# for example, harbor1-project1.org1.zone1.google.gdc.com

export ROBOT_NAME="your-robot-account-name"
# for example, robot\$oss-llm-puller (note how we escape the $ character)

export ROBOT_SECRET="your-robot-account-secret"

docker login ${INSTANCE_URL} --username ${ROBOT_NAME} --password ${ROBOT_SECRET}

# Sample output:

WARNING! Using --password via the CLI is insecure. Use --password-stdin.

WARNING! Your credentials are stored unencrypted in '$HOME/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/

Login Succeeded

כפי שמוצג בפלט לדוגמה, הפקודה הזו מעדכנת את קובץ התצורה המקומי של Docker ‏ ($HOME/.docker/config.json) עם פרטי האימות. קובץ config.json נראה כך:

{
    "auths": {
        "harbor1-project1.org1.zone1.google.gdc.com": {
            "auth": "...omitted..."
        }
    }
}

אם השתמשתם בעבר בלקוח Docker כדי להתחבר למאגרי רישום אחרים, יופיעו עוד רשומות בקטע auths.

יוצרים את סוד המשיכה של תמונת Kubernetes:

משתמשים ב-kubectl כדי ליצור סוד מסוג docker-registry במרחב השמות של הפרויקט, באמצעות קובץ ההגדרות של Docker שעודכן בשלב הקודם:

# Log in to GDC air-gapped using the next commands

gdcloud auth login --login-config-cert {path to your web TLS certificate}

gdcloud clusters get-credentials {Your User Cluster}
kubectl config set-context --current --namespace=NAMESPACE

export SECRET_NAME="oss-llm-pull-secret" # You can choose another name
export NAMESPACE="your-project-namespace"
# Assuming default Docker config path. Adjust if necessary.
export DOCKER_CONFIG_PATH="$HOME/.docker/config.json"

kubectl create secret docker-registry ${SECRET_NAME} \
      --from-file=.dockerconfigjson=${DOCKER_CONFIG_PATH} \
      -n ${NAMESPACE}

תצטרכו להפנות לסוד הזה בהמשך במפרט של קונטיינר הקצה העורפי של ה-LLM, על ידי הכללת השדה imagePullSecrets.

אם תפעלו לפי השלבים האלה, אשכול Kubernetes ישתמש עכשיו בפרטי הכניסה שסיפקתם כדי לשלוף קובץ אימג' של קונטיינר ממאגר Harbor הפרטי בסביבת GDC עם air gap. השלבים האלה מופיעים גם בתיעוד המוצר.

הגדרת פריסת LLM

יש שתי אפשרויות ל-LLM Backend:

  • vLLM
  • Ollama

אתם יכולים לבחור אחת מהן או לפרוס את שתי מערכות ה-Backend. כל קצה עורפי יכול להריץ מודל שפה גדול אחד או יותר, לדוגמה:

  • Gemma 3
  • DeepSeek
  • Llama
  • מודלים אחרים של LLM

בקטע 1 מוסבר איך לפרוס את vLLM, ובקטע 2 מוסבר איך להתקין את Ollama.

1. פריסת vLLM כקצה עורפי של LLM

קבלת קובץ האימג' של Docker ל-vLLM

באופן כללי, משתמשים ב-vLLM כדי להכניס לשימוש בסביבת הייצור מודלים שהורדו מ-HuggingFace, כמו שיוצג בהמשך במאמר הזה על פריסת LLM. חלק מהמודלים חסומים, כלומר המשתמשים צריכים לבקש במפורש גישה לקבצים ולתוכן שלהם ב-Hugging Face Hub או לאשר את הגישה אליהם לפני שהם יכולים להוריד אותם או להשתמש בהם.

נכנסים למופע Harbor באמצעות Docker כמו שמוסבר במסמכים. במחשב עם גישה לאינטרנט, מושכים את קובץ האימג' של vLLM Docker ומעבירים אותו לפרויקט Harbor:

# Pull and Tag vLLM (v0.13.0 recommended for stability)
docker pull vllm/vllm-openai:v0.13.0
docker tag vllm/vllm-openai:v0.13.0 HARBOR_URL/PROJECT/vllm-openai:v0.13.0
docker push HARBOR_URL/PROJECT/vllm-openai:v0.13.0

מחליפים את מה שכתוב בשדות הבאים:

  • ‫HARBOR_URL: כתובת ה-URL של מופע Harbor.
  • ‫PROJECT: שם הפרויקט ב-Harbor.

הגרסה של vLLM שבה השתמשנו במדריך הפריסה הזה היא: v0.13.0

שמירת משקלי המודל של LLM ב-PVC

פותחים טרמינל חדש ויוצרים תיקייה שבה ישמרו קובצי הפריסה של vLLM:

mkdir vllm-deployment
cd vllm-deployment

לאחר מכן יוצרים קובץ YAML (לדוגמה, model-pvc.yaml) כדי להצהיר על בקשה ל-PersistentVolume (PVC) באמצעות פרימיטיבים סטנדרטיים של Kubernetes:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: model-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 500Gi
  storageClassName: standard-rwo
  volumeMode: Filesystem

מתחברים לאשכול GDC עם air gap ומחילים את ה-PVC:

# Log in to GDC air-gapped using the next commands

gdcloud auth login --login-config-cert {path to your web TLS cert}

gdcloud clusters get-credentials {Your User Cluster}
kubectl config set-context --current --namespace=NAMESPACE

# Apply the PVC manifest
kubectl apply -f model-pvc.yaml

הורדה של משקלי המודל מ-Hugging Face:

# Log in to Hugging Face
hf auth login

# Download weights for Gemma 3 (for example, 4B instruction-tuned)
hf download google/gemma-3-4b-it

פלט לדוגמה:

Fetching 9 files: 100%| 9/9 [00:00<00:00, 19.34it/s]
Downloading (…)7f58a/.gitattributes: 100%| 1.62k/1.62k [00:00<00:00, 7.82MB/s]
Downloading (…)del-00002-of-00002.safetensors: 100%| 3.75G/3.75G [00:46<00:00, 81.3MB/s]
Downloading (…)del-00001-of-00002.safetensors: 100%| 4.90G/4.90G [00:54<00:00, 90.1MB/s]
Downloading (…)-3-4b-it/README.md: 100%| 23.3k/23.3k [00:00<00:00, 48.0MB/s]
Downloading (…)8a/model.safetensors.index.json: 100%| 26.3k/26.3k [00:00<00:00, 39.5MB/s]
Downloading (…)f58a/config.json: 100%| 908/908 [00:00<00:00, 4.41MB/s]
Downloading (…)generation_config.json: 100%| 210/210 [00:00<00:00, 936kB/s]
Downloading (…)tokenizer.json: 100%| 33.1M/33.1M [00:01<00:00, 17.6MB/s]
/Users/rashjab/.cache/huggingface/hub/models--google--gemma-3-4b-it/snapshots/952ec8ffca3adadfd00c6d71b40280ebdbb7f58a

כפי שאפשר לראות בפלט לדוגמה, גודל המודל בדיסק הוא 8.64GB, שמתאים ל-PVC של 500GiB שהגדרנו קודם. חשוב לוודא שזה המצב בכל מודל שבוחרים לטעון ל-Persistent Volume ‏ (PV). לדוגמה, אם משתמשים ב-PVC בגודל 500GiB כדי לטעון מודל בגודל 15GB, אפשר להשיג 1,500 IOPS, וכך לקצר משמעותית את זמן הטעינה של המשקלים מכ-30 דקות לפחות מ-5 דקות.

מאכלסים את ה-PV על ידי העתקת קובצי המודל לנפח שלו. לרוב זה כולל:

  • יצירת פוד זמני מסוג helper שמבצע mount של ה-PV.
  • משתמשים ב-kubectl cp כדי להעתיק את קובצי המודל מתחנת העבודה לנפח המצורף של ה-pod של העוזר.
  • Pod של עוזר לדוגמה:

helper-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: model-uploader
spec:
  containers:
  - name: uploader
    image: HARBOR_URL/PROJECT/busybox:latest
    command: ["sleep", "3600"]
    volumeMounts:
    - name: model-data
      mountPath: /data
  imagePullSecrets:
  - name: oss-llm-pull-secret
  volumes:
  - name: model-data
    persistentVolumeClaim:
      claimName: model-pvc

מחליפים את מה שכתוב בשדות הבאים:

  • ‫HARBOR_URL: כתובת ה-URL של מופע Harbor.
  • ‫PROJECT: שם הפרויקט ב-Harbor.
  • ‫oss-llm-pull-secret: אם בחרתם שם אחר של סוד משיכת התמונה.
  • ‫model-pvc: עם השם שנתתם ל-PVC.

דחיפה של קובץ האימג' של Docker (busybox):

docker pull busybox:latest
docker tag busybox HARBOR_URL/PROJECT/busybox:latest
docker push HARBOR_URL/PROJECT/busybox:latest

מחליפים את מה שכתוב בשדות הבאים:

  • ‫HARBOR_URL: כתובת ה-URL של מופע Harbor.
  • ‫PROJECT: שם הפרויקט ב-Harbor.

מחילים את הקובץ helper-pod.yaml ומעתיקים את משקלי המודל ל-PV:

kubectl apply -f helper-pod.yaml

# Wait for the pod to be Running
kubectl cp ~/.cache/huggingface/hub/ NAMESPACE/model-uploader:/data/

# After copying, delete the helper pod
kubectl delete pod model-uploader

פריסת הבק-אנד של vLLM

יוצרים את קובץ הפריסה של vLLM כדי להריץ את שרת המודלים. בדוגמה הבאה מפריסים את המודל gemma-3-4b-it.

vllm-gemma-3-4b-it-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gemma-3-4b-it
  labels:
    app: gemma-3-4b-it
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gemma-3-4b-it
  template:
    metadata:
      labels:
        app: gemma-3-4b-it
    spec:
      volumes:
      - name: cache-volume
        persistentVolumeClaim:
          claimName: model-pvc # change with the name you gave initially to your PVC
      # vLLM needs to access the host's shared memory for tensor parallel inference.
      - name: shm
        emptyDir:
          medium: Memory
          sizeLimit: "16Gi"
      containers:
      - name: gemma-3-4b-it
        image: HARBOR_URL/PROJECT/vllm-openai:v0.13.0
        command: ["python3"]
        args: [
          "-m",
          "vllm.entrypoints.openai.api_server",
          "--model",
          "google/gemma-3-4b-it", # Use the repo ID
          "--max-model-len",
          "32768",
          "--enforce-eager"
        ]
        env:
        - name: HF_HUB_OFFLINE
          value: "1"
        - name: HF_HOME
          value: "/model" # Tells vLLM to look for models in /model/hub
        # --- PERFORMANCE & STABILITY OPTIMIZATIONS ---
        - name: NCCL_P2P_DISABLE
          value: "1" # Prevents initialization hangs on P2P checks
        - name: NCCL_IB_DISABLE
          value: "1" # Prevents initialization hangs on InfiniBand checks
        # --- FIPS BYPASS ---
        - name: BORINGSSL_FIPS
          value: "0"
        - name: OPENSSL_FIPS
          value: "0"
        - name: OPENSSL_CONF
          value: "/dev/null"
        - name: FIPS_SIG
          value: "off"
        ports:
        - containerPort: 8000
        securityContext:
          privileged: true
          runAsUser: 0
        resources:
          limits:
            nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1
            cpu: "8"       # Increased to handle model weight verification
            memory: "64Gi"  # Increased to ensure headroom for weight loading
          requests:
            nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1
            cpu: "8"
            memory: "32Gi"
        volumeMounts:
        - name: cache-volume
          mountPath: /model
        - name: shm
          mountPath: /dev/shm
      imagePullSecrets:
      - name: oss-llm-pull-secret

מחליפים את מה שכתוב בשדות הבאים:

  • ‫HARBOR_URL: כתובת ה-URL של מופע Harbor.
  • ‫PROJECT: שם הפרויקט ב-Harbor.
  • ‫oss-llm-pull-secret: השם שנתתם במהלך יצירת הסוד של משיכת התמונה.
  • ‫claimName: השם שנתתם ליצירת ה-PVC הראשונית.

לאחר מכן, יוצרים קובץ שירות של Kubernetes כדי לחשוף את ממשקי ה-API של ה-Backend של vLLM:

vllm-gemma-3-4b-it-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: gemma-3-4b-it
  namespace: NAMESPACE
spec:
  ports:
  - name: http-gemma-3-4b-it
    port: 80
    protocol: TCP
    targetPort: 8000
  selector:
    app: gemma-3-4b-it
  sessionAffinity: None
  type: LoadBalancer

החלת הפריסה והגדרות השירות:

kubectl apply -f vllm-gemma-3-4b-it-deployment.yaml
kubectl apply -f vllm-gemma-3-4b-it-service.yaml

אימות ובדיקה של פריסת vLLM

  1. בודקים את הסטטוס של ה-pod:

    kubectl get pods
    

    ממתינים עד שה-pod יהיה במצב Running.

  2. בודקים את השירות:

    kubectl get service
    

    פלט לדוגמה:

    # NAME          TYPE         CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
    # gemma-3-4b-it LoadBalancer 10.201.136.62  136.125.37.198   80:30109/TCP   3d1h
    

    מהפלט הקודם, כדאי לשמור את EXTERNAL-IP של שירות vLLM (לדוגמה, 136.125.37.198). אפשר גם להדפיס אותו באמצעות:

    kubectl get service gemma-3-4b-it \
    -o jsonpath='{.status.loadBalancer.ingress[*].ip}'
    
  3. צפייה ביומנים:

    kubectl logs YOUR_VLLM_POD
    

    מחפשים הודעות שמציינות שהשרת הופעל והמודל נטען (לדוגמה, INFO: Application startup complete.). מכיוון שאין הורדה של Hugging Face, הפעולה אמורה להיות מהירה אם הקבצים נמצאים ב-PVC עם קיבולת גבוהה של Persistent Volume.

  4. בדיקת ההסקה באמצעות curl:

    אחרי שמוודאים שתרמיל vLLM פועל ושיש לכם את כתובת ה-IP החיצונית של השירות, אפשר לשלוח בקשת הסקה באמצעות curl. מכיוון ש-vLLM מספק API שתואם ל-OpenAI, אפשר להשתמש בנקודת הקצה /v1/chat/completions:

    curl http://EXTERNAL_IP/v1/chat/completions \
      -H "Content-Type: application/json" \
      -d '{
        "model": "google/gemma-3-4b-it",
        "messages": [
          {"role": "user", "content": "What is Google Distributed Cloud air-gapped?"}
        ],
        "max_tokens": 100
      }'
    

    מחליפים את EXTERNAL_IP בכתובת ה-IP החיצונית של שירות ה-vLLM.

2. פריסת Ollama כקצה עורפי של LLM

‫Ollama היא מסגרת פופולרית להרצת מודלים גדולים של שפה (LLM) בקוד פתוח באופן מקומי ובסביבות בקונטיינרים. הוא מפשט את הרצת המודל על ידי טיפול בהורדות של משקלים, בכימות ובהאצת GPU. הוא כולל API בארכיטקטורת REST מובנה ליצירת השלמות, תשובות בצ'אט והטמעות.

בניגוד למנועי הצגה אחרים, Ollama מנהל את הביצוע של המודל באופן דינמי:

  • טעינה דינמית של מודלים: כשמתקבלת בקשה למודל ספציפי, Ollama טוען את המשקלים לזיכרון (VRAM של GPU או RAM של המערכת) לפי דרישה.
  • הסרת טעינה של חוסר פעילות: אם לא מתקבלות בקשות הסקה עבור מודל במשך 30 דקות (אפשר להגדיר את זה באמצעות OLLAMA_KEEP_ALIVE), ‏ Ollama מסיר את הטעינה שלו מהזיכרון כדי לפנות משאבי חומרה לעומסי עבודה אחרים.
  • מודל פעיל יחיד לכל מופע: Ollama מעבד בקשות למודל פעיל אחד בכל פעם לכל מופע שרת. אם קוראים לכמה מודלים במקביל, Ollama מכניס את הבקשות לתור ומחליף בין המודלים באופן עקבי, מה שעלול לגרום לזמן אחזור. כדי להפעיל כמה מודלים בו-זמנית בלי להחליף ביניהם, צריך לפרוס מופעי Ollama נפרדים לכל מודל.

הורדת משקלים של מודלים ויצירת קובץ אימג' של Docker

בניגוד ל-vLLM, שיכול לטעון משקלים ישירות מנפח אחסון קבוע, בדרך כלל Ollama מצפה שהמודלים יאוחסנו בפורמט של ספרייה פנימית (~/.ollama/models).

בסביבה עם air gap, שבה קונטיינרי זמן הריצה לא יכולים להוריד מודלים מהאינטרנט הציבורי, צריך לארוז מראש את משקלי המודל בקובץ אימג' של קונטיינר עצמו במהלך שלב ה-build. הגישה הזו מבטיחה שהקונטיינר יהיה עצמאי לחלוטין ומוכן להפעלה מיידית אחרי הפריסה, בלי לדרוש גישה לרשת חיצונית.

יוצרים תיקייה לפריסת Ollama:

mkdir ollama-gemma3
cd ollama-gemma3

יוצרים Dockerfile עם התוכן הבא:

# Use a standard Linux base image
FROM ubuntu

# Install necessary dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl \
    ca-certificates \
    zstd \
    && rm -rf /var/lib/apt/lists/*

# Install Ollama
# This uses Ollama's official installation script, which adds Ollama to /usr/local/bin
RUN curl -fsSL https://ollama.com/install.sh -o install.sh && \
    chmod +x install.sh && \
    ./install.sh && \
    rm install.sh

# Set environment variables for Ollama (optional, but a good practice)
# ENV OLLAMA_HOST="0.0.0.0"

# If you want to customize the model storage path within the container, set OLLAMA_MODELS, for example:
# ENV OLLAMA_MODELS="/usr/local/ollama/models"
# The default OLLAMA_MODELS is /root/.ollama
# Then, ensure you create and populate that directory.

# --- Download Gemma 3 model weights ---
# This step starts Ollama server in the background, pulls the model,
# and then kills the server to allow the Docker build to continue.
# This approach works around the Docker RUN command limitations for services.

RUN ollama serve & \
    # Give the Ollama server a moment to start up
    # Use --retry and --retry-connrefused to handle startup delays
    curl --retry 10 --retry-connrefused -s http://localhost:11434 || true && \
    # Pull the Gemma 3 model weights
    ollama pull gemma3:latest && \
    # Stop the background Ollama server process cleanly
    pkill ollama || true

# Expose Ollama's default port
EXPOSE 11434

# Command to run Ollama server when the container starts
CMD ["ollama", "serve"]

אם רוצים לנסות מודל שפה גדול (LLM) אחר בקוד פתוח, כמו מודל מהמשפחות Llama 3.2 או DeepSeek-R1, צריך לשנות את פקודת Ollama הזו בקובץ Dockerfile הקודם:

ollama pull gemma3:latest

לדוגמה, אם רוצים למשוך את Llama 3.2 עם 3 מיליארד פרמטרים, משתמשים בפקודה הבאה:

ollama pull llama3.2:3b

לחלופין, אם אתם מעדיפים להשתמש ב-DeepSeek-R1 עם 8 מיליארד פרמטרים, תוכלו להשתמש בפקודה הזו:

ollama pull deepseek-r1:8b

אפשר גם להוריד יותר ממודל LLM אחד ולכלול את משקלי המודל שלהם במאגר. לאחר מכן, Ollama יוכל לעבור בין מודלים כשמבקשים מסקנות על ידי מודלים שונים שנטענו מראש. לדוגמה, אפשר להוסיף גם את מודל Gemma וגם את מודל Llama לקובץ האימג' של Docker. כפי שציינו, בסביבה עם פער אוויר, ל-Ollama backend אין גישה לספריית Ollama כדי להוריד מודל כלשהו בכל שלב.

חשוב לזכור לבדוק את הרישיון ואת תנאי השימוש של כל מודל ולאשר אותם לפני שמריצים את המודלים באפליקציות. יש הרבה מודלי שפה גדולים בספרייה של Ollama. תצטרכו חיבור לאינטרנט רק כדי להוריד את משקלי המודל בזמן בניית קובץ אימג' של Docker של ה-LLM backend.

יצירת קובץ אימג' של Docker והעברה שלו בדחיפה ל-Harbor

נכנסים למופע Harbor באמצעות Docker כמו שמוסבר במסמכים. יוצרים את קובץ האימג' של Gemma 3 docker ומעלים אותו למאגר Harbor:

docker build -t ollama-gemma3 .
docker tag ollama-gemma3 HARBOR_URL/PROJECT/ollama-gemma3:latest
docker push HARBOR_URL/PROJECT/ollama-gemma3:latest

מחליפים את מה שכתוב בשדות הבאים:

  • ‫HARBOR_URL: כתובת ה-URL של מופע Harbor.
  • ‫PROJECT: שם הפרויקט ב-Harbor.

גרסת Ollama שבה נעשה שימוש במדריך הפריסה הזה: 0.14.1

הכנת פריסה ושירות של Kubernetes

יוצרים קובץ בשם ollama-gemma3.yaml כדי להגדיר את הפריסה של ה-backend של Ollama ואת ההגדרה של מאזן העומסים שלו, כדי לחשוף אותו כשירות:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ollama-gemma3
  namespace: osd-dev
  labels:
    app: ollama-gemma3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ollama-gemma3
  template:
    metadata:
      labels:
        app: ollama-gemma3
    spec:
      containers:
      - name: ollama-gemma3
        image: rashjab-mhs-rashjab-test2.gdc1.us-west6-a.staging.gpcdemolabs.com/rashjab-repo/ollama-gemma3:latest
        env:
        # This is the crucial fix: Tell Ollama to listen on all network interfaces
        - name: OLLAMA_HOST
          value: "0.0.0.0"
        imagePullPolicy: Always
        ports:
        - containerPort: 11434
        securityContext:
          privileged: true
          runAsUser: 0
        resources:
          limits:
            nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1
          requests:
            nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1
      imagePullSecrets:
      - name: oss-llm-pull-secret
---
apiVersion: v1
kind: Service
metadata:
  name: ollama-gemma3
  namespace: osd-dev
spec:
  type: LoadBalancer
  selector:
    app: ollama-gemma3
  ports:
  - name: ollama-gemma3-port
    port: 11434
    protocol: TCP
    targetPort: 11434

מחליפים את מה שכתוב בשדות הבאים:

  • ‫HARBOR_URL: כתובת ה-URL של מופע Harbor.
  • ‫PROJECT: שם הפרויקט ב-Harbor.
  • ‫oss-llm-pull-secret: אם בחרתם שם אחר של סוד משיכת התמונה.

אימות הקצאת ה-GPU

‫GDC עם air gap תומך ב-NVIDIA Multi-Instance GPUs‏ (MIG), ואפשר לעיין בפרופילים השונים של MIG בתיעוד הציבורי. אם אתם פורסים מודלים קטנים של LLM, מומלץ לבדוק את הגודל שלהם (בזיכרון) ולחלק את מעבדי ה-GPU בהתאם. סכמת החלוקה למחיצות של מאגר צמתים מוגדרת במשאב המותאם אישית Cluster שלו. מידע נוסף על אופן ההחלה של סכימת חלוקה למחיצות של GPU זמין במאמר בנושא הוספת מאגר צמתים. אם אתם אופרטור של אפליקציות (AO), כדאי להתייעץ עם אדמין הפלטפורמה (PA) לגבי המאיצים שמותקנים בפרויקט או באשכול שלכם וזמינים לשימוש. כאן אפשר לקרוא פרטים נוספים על הגדרת קונטיינר לשימוש במשאבי GPU ועל בדיקת הקצאת משאבי GPU.

דיוק ברירת המחדל של מודל Gemma 3 4B הוא 16 ביט. לפי הטבלה הזו שפורסמה על ידי Google, דרישת הזיכרון של ה-GPU עבור מודל ה-LLM הזה היא 6.4GB, באמצעות דיוק BF16 (16 ביט).

בדוגמה הקודמת ollama-gemma3.yaml, צירפנו לקונטיינר פרוסת GPU של 10GB ‏ (NVIDIA A100), כי כמות הזיכרון הזו של VRAM מספיקה לטעינה ולהרצה של מודל Gemma 3 4B, כמו שמוצג בהמשך:

ollama-gemma3.yaml

... omitted ...

        resources:
          limits:
            nvidia.com/mig-1g.10gb-NVIDIA_A100_80GB_PCIE: 1
          requests:
            nvidia.com/mig-1g.10gb-NVIDIA_A100_80GB_PCIE: 1

... omitted ...

פריסת הקצה העורפי של Ollama וחשיפתו כשירות

מתחברים לאשכול ומגדירים את ההקשר למרחב השמות של הפרויקט:

# Log in to GDC air-gapped using the next commands

gdcloud auth login --login-config-cert {path to your web TLS certificate}

gdcloud clusters get-credentials {Your User Cluster}
kubectl config set-context --current --namespace=NAMESPACE

מחילים את מניפסט Ollama:

kubectl apply -f ollama-gemma3.yaml

מוודאים שרכיב ה-pod של Ollama פועל ושקיים השירות המשויך:

kubectl get pods

פלט לדוגמה:

# NAME                             READY   STATUS    RESTARTS   AGE
# ollama-gemma3-6fc6fff74b-9qtpf   1/1     Running   0          1h
kubectl get service

פלט לדוגמה:

# NAME             TYPE          CLUSTER-IP    EXTERNAL-IP    PORT(S)          AGE
# ollama-gemma3   LoadBalancer  172.0.0.1     10.0.0.1       11434:31822/TCP  1d

שימו לב ל-EXTERNAL-IP של שירות Ollama (לדוגמה, 10.0.0.1) מהפלט הקודם. אפשר גם להדפיס אותו באמצעות:

kubectl get service ollama-gemma3 \
-o jsonpath='{.status.loadBalancer.ingress[*].ip}'

לפני שבודקים אם Ollama Gemma 3 פועל, צריך להחיל מדיניות רשת כמו :

apiVersion: networking.gdc.goog/v1
kind: ProjectNetworkPolicy
metadata:
  name: allow-ollama-ingress
  namespace: osd-dev
spec:
  subject:
    subjectType: UserWorkload
  policyType: Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 0.0.0.0/0 # Allows traffic from any IP. Restrict this for production.
    ports:
    - protocol: TCP
      port: 11434

החלת מדיניות רשת ב-Kubernetes:

kubectl apply -f ollama-netpol.yaml

בודקים ומריצים בדיקות לפריסת Ollama:

  1. בודקים אם Ollama פועל:

    curl http://EXTERNAL_IP:11434
    

    התשובה הצפויה: 'Ollama is running'

  2. שליחת בקשת השלמה:

    curl -X POST http://EXTERNAL_IP:11434/v1/completions \
      -H "Content-Type: application/json" \
      -d '{
        "model": "gemma3:latest",
        "prompt": "Google Distributed Cloud air-gapped is a",
        "max_tokens": 128,
        "temperature": 0.90
      }'
    

בקשת מסקנות

עכשיו, אחרי שפרסתם את העורפים של מודלי ה-LLM (vLLM ו-Ollama) ואפשר להגיע אליהם דרך שירותי LoadBalancer המתאימים, אתם יכולים להתחיל להשתמש בהם להסקת מסקנות.

בהתאם לתרחיש לדוגמה שלכם, יש לכם כמה אפשרויות:

  • ממשק משתמש אינטראקטיבי באינטרנט: כדי לבדוק, ליצור אב טיפוס או לספק למשתמשים חוויה דומה ל-ChatGPT, אפשר לפרוס את Open WebUI או קצה קדמי דומה.
  • ממשק שורת הפקודה (CLI): כדי לבצע אימות מהיר, לכתוב סקריפטים או להגדיר אוטומציה, אפשר להשתמש ב-curl או בסקריפטים מותאמים אישית.
  • שילוב אפליקציות: אפשר לחבר את האפליקציות הפנימיות, סוכני ה-AI או הפלאגינים לסביבת הפיתוח המשולבת (IDE) (לדוגמה, Continue ל-VS Code או ל-JetBrains) ישירות לנקודות הקצה שתואמות ל-OpenAI שמסופקות על ידי vLLM ‏(/v1) או Ollama ‏(/v1).

1. אינטראקציה עם מודל LLM באמצעות ממשק משתמש

כדי לספק ממשק כמו ChatGPT לאינטראקציה עם המודלים שלכם, צריך לפרוס את Open WebUI באשכול.

יצירת פריסה של Open WebUI

יצירת open-webui-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: open-webui
  namespace: osd-dev
  labels:
    app: open-webui
spec:
  replicas: 1
  selector:
    matchLabels:
      app: open-webui
  template:
    metadata:
      labels:
        app: open-webui
    spec:
      containers:
      - name: open-webui
        image: HARBOR_URL/PROJECT/open-webui:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        env:
        - name: OPENAI_API_BASE_URL
          value: "http://gemma-3-4b-it/v1" # Point to your vLLM service
        - name: OPENAI_API_KEY
          value: "EMPTY"
        - name: WEBUI_AUTH
          value: "False"
      imagePullSecrets:
      - name: oss-llm-pull-secret
---
apiVersion: v1
kind: Service
metadata:
  name: open-webui
  namespace: osd-dev
spec:
  type: LoadBalancer
  selector:
    app: open-webui
  ports:
  - port: 80
    targetPort: 8080

החלת מדיניות הרשת

אתם צריכים לאפשר למכונה שלכם להגיע לשירות Open WebUI ביציאה 80.

מעדכנים את מדיניות הרשת של הפרויקט שלכם ב-PNP כך שתכלול את השירות open-webui או מחילים מדיניות רחבה:

apiVersion: networking.gdc.goog/v1
kind: ProjectNetworkPolicy
metadata:
  name: allow-webui-ingress
  namespace: NAMESPACE
spec:
  subject:
    subjectType: UserWorkload
  policyType: Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 0.0.0.0/0 # Allows traffic from any IP then restrict this for production
    ports:
    - protocol: TCP
      port: 8080

אימות

  1. קבלת כתובת ה-IP של ממשק המשתמש האינטרנטי:

    kubectl get service open-webui -n NAMESPACE
    
  2. כדי לגשת לממשק המשתמש: פותחים את הדפדפן ועוברים לכתובת http://WEB_UI_EXTERNAL_IP

  3. הגדרה: בכניסה הראשונה, יוצרים חשבון אדמין. בהגדרות, מוודאים שנקודות החיבור של OpenAI מצביעות על http://gemma-3-4b-it/v1

  4. בוחרים מודל: בממשק הצ'אט, לוחצים על google/gemma-3-4b-it בתפריט הנפתח של המודל.

    פותחים את התפריט הנפתח לבחירת מודל בממשק המשתמש האינטרנטי.

2. שליחת בקשות HTTP באמצעות CLI

  • ‫curl:
curl -X POST http://OLLAMA_LOAD_BALANCER_IP:11434/v1/completions \
-H "Content-Type: application/json" \
-d '{
  "model": "gemma3:latest",
  "prompt": "Google Distributed Cloud air-gapped is a",
  "max_tokens": 128,
  "temperature": 0.90
}'

אימות ובדיקת תקינות

בודקים שכל המאגרים והשירותים פועלים:

# Log in to GDC air-gapped using the next commands

gdcloud auth login --login-config-cert {path to your web TLS cert}
gdcloud clusters get-credentials {Your User Cluster}
kubectl config set-context --current --namespace=NAMESPACE

# Pods

kubectl get pods # This command should return results like below

# NAME                                   READY   STATUS    RESTARTS   AGE
# vllm-6fc6fff74b-9qtpf                 1/1     Running   0          1h
# ollama-798fbf6ff6-9m7ln               1/1     Running   0          1h


# Services

kubectl get services # This command should return results like below

# NAME                      TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)           AGE
# vllm-service              LoadBalancer   172.0.0.1        10.0.0.1       11434:31822/TCP   1h
# ollama-service        LoadBalancer   172.0.0.2        10.0.0.2       11434:30728/TCP   1h

שלבים להסרה

  1. מסירים את כל משאבי Kubernetes:

    kubectl delete -f vllm-gemma-3-4b-it-deployment.yaml
    kubectl delete -f vllm-gemma-3-4b-it-service.yaml
    
  2. מוחקים ידנית מאגרים שלא בשימוש ממאגר Harbor.

תפעול

בק-אנד של vLLM

מושגי יסוד ב-vLLM

‫vLLM מתוכנן כמנוע להצגת מודל יחיד עם ביצועים גבוהים. הוא לא תומך בהצגת כמה מודלים בתהליך שרת יחיד או בהגדרת כמה מודלים בפקודת הפעלה יחידה. כדי להפעיל יותר ממודל אחד (לדוגמה, מודל צ'אט ומודל הטמעה נפרד), צריך להפעיל מופעים נפרדים של vLLM, כל אחד בתא או במאגר משלו, שאפשר להקצות אותם ל-GPU או לחלקים שונים של GPU. בניגוד למערכות עורפיות אחרות שעשויות להחליף מודלים באופן דינמי, מופע vLLM מצמיד את המודל שלו ואת זיכרון מטמון ה-KV המשויך לו עם ההפעלה, כדי להבטיח תפוקה גבוהה ועקבית וזמן אחזור נמוך.

אפשר לפתוח טרמינל בכל אחד מהפודים של vLLM באמצעות הפקודות הבאות:

kubectl exec -it gemma-3-4b-random-string -n NAMESPACE -- /bin/bash

יוצגו לכם הדגמים שנטענו, הארגומנטים שלהם ומזהי התהליך שלהם :

ps aux | grep vllm

פלט דומה צפוי:

root           1  0.1  0.8 9436960 1550504 ?     Ssl  Feb04   9:18 python3 -m vllm.entrypoints.openai.api_server --model google/gemma-3-4b-it --max-model-len 32768 --enforce-eager
root         504  0.0  0.0   3476  1596 pts/0    S+   02:48   0:00 grep --color=auto vllm

אם רוצים תצוגה נקייה יותר, בסגנון Ollama, בלי העומס של הפקודה grep עצמה ומזהי התהליכים (PID) של המערכת, אפשר להשתמש בפקודה הבאה:

ps aux | grep [v]llm.entrypoints | awk -F'--model ' '{print $2}' | awk '{print $1}'

דוגמה לתשובה :

google/gemma-3-4b-it

אתם יכולים לעקוב אחרי הסטטוס של פריסת vLLM באמצעות פקודות kubectl סטנדרטיות ובאמצעות שאילתות של נקודות הקצה של ה-API הפנימי.

בדיקת היומנים של ה-Pod

פותחים טרמינל כדי לראות את יומני האתחול וההצגה:

kubectl logs -f gemma-3-4b-it-random_string -n NAMESPACE

מחפשים את האישור שהשרת מוכן:

(APIServer pid=1) INFO:     Started server process [1]
(APIServer pid=1) INFO:     Waiting for application startup.
(APIServer pid=1) INFO:     Application startup complete.

הסטטוס הפנימי של השאילתה

‫vLLM מספקת API שתואם ל-OpenAI, כך שאפשר לאמת את המודלים שנטענו ואת תקינות המערכת ישירות ממסוף בתוך האשכול (לדוגמה, באמצעות פוד debug-sh).

קודם צריך להפעיל את ה-pod לניפוי באגים. הנה ההוראות :

הפעלת כלי ניפוי הבאגים

מריצים את הפקודה הבאה כדי להפעיל מעטפת זמנית במרחב השמות של הפרויקט. ההגדרה הזו משתמשת באימג' של busybox (שנדחף בעבר למאגר שלכם ב-Harbor) ומזריקה את פרטי הכניסה הנדרשים באמצעות הדגל --overrides:

kubectl run --rm -it debug-sh \
  --image=HARBOR_URL/PROJECT/busybox:latest \
  --restart=Never -n osd-dev --overrides='{
    "spec": {
      "imagePullSecrets": [{"name": "oss-llm-pull-secret"}]
    }
  }' -- sh

פרמטרים מרכזיים:

  • ‫--rm: מחיקה אוטומטית של ה-Pod ביציאה, כדי לשמור על משאבי האשכול.
  • ‫--overrides: חובה בסביבות מבודדות כדי לאפשר לאמצעי ההגנה לאמת את עצמו מול מרשם Harbor הפרטי.

שאילתת הסטטוס של שרת מודל השאילתות

אחרי שנכנסים ל-Pod, משתמשים בכלי wget כדי לשלוח שאילתה ל-vLLM API. מכיוון ששירות vLLM ממפה את יציאה פנימית 8000 ליציאה 80, אפשר להשתמש בשם ה-DNS של השירות:

  • רשימת המודלים שנטענו: מוודאים שמנוע vLLM הופעל וטען את המשקלים של Gemma 3.

    wget -qO- http://gemma-3-4b-it/v1/models
    

    תגובה להצלחה:

    {"object":"list","data":[{"id":"google/gemma-3-4b-it"}]}
    
  • בדיקת תקינות האפליקציה: מוודאים ששרת ה-API מוכן לעיבוד בקשות.

    wget -qO- http://gemma-3-4b-it/health
    

    תגובה להצלחה:

    OK
    

מושגי יסוד ב-Ollama

‫Ollama לא תומך בטעינה של כמה מודלים לזיכרון בו-זמנית. בנוסף, אם לא משתמשים ב-LLM במשך פרק זמן מסוים (בדרך כלל 30 דקות כברירת מחדל), ‏ Ollama מבטל את הטעינה של המודל הנוכחי מהזיכרון.

בגלל ההתנהגות שתוארה קודם, הפתרון מטמיע שני עורפי קצה (backend) או יותר של Ollama, בהתאם לצרכים ולתרחיש השימוש, כדי שמפתחים או משתמשים רבים יוכלו להשתמש בהם במקביל בלי שרק מופע אחד של Ollama יטען ויבטל טעינה של מודלים לעיתים קרובות, מה שיוצר חביון מיותר.

אפשר לפתוח טרמינל בכל אחד מה-pods של Ollama באמצעות הפקודות הבאות:

kubectl exec -it ollama-chat-random_string -- sh
kubectl exec -it ollama-autocomplete-random_string -- sh

בתוך ה-pods, אפשר להשתמש ב-Ollama CLI כדי לראות את המודלים הזמינים ולבדוק איזה מודל נטען:

  • ב-pod‏ ollama-chat מופיע מודל אחד:

    # ollama list
    NAME                     ID              SIZE      MODIFIED
    codegemma:7b-instruct    0c96700aaada    5.0 GB    2 hours ago
    
    # ollama ps
    NAME                     ID              SIZE     PROCESSOR    UNTIL
    codegemma:7b-instruct    0c96700aaada    10 GB    100% GPU     4 minutes from now
    
  • בתרמיל ollama-autocomplete יש שני מודלים:

    # ollama list
    NAME                     ID              SIZE      MODIFIED
    codegemma:2b             926331004170    1.6 GB    2 hours ago
    codegemma:7b-code        aee9a63c13b9    5.0 GB    2 hours ago
    
    # ollama ps
    NAME                 ID              SIZE      PROCESSOR    UNTIL
    codegemma:7b-code    aee9a63c13b9    7.1 GB    100% GPU     4 minutes from now
    
  • כש-Ollama מבטל את הטעינה של המודל הנוכחי, הפלט ריק:

    # ollama ps
    NAME    ID    SIZE    PROCESSOR    UNTIL
    

שימו לב: Ollama טוען מחדש באופן דינמי מודל כששולחים את הבקשה הבאה לסיוע בכתיבת קוד, ללא התערבות ידנית.

חשיבות הקיבולת של ה-GPU

אם אתם מקצים פרוסת GPU עם 10GB, אבל הזיכרון שבשימוש של המודל גדול יותר (אפילו קצת), תשימו לב שחלק מה-LLM נטען במעבד (CPU), כמו בדוגמה הבאה:

# ollama ps
NAME                     ID              SIZE     PROCESSOR         UNTIL
codegemma:7b-instruct    0c96700aaada    10 GB    6%/94% CPU/GPU    29 minutes from now

זה לא אופטימלי ויוצר זמן אחזור גבוה יותר בתגובה, לכן חשוב לספק את גודל ה-GPU שמומלץ במדריך הזה.

מודלים של LLM

שימוש ב-vLLM כדי להפעיל מודל LLM אחר או את המודל המועדף

כדי להריץ גרסאות שונות של Gemma או כל מודל שפה גדול (LLM) אחר בקוד פתוח באמצעות vLLM ב-GDC עם air gap, כמו DeepSeek-R1 או Llama 3.1, צריך להטמיע את משקלי המודל החדשים בסביבה שלכם ולעדכן את מניפסט הפריסה כך שיצביע על הנכסים החדשים.

בהתאם לנהלים התפעוליים שנקבעו לפתרון הזה, פועלים לפי השלבים הבאים כדי לטעון מודל אחר :

  1. הורדת משקלים של מודלים חדשים:

    בתחנת עבודה עם גישה לאינטרנט, משתמשים ב-Hugging Face CLI כדי להוריד את המשקלים של המודל המועדף.

    • ‫Gemma 3 (3-12b-it):
    hf download google/gemma-3-12b-it
    
    • ‫DeepSeek-R1 (7B Distill):
    hf download deepseek-ai/DeepSeek-R1-Distill-Qwen-7B
    
    • ‫Llama 3.1 (8B):
    hf download meta-llama/Meta-Llama-3.1-8B-Instruct
    

    הערה: לפני ההורדה, צריך לוודא שאישרתם את תנאי הרישיון של המודל ב-Hugging Face.

  2. מאכלסים את Persistent Volume ‏ (PVC):

    מעדכנים את model-pvc הקיים או יוצרים חדש עם קיבולת מספקת לדגם החדש. אפשר להשתמש בשיטה של פודים מסייעים כדי להעביר את המשקלים מתחנת העבודה. גורמי צורה גדולים יותר דורשים הרבה יותר מקום בדיסק. מוודאים שלתביעת הנפח המתמשך (PVC) יש מספיק קיבולת לאחסון המשקלים החדשים.

    • ‫Gemma 3 4B: ‏ ‎~15.2 GB.
    • ‫Gemma 3 27B: ‏ ‎~54 GB+‎.
    • המלצה: כדי להבטיח IOPS גבוה (1,500) לטעינה מהירה יותר, בלי קשר לגודל המודל, מומלץ לשמור על ההמלצה לגבי PVC של 500GiB.
    # Copy the new model's hub directory to the helper pod
    kubectl cp ~/.cache/huggingface/hub/ osd-dev/model-uploader:/data/
    
  3. מעדכנים את מניפסט הפריסה של vLLM:

    משנים את קובץ ה-YAML של פריסת vLLM כדי להפנות למזהה המודל החדש. בניגוד ל-Ollama, שמאפשר להחליף מודלים באופן דינמי, מופע vLLM מוקדש למודל יחיד וצריך לעדכן או לפרוס אותו מחדש כדי לשנות מודלים.

    מעדכנים את הקטע args של הפריסה בהתאם למודל שבו משתמשים. כאן מוצג deepseek כדוגמה:

    args: [
      "-m", "vllm.entrypoints.openai.api_server",
      "--model", "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B", # Update to new Repo ID
      "--max-model-len", "32768",
      "--enforce-eager" # Recommended for GDC stability
    ]
    
  4. שינוי משאבי ה-GPU והזיכרון:

    מודלים גדולים יותר דורשים יותר VRAM למשקלים ולמטמון KV. אם עוברים ממודל 4B למודל 8B או 14B, צריך לוודא שמגבלות המשאבים מספיקות כדי למנוע קריסות של 'אין זיכרון פנוי (OOM)'.

    • השימוש בזיכרון VRAM: בדיוק של 16 ביט, מודל של 8B דורש כ-16GB רק בשביל המשקלים, בנוסף לזיכרון נוסף בשביל מטמון ה-vLLM PagedAttention.
    • המלצה: כדי להבטיח ביצועים אופטימליים ומרחב פעולה למטמון KV, מומלץ להשתמש ב-GPU מלא מסוג A100 ‏(nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1) למודלים עם יותר מ-7 מיליארד פרמטרים.
  5. מאמתים את המודל החדש:

    אחרי שהפריסה מסתיימת, מאמתים שהמודל החדש פעיל באמצעות ה-API הפנימי:

    # Inside a debug-sh pod
    wget -qO- http://gemma-3-4b-it/v1/models
    

    תגובה להצלחה:

    {"object":"list","data":[{"id":"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B"}]}
    

שימוש במודל שפה גדול (LLM) אחר עם Ollama

אם רוצים לנסות מודל שפה גדול (LLM) אחר בקוד פתוח, כמו מודל מהמשפחות Llama 3.2 או DeepSeek-R1, צריך לשנות את פקודת Ollama הזו ב-Dockerfile הקודם:

ollama pull gemma3:latest

לדוגמה, אם רוצים למשוך את Llama 3.2 עם 3 מיליארד פרמטרים, משתמשים בפקודה הבאה:

ollama pull llama3.2:3b

לחלופין, אם אתם מעדיפים להשתמש ב-DeepSeek-R1 עם 8 מיליארד פרמטרים, תוכלו להשתמש בפקודה הזו:

ollama pull deepseek-r1:8b

אפשר גם להוריד יותר ממודל LLM אחד ולכלול את משקלי המודל שלהם במאגר. לאחר מכן, Ollama יוכל לעבור בין מודלים כשמבקשים מסקנות על ידי מודלים שונים שנטענו מראש. לדוגמה, אפשר להוסיף גם את מודל Gemma וגם את מודל Llama לקובץ האימג' של Docker. כפי שציינו, בסביבה עם פער אוויר, ל-Ollama backend אין גישה לספריית Ollama כדי להוריד מודל כלשהו בכל שלב.

חשוב לזכור לבדוק את הרישיון ואת תנאי השימוש של כל מודל ולאשר אותם לפני שמריצים את המודלים באפליקציות. יש הרבה מודלי שפה גדולים בספרייה של Ollama. תצטרכו חיבור לאינטרנט רק כדי להוריד את משקלי המודל בזמן בניית קובץ אימג' של Docker של ה-LLM backend.

פתיחת ממשק משתמש באינטרנט

בודקים אם ה-pod של Open WebUI נמצא במצב פעיל :

kubectl get pods -n NAMESPACE

הפלט הצפוי :

NAME                             READY   STATUS    RESTARTS   AGE
open-webui-69df4664d-przjl       1/1     Running   0          6d3h

בודקים את כתובת ה-IP של השירות :

kubectl get service -n NAMESPACE

הפלט אמור להיראות כך:

NAME          TYPE            CLUSTER-IP       EXTERNAL-IP      PORT(S)           AGE
open-webui     LoadBalancer   10.201.137.164   136.125.37.224   80:30492/TCP      6d3h

בקטעים הבאים מוסבר איך להשתמש בתכונות העיקריות של ממשק המשתמש.

פתיחת תרשים של ממשק המשתמש של WebUI.

הרחבת הפתרון באמצעות קצה עורפי של Ollama

אנכית

  • כדאי להקצות פרוסה גדולה יותר של GPU למודל שפה גדול שהפך לצוואר בקבוק, עד שתשתמשו ב-GPU מלא.
  • אם רוצים להשתמש ב-LLM גדול יותר כדי לקבל תשובות מדויקות יותר, למשל LLM עם 405 מיליארד פרמטרים במקום 7 מיליארד, יכול להיות שתצטרכו יותר מ-GPU אחד כדי להריץ אותו בצורה חלקה.
  • מודלים שמתאימים ליותר מיחידת GPU אחת חווים השהיה שקשורה לתקשורת בין יחידות ה-GPU.

אופקית

  • פורסים כמה פודים של Ollama שצריך כדי להשיג את קצב העברת הנתונים הרצוי במודל שפה גדול (LLM) נתון.
    • כדי לעשות את זה, מגדילים את מספר העותקים בקובץ ה-YAML של פריסת Ollama המתאים.
  • שירות Kubernetes, מסוג LoadBalancer, יפיץ בקשות לעזרה בכתיבת קוד בין נקודות קצה (כלומר, pods) ויחזיר את התגובות המתאימות דרך כתובת ה-IP החיצונית שנחשפת.
  • חשוב לזכור שהתוסף Continue מצביע רק על כתובת IP אחת לכל פונקציונליות.

דיאגרמת ארכיטקטורה של סקייל של LLM עם משקלים פתוחים.

כדי לשנות את קנה המידה של קצה העורפי (backend) של vLLM בסביבת GDC עם בידוד פיזי, אפשר לפעול לפי אסטרטגיה דומה לזו שמשמשת ל-Ollama, ולהתמקד בהקצאת משאבי חומרה ובשכפול של פודים.

הרחבת הפתרון באמצעות קצה עורפי של vLLM

אנכית

  • שדרוג הקצאת ה-GPU: אם קצב העברת הנתונים של ההסקה (טוקנים/שנייה) הופך לצוואר בקבוק, צריך להקצות פרוסת GPU גדולה יותר עד לשימוש ב-GPU מלא של NVIDIA A100.
  • תצורות של כמה מעבדי GPU: כדי להשתמש במודלים גדולים מאוד (לדוגמה, פרמטרים של 70B עד 405B) שלא נכנסים לזיכרון של A100 יחיד בנפח 80GB, צריך להגדיל את מספר מעבדי ה-GPU באמצעות מקביליות טנסורית.
  • שיקולים לגבי זמן האחזור: שימו לב שייתכן שיהיה תקורה קלה בדגמים שמשתרעים על יותר מ-GPU אחד, שקשורה לתקשורת בין ה-GPU (לדוגמה, סנכרון NCCL).

אופקית

  • הגדלת התפוקה באמצעות רפליקות: כדי לטפל בנפח גדול יותר של בקשות משתמשים בו-זמניות עבור אותו מודל, מגדילים את replicas מספר הרפליקות בקובץ ה-YAML של פריסת vLLM.
  • מופעים ייעודיים של מודלים: מכיוון ש-vLLM מתוכנן כמנוע להצגת מודל יחיד ומצמיד את זיכרון מטמון KV שלו במהלך האתחול, צריך לפרוס קבוצה נפרדת של פודים לכל LLM שרוצים לארח.
  • איזון עומסים: שירות GDC Kubernetes (סוג LoadBalancer) יפיץ באופן אוטומטי בקשות הסקה נכנסות בין כל נקודות הקצה של vLLM pod שמשויכות לשירות הזה.

פתרון בעיות

שגיאה צמצום הפגיעה
FIPS SELFTEST FAILURE השגיאה הזו מתרחשת כשחסרים חתימות שלמות בספריות כמו BoringSSL. תיקון באמצעות הגדרת BORINGSSL_FIPS=0 ושימוש בתמונות vLLM רשמיות
טעינת משקל מושהית בודקים אם יש הגבלת IOPS ב-PVC קטנים. נדרש נפח אחסון של 500GiB כדי לאתחל את מודל הביצועים.
החיבור נדחה מוודאים ש-PNP מאפשר באופן מפורש את targetPort ‏ (8000/8080). חומות האש של GDC לא מעניקות אוטומטית גישה ליציאות של השרתים העורפיים עבור כתובות ה-VIP של מאזן העומסים.