1. Introducción
Descripción general
En este codelab, aprenderás a compilar una canalización de procesamiento de IA asíncrona y basada en eventos. Implementarás un modelo de código abierto con Ollama en un grupo de trabajadores de Cloud Run. El grupo de trabajadores extrae mensajes de un tema de Pub/Sub y los procesa con un modelo de gemma3:4b.
Qué aprenderás
- Cómo usar grupos de trabajadores con una suscripción de extracción de Pub/Sub
- Cómo usar Ollama para realizar inferencias como un grupo de trabajadores
2. Antes de comenzar
Habilita las APIs
Antes de comenzar a usar este codelab, habilita las siguientes APIs ejecutando el siguiente comando:
gcloud services enable run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
pubsub.googleapis.com \
storage.googleapis.com
3. Configuración y requisitos
Para configurar los recursos necesarios, sigue estos pasos:
- Configura las variables de entorno para este 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 una cuenta de servicio para el grupo de trabajadores
gcloud iam service-accounts create ${SERVICE_ACCOUNT_NAME} \
--display-name="Ollama Worker Service Account"
- Otorga acceso a Pub/Sub a la SA
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
--role="roles/pubsub.subscriber"
- Crea un repositorio de RA para la imagen del grupo de trabajadores
gcloud artifacts repositories create ${AR_REPO_NAME} \
--repository-format=docker \
--location=${REGION}
- Crea el tema y la suscripción de Pub/Sub
gcloud pubsub topics create $TOPIC_NAME
gcloud pubsub subscriptions create $SUBSCRIPTION_NAME --topic $TOPIC_NAME
4. Descarga y aloja el modelo en GCS
En lugar de extraer el modelo directamente dentro del contenedor durante el proceso de compilación, lo que puede ser lento e ineficiente, extraeremos el modelo a una máquina local con la CLI de Ollama y, luego, subiremos los archivos del modelo a un bucket de GCS. Luego, el grupo de trabajadores activará el bucket para acceder al modelo.
- Instala Ollama en tu equipo local:
Ejecuta el siguiente comando para instalar Ollama en Linux. Para otros sistemas operativos, consulta el sitio web de Ollama.
curl -fsSL https://ollama.com/install.sh | sh
- Inicia el servicio de Ollama y extrae el modelo:
Primero, inicia el servicio de Ollama en segundo plano.
ollama serve &
ollama pull gemma3:4b
- Crea un bucket de GCS:
Crea el bucket de GCS con la variable de entorno BUCKET_NAME que configuraste antes.
gsutil mb gs://${BUCKET_NAME}
- Sube los archivos del modelo a tu bucket de GCS:
Ollama almacena los archivos de modelo en el directorio ~/.ollama/models. Sube el contenido de este directorio a tu bucket de GCS. Se copiarán todos los modelos que descargaste.
gsutil -m cp -r ~/.ollama/models/* gs://${BUCKET_NAME}/
- Otorga acceso a la SA al bucket de Cloud Storage
gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \
--member=serviceAccount:${SERVICE_ACCOUNT_EMAIL} \
--role=roles/storage.objectViewer
5. Crea el trabajo de Cloud Run
El trabajo de Cloud Run usa 2 contenedores:
- ollama-coordinator: Para alojar Ollama y entregar el modelo Gemma 3 4B
- pubsub-pull-msg: Para extraer de la suscripción de Pub/Sub y pasar el mensaje al contenedor de ollama-coordinator
Primero, crearás el contenedor ollama-coordinator.
- Crea un directorio principal para el codelab:
mkdir codelab-ollama-wp
cd codelab-ollama-wp
- Crea un directorio para el contenedor de ollama-coordinator
mkdir ollama-coordinator
cd ollama-coordinator
- Crea un
Dockerfilecon el siguiente contenido:
# 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"]
- Compila el contenedor de Ollama
gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${OLLAMA_IMAGE_NAME} --timeout=20m
A continuación, crearás el contenedor pubsub-pull-msg.
- Crea un directorio para el contenedor pubsub-pull-msg
cd ..
mkdir pubsub-pull-msg
cd pubsub-pull-msg
- Cómo crear 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 archivo
requirements.txtcon el siguiente contenido:
google-cloud-pubsub
requests
- Crea un archivo
main.pycon el siguiente contenido:
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()
- Ahora compila el contenedor pubsub-pull-msg
gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${PULL_MSG_IMAGE_NAME}
6. Implementa y ejecuta el trabajo
En este paso, crearás el trabajo de Cloud Run implementando un archivo YAML.
Muévete a la carpeta raíz para crear el archivo YAML.
cd ..
- Crea un archivo
worker-pool.template.yamlcon el siguiente contenido:
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
Luego, define las URLs de las imágenes completas y usa sed para sustituir las variables en el archivo de plantilla, lo que creará el worker-pool.yaml final.
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
Ahora puedes implementar
gcloud beta run worker-pools replace worker-pool.yaml
Y prueba
gcloud pubsub topics publish ${TOPIC_NAME} --message="What is 1 + 1?"
Luego, visualiza los registros. Es posible que debas esperar un minuto o puedes ir a la página del grupo de trabajadores de Cloud Console y mirar los registros en tiempo real.
gcloud alpha run worker-pools logs read "codelab-ollama-wp" --limit 10
y deberías ver algo que diga
Ollama response: {"model": "gemma3:4b", "created_at": "2025-11-06T23:48:39.572079369Z", "response": "1 + 1 = 2\n", ...
7. ¡Felicitaciones!
¡Felicitaciones por completar el codelab!
Te recomendamos que revises la documentación de Cloud Run.
Temas abordados
- Cómo usar grupos de trabajadores de Cloud Run con una suscripción de extracción de Pub/Sub
- Cómo usar Ollama para realizar inferencias como un grupo de trabajadores de Cloud Run
8. Limpia
Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos usados en este instructivo, borra el proyecto que contiene los recursos o conserva el proyecto y borra los recursos individuales.
Borra el proyecto
La manera más fácil de eliminar la facturación es borrar el proyecto que creaste para el instructivo.
Para borrar el proyecto, haz lo siguiente:
- En la consola de Google Cloud, ve a la página Administrar recursos.
- En la lista de proyectos, elige el proyecto que deseas borrar y haz clic en Borrar.
- En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrarlo.
Borra recursos individuales
Para borrar los recursos individuales, ejecuta los siguientes comandos:
- Borra el grupo de trabajadores de Cloud Run:
gcloud beta run worker-pools delete codelab-ollama-wp --region ${REGION}
- Borra el bucket de GCS:
gsutil -m rm -r gs://${BUCKET_NAME}
- Borra el tema y la suscripción de Pub/Sub:
gcloud pubsub subscriptions delete ${SUBSCRIPTION_NAME}
gcloud pubsub topics delete ${TOPIC_NAME}
- Borra el repositorio de Artifact Registry:
gcloud artifacts repositories delete ${AR_REPO_NAME} --location=${REGION} --quiet
- Borra la cuenta de servicio:
gcloud iam service-accounts delete ${SERVICE_ACCOUNT_EMAIL} --quiet
Cómo limpiar archivos locales
Para limpiar los archivos locales, haz lo siguiente:
- Detén el servicio local de Ollama:Si iniciaste Ollama con
ollama serve &, puedes detenerlo buscando su ID de proceso (PID) y, luego, usando el 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> - Borra los modelos descargados:
rm -rf ~/.ollama/models
- Desinstala Ollama:
Sigue las instrucciones del sitio web de Ollama para desinstalar Ollama de tu equipo local.