1. Introduzione
Panoramica
In questo codelab imparerai a creare una pipeline di elaborazione AI asincrona basata su eventi. Esegui il deployment di un modello open source utilizzando Ollama in un pool di worker Cloud Run. Il pool di worker estrae i messaggi da un argomento Pub/Sub e li elabora utilizzando un modello gemma3:4b.
Obiettivi didattici
- Utilizzare i pool di worker con una sottoscrizione pull Pub/Sub
- Come utilizzare Ollama per eseguire l'inferenza come pool di worker
2. Prima di iniziare
Abilita API
Prima di poter iniziare a utilizzare questo codelab, abilita le seguenti API eseguendo:
gcloud services enable run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
pubsub.googleapis.com \
storage.googleapis.com
3. Configurazione e requisiti
Per configurare le risorse richieste:
- Imposta le variabili di ambiente per questo 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
- Crea un service account per il pool di worker
gcloud iam service-accounts create ${SERVICE_ACCOUNT_NAME} \
--display-name="Ollama Worker Service Account"
- Concedi al service account l'accesso a Pub/Sub
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
--role="roles/pubsub.subscriber"
- Crea un repository AR per l'immagine del pool di worker
gcloud artifacts repositories create ${AR_REPO_NAME} \
--repository-format=docker \
--location=${REGION}
- Crea l'argomento e la sottoscrizione Pub/Sub
gcloud pubsub topics create $TOPIC_NAME
gcloud pubsub subscriptions create $SUBSCRIPTION_NAME --topic $TOPIC_NAME
4. Scaricare e ospitare il modello su GCS
Anziché estrarre il modello direttamente all'interno del container durante il processo di build, che può essere lento e inefficiente, lo estrarremo in una macchina locale utilizzando la CLI Ollama e poi caricheremo i file del modello in un bucket GCS. Il pool di worker monterà questo bucket per accedere al modello.
- Installa Ollama sulla tua macchina locale:
Esegui questo comando per installare Ollama su Linux. Per altri sistemi operativi, consulta il sito web di Ollama.
curl -fsSL https://ollama.com/install.sh | sh
- Avvia il servizio Ollama ed estrai il modello:
Per prima cosa, avvia il servizio Ollama in background.
ollama serve &
ollama pull gemma3:4b
- Crea un bucket GCS:
Crea il bucket GCS utilizzando la variabile di ambiente BUCKET_NAME che hai impostato in precedenza.
gsutil mb gs://${BUCKET_NAME}
- Carica i file del modello nel bucket GCS:
Ollama archivia i file del modello nella directory ~/.ollama/models. Carica i contenuti di questa directory nel bucket GCS. Verranno copiati tutti i modelli che hai scaricato.
gsutil -m cp -r ~/.ollama/models/* gs://${BUCKET_NAME}/
- Concedi all'account di servizio l'accesso al bucket Cloud Storage
gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \
--member=serviceAccount:${SERVICE_ACCOUNT_EMAIL} \
--role=roles/storage.objectViewer
5. Crea il job Cloud Run
Il job Cloud Run utilizza due container:
- ollama-coordinator: per ospitare ollama e distribuire il modello Gemma 3 4B
- pubsub-pull-msg: per eseguire il pull dalla sottoscrizione pubsub e passare il messaggio al contenitore ollama-coordinator
Per prima cosa, crea il container ollama-coordinator.
- Crea una directory principale per il codelab:
mkdir codelab-ollama-wp
cd codelab-ollama-wp
- Crea una directory per il container ollama-coordinator
mkdir ollama-coordinator
cd ollama-coordinator
- Crea un file
Dockerfilecon il seguente contenuto
# 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"]
- Crea il container ollama
gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${OLLAMA_IMAGE_NAME} --timeout=20m
Successivamente, creerai il container pubsub-pull-msg.
- Crea una directory per il container pubsub-pull-msg
cd ..
mkdir pubsub-pull-msg
cd pubsub-pull-msg
- Crea un
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"]
- Crea un file
requirements.txtcon il seguente contenuto
google-cloud-pubsub
requests
- Crea un file
main.pycon il seguente contenuto
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()
- Ora crea il container pubsub-pull-msg
gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${PULL_MSG_IMAGE_NAME}
6. Esegui il deployment ed esegui il job
In questo passaggio, creerai il job Cloud Run eseguendo il deployment di un file YAML.
Sposta nella cartella principale per creare il file YAML.
cd ..
- Crea un file
worker-pool.template.yamlcon il seguente contenuto
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
Poi, definisci gli URL completi delle immagini e utilizza sed per sostituire le variabili nel file modello, creando il worker-pool.yaml finale.
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
Ora puoi eseguire il deployment
gcloud beta run worker-pools replace worker-pool.yaml
E test
gcloud pubsub topics publish ${TOPIC_NAME} --message="What is 1 + 1?"
e poi visualizza i log. Potresti dover attendere un minuto oppure puoi andare alla pagina del pool di worker della console Cloud e guardare i log in tempo reale.
gcloud alpha run worker-pools logs read "codelab-ollama-wp" --limit 10
e dovresti vedere un messaggio che dice
Ollama response: {"model": "gemma3:4b", "created_at": "2025-11-06T23:48:39.572079369Z", "response": "1 + 1 = 2\n", ...
7. Complimenti!
Congratulazioni per aver completato il codelab.
Ti consigliamo di consultare la documentazione di Cloud Run.
Argomenti trattati
- Come utilizzare i pool di worker Cloud Run con una sottoscrizione pull di Pub/Sub
- Come utilizzare Ollama per eseguire l'inferenza come pool di worker Cloud Run
8. Esegui la pulizia
Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.
Elimina il progetto
Il modo più semplice per eliminare la fatturazione è eliminare il progetto creato per il tutorial.
Per eliminare il progetto:
- Nella console Google Cloud, vai alla pagina Gestisci risorse.
- Nell'elenco dei progetti, seleziona il progetto che vuoi eliminare, quindi fai clic su Elimina.
- Nella finestra di dialogo, digita l'ID progetto, quindi fai clic su Chiudi per eliminare il progetto.
Eliminazione di singole risorse
Per eliminare le singole risorse, esegui questi comandi:
- Elimina il pool di worker Cloud Run:
gcloud beta run worker-pools delete codelab-ollama-wp --region ${REGION}
- Elimina il bucket GCS:
gsutil -m rm -r gs://${BUCKET_NAME}
- Elimina l'argomento e la sottoscrizione Pub/Sub:
gcloud pubsub subscriptions delete ${SUBSCRIPTION_NAME}
gcloud pubsub topics delete ${TOPIC_NAME}
- Elimina il repository Artifact Registry:
gcloud artifacts repositories delete ${AR_REPO_NAME} --location=${REGION} --quiet
- Elimina il account di servizio:
gcloud iam service-accounts delete ${SERVICE_ACCOUNT_EMAIL} --quiet
Pulizia dei file locali
Per pulire i file locali:
- Arresta il servizio Ollama locale:se hai avviato Ollama con
ollama serve &, puoi arrestarlo trovando il relativo ID processo (PID) e utilizzando il comandokill.# Find the process ID of the Ollama server pgrep ollama # Replace <PID> with the actual process ID obtained from the previous command kill <PID> - Elimina i modelli scaricati:
rm -rf ~/.ollama/models
- Disinstalla Ollama:
Segui le istruzioni sul sito web di Ollama per disinstallare Ollama dalla tua macchina locale.