Ollama als Worker-Pool für die Inferenz hosten

1. Einführung

Übersicht

In diesem Codelab erfahren Sie, wie Sie eine ereignisgesteuerte, asynchrone KI-Verarbeitungspipeline erstellen. Sie stellen ein Open-Source-Modell mit Ollama in einem Cloud Run-Worker-Pool bereit. Der Worker-Pool ruft Nachrichten aus einem Pub/Sub-Thema ab und verarbeitet sie mit einem gemma3:4b-Modell.

Lerninhalte

  • Worker-Pools mit einem Pub/Sub-Pull-Abo verwenden
  • Ollama für die Inferenz als Worker-Pool verwenden

2. Hinweis

APIs aktivieren

Bevor Sie mit diesem Codelab beginnen können, müssen Sie die folgenden APIs aktivieren. Führen Sie dazu folgenden Befehl aus:

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

3. Einrichtung und Anforderungen

So richten Sie die erforderlichen Ressourcen ein:

  1. Legen Sie Umgebungsvariablen für dieses Codelab fest:
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. Dienstkonto für den Worker-Pool erstellen
gcloud iam service-accounts create ${SERVICE_ACCOUNT_NAME} \
  --display-name="Ollama Worker Service Account"
  1. Dienstkonto Zugriff auf Pub/Sub gewähren
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
  --member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
  --role="roles/pubsub.subscriber"
  1. AR-Repository für das Worker-Pool-Image erstellen
gcloud artifacts repositories create ${AR_REPO_NAME} \
  --repository-format=docker \
  --location=${REGION}
  1. Pub/Sub-Thema und -Abo erstellen
gcloud pubsub topics create $TOPIC_NAME
gcloud pubsub subscriptions create $SUBSCRIPTION_NAME --topic $TOPIC_NAME

4. Modell herunterladen und auf GCS hosten

Anstatt das Modell während des Build-Prozesses direkt in den Container zu ziehen, was langsam und ineffizient sein kann, ziehen wir das Modell mit der Ollama-Befehlszeile auf einen lokalen Computer und laden die Modelldateien dann in einen GCS-Bucket hoch. Der Worker-Pool hängt diesen Bucket dann ein, um auf das Modell zuzugreifen.

  1. Ollama auf Ihrem lokalen Computer installieren:

Führen Sie den folgenden Befehl aus, um Ollama unter Linux zu installieren. Informationen zu anderen Betriebssystemen finden Sie auf der Ollama-Website.

curl -fsSL https://ollama.com/install.sh | sh
  1. Ollama-Dienst starten und Modell abrufen:

Starten Sie zuerst den Ollama-Dienst im Hintergrund.

ollama serve &
ollama pull gemma3:4b
  1. GCS-Bucket erstellen:

Erstellen Sie den GCS-Bucket mit der zuvor festgelegten Umgebungsvariable BUCKET_NAME.

gsutil mb gs://${BUCKET_NAME}
  1. Modell-Dateien in Ihren GCS-Bucket hochladen:

Ollama speichert Modelldateien im Verzeichnis ~/.ollama/models. Laden Sie den Inhalt dieses Verzeichnisses in Ihren GCS-Bucket hoch. Dadurch werden alle heruntergeladenen Modelle kopiert.

