איך מארחים את Ollama כמאגר עובדים להסקת מסקנות

1. מבוא

סקירה כללית

ב-Codelab הזה תלמדו איך ליצור צינור עיבוד נתונים אסינכרוני מבוסס-אירועים של עיבוד באמצעות AI. תפרסו מודל קוד פתוח באמצעות Ollama במאגר עובדים של Cloud Run. מאגר העובדים שולף הודעות מנושא Pub/Sub ומעבד אותן באמצעות מודל gemma3:4b.

מה תלמדו

  • איך משתמשים במאגרי worker עם מינוי שליפה של Pub/Sub
  • איך משתמשים ב-Ollama כדי לבצע הסקה כמאגר עובדים

‫2. לפני שמתחילים

הפעלת ממשקי ה-API

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

gcloud services enable run.googleapis.com \
    cloudbuild.googleapis.com \
    artifactregistry.googleapis.com \
    pubsub.googleapis.com \
    storage.googleapis.com

‫3. הגדרה ודרישות

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

  1. מגדירים את משתני הסביבה של ה-Codelab הזה:
export PROJECT_ID=<YOUR_PROJECT_ID>
export REGION=<YOUR_REGION>

export BUCKET_NAME=$PROJECT_ID-gemma3-4b
export SERVICE_ACCOUNT_NAME=ollama-worker-sa
export SERVICE_ACCOUNT_EMAIL=${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com
export TOPIC_NAME=ollama-prompts
export SUBSCRIPTION_NAME=ollama-prompts-sub
export AR_REPO_NAME=ollama-worker-repo
export PULL_MSG_IMAGE_NAME=pubsub-pull-msg
export OLLAMA_IMAGE_NAME=ollama-coordinator
  1. יצירת חשבון שירות למאגר העובדים
gcloud iam service-accounts create ${SERVICE_ACCOUNT_NAME} \
  --display-name="Ollama Worker Service Account"
  1. הענקת גישה לחשבון השירות ל-Pub/Sub
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
  --role="roles/pubsub.subscriber"
  1. יצירת מאגר AR לתמונה של מאגר העובדים
gcloud artifacts repositories create ${AR_REPO_NAME} \
  --repository-format=docker \
  --location=${REGION}
  1. יצירת נושא ומינוי ב-PubSub
gcloud pubsub topics create $TOPIC_NAME
gcloud pubsub subscriptions create $SUBSCRIPTION_NAME --topic $TOPIC_NAME

4. הורדה ואירוח של המודל ב-GCS

במקום לשלוף את המודל ישירות בתוך הקונטיינר במהלך תהליך build, מה שעלול להיות איטי ולא יעיל, נשלוף את המודל למכונה מקומית באמצעות Ollama CLI ואז נעלה את קובצי המודל לקטגוריית GCS. לאחר מכן, מאגר העובדים יטען את הקטגוריה הזו כדי לגשת למודל.

  1. מתקינים את Ollama במחשב המקומי:

מריצים את הפקודה הבאה כדי להתקין את Ollama ב-Linux. למערכות הפעלה אחרות, אפשר לעיין באתר Ollama.

curl -fsSL https://ollama.com/install.sh | sh
  1. מפעילים את שירות Ollama ומורידים את המודל:

קודם כול, מפעילים את שירות Ollama ברקע.

ollama serve &
ollama pull gemma3:4b
  1. יצירת קטגוריית GCS:

יוצרים את קטגוריית GCS באמצעות משתנה הסביבה BUCKET_NAME שהגדרתם קודם.

gsutil mb gs://${BUCKET_NAME}
  1. מעלים את קובצי המודל לקטגוריה של GCS:

‫Ollama מאחסן קבצים של מודלים בספרייה ~/.ollama/models. מעלים את התוכן של הספרייה הזו לקטגוריית GCS. כל המודלים שהורדתם יועתקו.

gsutil -m cp -r ~/.ollama/models/* gs://${BUCKET_NAME}/
  1. הענקת גישה לחשבון השירות לקטגוריה של Cloud Storage
gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \
     --member=serviceAccount:${SERVICE_ACCOUNT_EMAIL} \
     --role=roles/storage.objectViewer

5. יצירת משימה ב-Cloud Run

הג'וב ב-Cloud Run משתמש ב-2 קונטיינרים:

  • ollama-coordinator – לאירוח של ollama ולהצגת מודל gemma 3 4B
  • ‫pubsub-pull-msg – לשליפה ממינוי pubsub ולהעברת ההודעה לקונטיינר ollama-coordinator

קודם יוצרים את מאגר התגים ollama-coordinator.

  1. יוצרים ספריית אב בשביל ה-codelab:
mkdir codelab-ollama-wp
cd codelab-ollama-wp
  1. יוצרים ספרייה בשביל מאגר ollama-coordinator
mkdir ollama-coordinator
cd ollama-coordinator
  1. יוצרים קובץ Dockerfile עם התוכן הבא
# Use the official Ollama image as a base image
FROM ollama/ollama

# Expose the port that Ollama listens on
EXPOSE 11434

# Set the entrypoint to start the Ollama server
ENTRYPOINT ["ollama", "serve"]
  1. יוצרים את קונטיינר ollama
gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${OLLAMA_IMAGE_NAME} --timeout=20m

בשלב הבא, יוצרים את מאגר התגים pubsub-pull-msg.

  1. יצירת ספרייה לקונטיינר pubsub-pull-msg
cd ..
mkdir pubsub-pull-msg
cd pubsub-pull-msg
  1. צור Dockerfile
# Use the official Python image as a base image
FROM python:3.9-slim

# Set the working directory in the container
WORKDIR /app

# Copy the requirements file into the container
COPY requirements.txt .

# Install the required Python packages
RUN pip install --no-cache-dir -r requirements.txt

# Copy the Python script into the container
COPY main.py .

# Set the entrypoint to run the Python script
CMD ["python", "main.py"]
  1. יוצרים קובץ requirements.txt עם התוכן הבא
google-cloud-pubsub
requests
  1. יוצרים קובץ main.py עם התוכן הבא
import os
import sys
import requests
import json
from google.cloud import pubsub_v1

# --- Main Application Logic ---
print("--- Sidecar container script started ---")

# --- Environment and Configuration ---
project_id = os.environ.get("PROJECT_ID")
subscription_name = os.environ.get("SUBSCRIPTION_NAME")
ollama_api_url = "http://localhost:11434/api/generate"

if not project_id or not subscription_name:
    print("FATAL: PROJECT_ID and SUBSCRIPTION_NAME must be set.")
    sys.exit(1)

print(f"PROJECT_ID: {project_id}")
print(f"SUBSCRIPTION_NAME: {subscription_name}")

def callback(message):
    """Processes a single Pub/Sub message."""
    print(f"Received message ID: {message.message_id}")
    try:
        prompt = message.data.decode("utf-8")
        print(f"Decoded prompt: '{prompt}'")
        
        data = {"model": "gemma3:4b", "prompt": prompt, "stream": False}
        
        print("Sending request to Ollama...")
        response = requests.post(ollama_api_url, json=data, timeout=300)
        response.raise_for_status()
        
        print("Successfully received response from Ollama.")
        ollama_response = response.json()
        print(f"Ollama response: {json.dumps(ollama_response)[:200]}...")

        message.ack()
        print(f"Message {message.message_id} acknowledged.")

    except requests.exceptions.RequestException as e:
        print(f"Error calling Ollama API: {e}")
        message.nack()
        print(f"Message {message.message_id} not acknowledged.")
    except Exception as e:
        print(f"An unexpected error occurred in callback: {e}")
        message.nack()
        print(f"Message {message.message_id} not acknowledged.")

def main():
    """Starts the Pub/Sub subscriber."""
    subscriber = pubsub_v1.SubscriberClient()
    subscription_path = subscriber.subscription_path(project_id, subscription_name)
    
    streaming_pull_future = subscriber.subscribe(subscription_path, callback=callback)
    print(f"Subscribed to {subscription_path}. Listening for messages...")

    try:
        # .result() will block indefinitely.
        streaming_pull_future.result()
    except Exception as e:
        print(f"A fatal error occurred in the subscriber: {e}")
        streaming_pull_future.cancel()
        streaming_pull_future.result()

if __name__ == "__main__":
    main()
  1. עכשיו בונים את הקונטיינר pubsub-pull-msg
gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${PULL_MSG_IMAGE_NAME}

6. פריסה והפעלה של המשימה

בשלב הזה תיצרו את משימת Cloud Run על ידי פריסת קובץ YAML.

עוברים לתיקיית הבסיס כדי ליצור את קובץ ה-YAML.

cd ..
  1. יוצרים קובץ worker-pool.template.yaml עם התוכן הבא
apiVersion: run.googleapis.com/v1
kind: WorkerPool
metadata:
  name: codelab-ollama-wp
  labels:
    cloud.googleapis.com/location: europe-west1
  annotations:
    run.googleapis.com/launch-stage: BETA
    run.googleapis.com/scalingMode: manual
    run.googleapis.com/manualInstanceCount: '1'
    run.googleapis.com/gcs-fuse-mounter-enabled: "true"
spec:
  template:
    metadata:
      annotations:
        run.googleapis.com/gpu: "1"
        run.googleapis.com/gpu-zonal-redundancy-disabled: 'true'        
    spec:
      serviceAccountName: ${SERVICE_ACCOUNT_EMAIL}
      nodeSelector:
        run.googleapis.com/accelerator: nvidia-l4
      volumes:
      - name: gcs-bucket
        csi:
          driver: gcsfuse.run.googleapis.com
          readOnly: true
          volumeAttributes: 
            bucketName: ${BUCKET_NAME}
      containers:
      - image: ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${PULL_MSG_IMAGE_NAME}
        name: pubsub-pull-msg
        env:
        - name: PROJECT_ID
          value: ${PROJECT_ID}
        - name: SUBSCRIPTION_NAME
          value: "ollama-prompts-sub"
        - name: PYTHONUNBUFFERED
          value: "1"
        resources:
          limits:
            cpu: '1'
            memory: 1Gi
      - image: ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${OLLAMA_IMAGE_NAME}
        name: ollama-coordinator
        env:
        - name: OLLAMA_MODELS
          value: /mnt/models
        volumeMounts:
        - name: gcs-bucket
          mountPath: /mnt/models
        resources:
          limits:
            cpu: '6'
            nvidia.com/gpu: '1'
            memory: 16Gi

לאחר מכן, מגדירים את כתובות ה-URL המלאות של התמונות ומשתמשים ב-sed כדי להחליף את המשתנים בקובץ התבנית, וכך ליצור את worker-pool.yaml הסופי.

sed -e "s|\${SERVICE_ACCOUNT_EMAIL}|${SERVICE_ACCOUNT_EMAIL}|g" \
     -e "s|\${BUCKET_NAME}|${BUCKET_NAME}|g" \
     -e "s|\${PULL_MSG_IMAGE_NAME}|${PULL_MSG_IMAGE_NAME}|g" \
     -e "s|\${OLLAMA_IMAGE_NAME}|${OLLAMA_IMAGE_NAME}|g" \
     -e "s|\${PROJECT_ID}|${PROJECT_ID}|g" \
     -e "s|\${REGION}|${REGION}|g" \
     -e "s|\${AR_REPO_NAME}|${AR_REPO_NAME}|g" \
     worker-pool.template.yaml > worker-pool.yaml

עכשיו אפשר לפרוס

gcloud beta run worker-pools replace worker-pool.yaml

בדיקה

gcloud pubsub topics publish ${TOPIC_NAME} --message="What is 1 + 1?"

ואז צופים ביומנים. יכול להיות שתצטרכו לחכות דקה, או שתוכלו לעבור אל דף מאגר העובדים במסוף Cloud ולצפות ביומנים בזמן אמת.

gcloud alpha run worker-pools logs read "codelab-ollama-wp" --limit 10

אמור להופיע משהו כמו

Ollama response: {"model": "gemma3:4b", "created_at": "2025-11-06T23:48:39.572079369Z", "response": "1 + 1 = 2\n", ...

7. מעולה!

כל הכבוד, סיימתם את ה-Codelab!

מומלץ לעיין במסמכי התיעוד של Cloud Run.

מה נכלל

  • איך משתמשים במאגרי עובדים של Cloud Run עם מינוי Pub/Sub Pull
  • איך משתמשים ב-Ollama כדי לבצע היסק כמאגר עובדים של Cloud Run

8. הסרת המשאבים

כדי להימנע מחיובים בחשבון Google Cloud בגלל השימוש במשאבים שנעשה במסגרת המדריך הזה, אפשר למחוק את הפרויקט שמכיל את המשאבים, או להשאיר את הפרויקט ולמחוק את המשאבים בנפרד.

מחיקת הפרויקט

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

כדי למחוק את הפרויקט:

  1. במסוף Google Cloud, עוברים לדף Manage resources.
  2. ברשימת הפרויקטים, בוחרים את הפרויקט שרוצים למחוק ולוחצים על Delete.
  3. כדי למחוק את הפרויקט, כותבים את מזהה הפרויקט בתיבת הדו-שיח ולוחצים על Shut down.

מחיקה של משאבים ספציפיים

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

  1. מוחקים את מאגר העובדים של Cloud Run:
gcloud beta run worker-pools delete codelab-ollama-wp --region ${REGION}
  1. מוחקים את קטגוריית ה-GCS:
gsutil -m rm -r gs://${BUCKET_NAME}
  1. מחיקת המינוי והנושא ב-Pub/Sub:
gcloud pubsub subscriptions delete ${SUBSCRIPTION_NAME}
gcloud pubsub topics delete ${TOPIC_NAME}
  1. מחיקת המאגר ב-Artifact Registry:
gcloud artifacts repositories delete ${AR_REPO_NAME} --location=${REGION} --quiet
  1. מוחקים את חשבון השירות:
gcloud iam service-accounts delete ${SERVICE_ACCOUNT_EMAIL} --quiet

ניקוי קבצים מקומיים

כדי לנקות קבצים מקומיים:

  1. מפסיקים את שירות Ollama המקומי:אם הפעלתם את Ollama באמצעות ollama serve &, תוכלו להפסיק אותו על ידי איתור מזהה התהליך (PID) שלו ואז שימוש בפקודה kill.
    # Find the process ID of the Ollama server
    pgrep ollama
    
    # Replace <PID> with the actual process ID obtained from the previous command
    kill <PID>
    
  2. מחיקת המודלים שהורדתם:
rm -rf ~/.ollama/models
  1. מסירים את ההתקנה של Ollama:

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