1. Введение
Обзор
В этом практическом занятии вы научитесь создавать асинхронный конвейер обработки данных в рамках искусственного интеллекта, управляемый событиями. Вы развернете модель с открытым исходным кодом, используя Ollama, в пуле рабочих процессов Cloud Run. Пул рабочих процессов получает сообщения из топика Pub/Sub и обрабатывает их с помощью модели gemma3:4b.
Что вы узнаете
- Как использовать пулы рабочих процессов с подпиской Pub/Sub Pull
- Как использовать Ollama для выполнения инференса в качестве пула рабочих процессов.
2. Прежде чем начать
Включить API
Прежде чем начать использовать этот практический пример, активируйте следующие API, выполнив следующие команды:
gcloud services enable run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
pubsub.googleapis.com \
storage.googleapis.com
3. Настройка и требования
Для настройки необходимых ресурсов выполните следующие шаги:
- Установите переменные среды для этого практического занятия:
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
- Создайте учетную запись службы для пула рабочих пользователей.
gcloud iam service-accounts create ${SERVICE_ACCOUNT_NAME} \
--display-name="Ollama Worker Service Account"
- Предоставьте SA доступ к Pub/Sub
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
--role="roles/pubsub.subscriber"
- Создайте репозиторий дополненной реальности для образа пула рабочих процессов.
gcloud artifacts repositories create ${AR_REPO_NAME} \
--repository-format=docker \
--location=${REGION}
- Создайте тему и подписку PubSub.
gcloud pubsub topics create $TOPIC_NAME
gcloud pubsub subscriptions create $SUBSCRIPTION_NAME --topic $TOPIC_NAME
4. Загрузите и разместите модель на GCS.
Вместо того чтобы загружать модель непосредственно в контейнер во время процесса сборки, что может быть медленно и неэффективно, мы загрузим модель на локальный компьютер с помощью CLI Ollama, а затем загрузим файлы модели в хранилище GCS. После этого пул рабочих узлов смонтирует это хранилище для доступа к модели.
- Установите Ollama на свой локальный компьютер:
Для установки Ollama на Linux выполните следующую команду. Информацию по другим операционным системам см. на веб-сайте Ollama .
curl -fsSL https://ollama.com/install.sh | sh
- Запустите службу Ollama и загрузите модель:
Сначала запустите службу Ollama в фоновом режиме.
ollama serve &
ollama pull gemma3:4b
- Создайте корзину GCS:
Создайте сегмент GCS, используя переменную среды BUCKET_NAME , которую вы установили ранее.
gsutil mb gs://${BUCKET_NAME}
- Загрузите файлы модели в свой бакет GCS:
Ollama хранит файлы моделей в каталоге ~/.ollama/models . Загрузите содержимое этого каталога в ваш GCS-хранилище. Это скопирует все загруженные вами модели.
gsutil -m cp -r ~/.ollama/models/* gs://${BUCKET_NAME}/
- Предоставьте администратору доступа к хранилищу 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.
- Создайте родительский каталог для практического задания:
mkdir codelab-ollama-wp
cd codelab-ollama-wp
- Создайте директорию для контейнера ollama-coordinator.
mkdir ollama-coordinator
cd ollama-coordinator
- Создайте
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"]
- Соберите контейнер для ламы.
gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${OLLAMA_IMAGE_NAME} --timeout=20m
Далее вам нужно будет создать контейнер pubsub-pull-msg.
- Создайте директорию для контейнера pubsub-pull-msg.
cd ..
mkdir pubsub-pull-msg
cd pubsub-pull-msg
- Создайте
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"]
- Создайте файл
requirements.txtсо следующим содержимым.
google-cloud-pubsub
requests
- Создайте файл
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()
- Теперь создайте контейнер 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 ..
- Создайте файл
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 Console и посмотреть журналы в режиме реального времени.
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. Поздравляем!
Поздравляем с завершением практического занятия!
Мы рекомендуем ознакомиться с документацией Cloud Run .
Что мы рассмотрели
- Как использовать пулы рабочих процессов Cloud Run с подпиской Pub/Sub Pull
- Как использовать Ollama для выполнения инференса в качестве пула рабочих процессов Cloud Run
8. Уборка
Чтобы избежать списания средств с вашего аккаунта Google Cloud за ресурсы, используемые в этом руководстве, либо удалите проект, содержащий эти ресурсы, либо сохраните проект и удалите отдельные ресурсы.
Удаление проекта
Самый простой способ избежать выставления счетов — удалить проект, созданный для этого урока.
Чтобы удалить проект:
- В консоли Google Cloud перейдите на страницу «Управление ресурсами» .
- В списке проектов выберите проект, который хотите удалить, и нажмите кнопку «Удалить» .
- В диалоговом окне введите идентификатор проекта, а затем нажмите «Завершить» , чтобы удалить проект.
Удаление отдельных ресурсов
Для удаления отдельных ресурсов выполните следующие команды:
- Удалите пул рабочих процессов Cloud Run:
gcloud beta run worker-pools delete codelab-ollama-wp --region ${REGION}
- Удалите корзину GCS:
gsutil -m rm -r gs://${BUCKET_NAME}
- Удалите подписку Pub/Sub и тему:
gcloud pubsub subscriptions delete ${SUBSCRIPTION_NAME}
gcloud pubsub topics delete ${TOPIC_NAME}
- Удалите репозиторий реестра артефактов:
gcloud artifacts repositories delete ${AR_REPO_NAME} --location=${REGION} --quiet
- Удалите учетную запись службы:
gcloud iam service-accounts delete ${SERVICE_ACCOUNT_EMAIL} --quiet
Очистка локальных файлов
Для очистки локальных файлов выполните следующие действия:
- Остановите локальную службу 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> - Удалите загруженные модели:
rm -rf ~/.ollama/models
- Удалите Ollama:
Чтобы удалить Ollama с вашего локального компьютера, следуйте инструкциям на веб-сайте Ollama .