gsutil -m cp -r ~/.ollama/models/* gs://${BUCKET_NAME}/
  1. Dienstkonto Zugriff auf den Cloud Storage-Bucket gewähren
gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \
     --member=serviceAccount:${SERVICE_ACCOUNT_EMAIL} \
     --role=roles/storage.objectViewer

5. Cloud Run-Job erstellen

Für den Cloud Run-Job werden zwei Container verwendet:

  • ollama-coordinator – zum Hosten von Ollama und Bereitstellen des Gemma 3 4B-Modells
  • pubsub-pull-msg – zum Abrufen von Nachrichten aus dem Pub/Sub-Abo und zum Übergeben der Nachricht an den ollama-coordinator-Container

Zuerst erstellen Sie den ollama-coordinator-Container.

  1. Erstellen Sie ein übergeordnetes Verzeichnis für das Codelab:
mkdir codelab-ollama-wp
cd codelab-ollama-wp
  1. Verzeichnis für den ollama-coordinator-Container erstellen
mkdir ollama-coordinator
cd ollama-coordinator
  1. Erstellen Sie ein Dockerfile mit folgendem Inhalt:
# 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-Container erstellen
gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${OLLAMA_IMAGE_NAME} --timeout=20m

Als Nächstes erstellen Sie den Container „pubsub-pull-msg“.

  1. Verzeichnis für den Container „pubsub-pull-msg“ erstellen
cd ..
mkdir pubsub-pull-msg
cd pubsub-pull-msg
  1. Dockerfile erstellen
# 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. Erstellen Sie eine requirements.txt-Datei mit folgendem Inhalt:
google-cloud-pubsub
requests
  1. Erstellen Sie eine main.py-Datei mit folgendem Inhalt:
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. Erstellen Sie nun den Container „pubsub-pull-msg“.
gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${PULL_MSG_IMAGE_NAME}

6. Job bereitstellen und ausführen

In diesem Schritt erstellen Sie den Cloud Run-Job, indem Sie eine YAML-Datei bereitstellen.

Wechseln Sie zum Stammordner, um die YAML-Datei zu erstellen.

cd ..
  1. Erstellen Sie eine worker-pool.template.yaml-Datei mit folgendem Inhalt:
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

Definieren Sie dann die vollständigen Bild-URLs und verwenden Sie sed, um die Variablen in der Vorlagendatei zu ersetzen und die endgültige worker-pool.yaml zu erstellen.

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

Jetzt können Sie die Bereitstellung vornehmen.

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

Und Test

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

Sehen Sie sich dann die Logs an. Möglicherweise müssen Sie eine Minute warten. Alternativ können Sie die Logs in Echtzeit auf der Seite „Worker-Pool“ in der Cloud Console ansehen.

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

Sie sollten dann Folgendes sehen:

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

7. Glückwunsch!

Herzlichen Glückwunsch zum Abschluss des Codelabs!

Wir empfehlen, die Cloud Run-Dokumentation zu lesen.

Behandelte Themen

  • Cloud Run-Worker-Pools mit einem Pub/Sub-Pull-Abo verwenden
  • Ollama für die Inferenz als Cloud Run-Worker-Pool verwenden

8. Bereinigen

Damit Ihrem Google Cloud-Konto die in dieser Anleitung verwendeten Ressourcen nicht in Rechnung gestellt werden, können Sie entweder das Projekt löschen, das die Ressourcen enthält, oder das Projekt beibehalten und die einzelnen Ressourcen löschen.

Projekt löschen

Am einfachsten vermeiden Sie weitere Kosten durch Löschen des für die Anleitung erstellten Projekts.

So löschen Sie das Projekt:

  1. Wechseln Sie in der Google Cloud Console zur Seite Ressourcen verwalten.
  2. Wählen Sie in der Projektliste das Projekt aus, das Sie löschen möchten, und klicken Sie auf Löschen.
  3. Geben Sie im Dialogfeld die Projekt-ID ein und klicken Sie auf Beenden, um das Projekt zu löschen.

Einzelne Ressourcen löschen

Führen Sie die folgenden Befehle aus, um die einzelnen Ressourcen zu löschen:

  1. Löschen Sie den Cloud Run-Worker-Pool:
gcloud beta run worker-pools delete codelab-ollama-wp --region ${REGION}
  1. Löschen Sie den GCS-Bucket:
gsutil -m rm -r gs://${BUCKET_NAME}
  1. Löschen Sie das Pub/Sub-Abo und -Thema:
gcloud pubsub subscriptions delete ${SUBSCRIPTION_NAME}
gcloud pubsub topics delete ${TOPIC_NAME}
  1. Löschen Sie das Artifact Registry-Repository:
gcloud artifacts repositories delete ${AR_REPO_NAME} --location=${REGION} --quiet
  1. Löschen Sie das Dienstkonto:
gcloud iam service-accounts delete ${SERVICE_ACCOUNT_EMAIL} --quiet

Lokale Dateien bereinigen

So bereinigen Sie lokale Dateien:

  1. Lokalen Ollama-Dienst beenden:Wenn Sie Ollama mit ollama serve & gestartet haben, können Sie den Dienst beenden, indem Sie die Prozess-ID (PID) ermitteln und dann den Befehl kill verwenden.
    # 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. Löschen Sie die heruntergeladenen Modelle:
rm -rf ~/.ollama/models
  1. Ollama deinstallieren:

Folgen Sie der Anleitung auf der Ollama-Website, um Ollama von Ihrem lokalen Computer zu deinstallieren.