Как разместить LLM в коляске для функции Cloud Run

Как разместить LLM в коляске для функции Cloud Run

О практической работе

subjectПоследнее обновление: мар. 27, 2025
account_circleАвтор: сотрудник Google

1. Введение

В этой лаборатории кода вы узнаете, как разместить модель gemma3:4b в дополнительном модуле для функции Cloud Run. Когда файл загружается в корзину Cloud Storage, он запускает функцию Cloud Run. Функция отправит содержимое файла в Gemma 3 в коляске для обобщения.

  • Как сделать вывод с помощью функции Cloud Run и LLM, размещенного в коляске с использованием графических процессоров
  • Как использовать выходную конфигурацию Direct VPC для графического процессора Cloud Run для более быстрой загрузки и обслуживания модели.
  • Как использовать genkit для взаимодействия с вашей размещенной моделью олламы

2. Прежде чем начать

Чтобы использовать функцию графических процессоров, необходимо запросить увеличение квоты для поддерживаемого региона. Необходимая квота — nvidia_l4_gpu_allocation_no_zonal_redundancy, которая находится в Cloud Run Admin API. Вот прямая ссылка для запроса квоты .

3. Настройка и требования

Установите переменные среды, которые будут использоваться в этой лаборатории кода.

PROJECT_ID=<YOUR_PROJECT_ID>
REGION
=<YOUR_REGION>

AR_REPO
=codelab-crf-sidecar-gpu
FUNCTION_NAME
=crf-sidecar-gpu
BUCKET_GEMMA_NAME
=$PROJECT_ID-codelab-crf-sidecar-gpu-gemma3
BUCKET_DOCS_NAME
=$PROJECT_ID-codelab-crf-sidecar-gpu-docs
SERVICE_ACCOUNT
="crf-sidecar-gpu"
SERVICE_ACCOUNT_ADDRESS
=$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com
IMAGE_SIDECAR
=$REGION-docker.pkg.dev/$PROJECT_ID/$AR_REPO/ollama-gemma3

Создайте учетную запись службы, выполнив следующую команду:

gcloud iam service-accounts create $SERVICE_ACCOUNT \
 
--display-name="SA for codelab crf sidecar with gpu"

Мы будем использовать ту же учетную запись службы, которая используется в качестве удостоверения функции Cloud Run, в качестве учетной записи службы для триггера eventarc для вызова функции Cloud Run. Если хотите, вы можете создать другой SA для Eventarc.

gcloud projects add-iam-policy-binding $PROJECT_ID \
   
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
   
--role=roles/run.invoker

Также предоставьте сервисной учетной записи доступ для получения событий Eventarc.

gcloud projects add-iam-policy-binding $PROJECT_ID \
   
--member="serviceAccount:$SERVICE_ACCOUNT_ADDRESS" \
   
--role="roles/eventarc.eventReceiver"

Создайте корзину, в которой будет размещена ваша настроенная модель. В этой кодовой лаборатории используется региональный сегмент. Вы также можете использовать многорегиональную корзину.

gsutil mb -l $REGION gs://$BUCKET_GEMMA_NAME

А затем предоставьте SA доступ к корзине.

gcloud storage buckets add-iam-policy-binding gs://$BUCKET_GEMMA_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin

Теперь создайте региональную корзину, в которой будут храниться документы, которые вы хотите обобщить. Вы также можете использовать многорегиональный сегмент при условии, что вы соответствующим образом обновите триггер Eventarc (показано в конце этой кодовой лаборатории).

gsutil mb -l $REGION gs://$BUCKET_DOCS_NAME

А затем предоставьте SA доступ к корзине Gemma 3.

gcloud storage buckets add-iam-policy-binding gs://$BUCKET_GEMMA_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin

и ведро Документов.

gcloud storage buckets add-iam-policy-binding gs://$BUCKET_DOCS_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin

Создайте репозиторий реестра артефактов для образа Ollama, который будет использоваться в коляске.

gcloud artifacts repositories create $AR_REPO \
   
--repository-format=docker \
   
--location=$REGION \
   
--description="codelab for CR function and gpu sidecar" \
   
--project=$PROJECT_ID

4. Скачать модель Джемма 3

Сначала вам нужно загрузить модель Gemma 3 4b с сайта ollama. Вы можете сделать это, установив ollama, а затем локально запустив модель gemma3:4b.

curl -fsSL https://ollama.com/install.sh | sh
ollama serve

Теперь в отдельном окне терминала выполните следующую команду, чтобы спустить модель. Если вы используете Cloud Shell, вы можете открыть дополнительное окно терминала, щелкнув значок плюса в правой верхней строке меню.

ollama run gemma3:4b

После запуска ollama не стесняйтесь задавать модели несколько вопросов, например:

"why is the sky blue?"

Закончив общение с олламой, вы можете выйти из чата, запустив

/bye

Затем в первом окне терминала выполните следующую команду, чтобы прекратить локальное обслуживание олламы.

# on Linux / Cloud Shell press Ctrl^C or equivalent for your shell

Здесь вы можете найти, где Ollama загружает модели в зависимости от вашей операционной системы.

https://github.com/ollama/ollama/blob/main/docs/faq.md#where-are-models-stored

Если вы используете облачные рабочие станции, вы можете найти загруженные модели ollama здесь /home/$USER/.ollama/models

Подтвердите, что ваши модели размещены здесь:

ls /home/$USER/.ollama/models

теперь переместите модель gemma3:4b в корзину GCS.

gsutil cp -r /home/$USER/.ollama/models gs://$BUCKET_GEMMA_NAME

5. Создайте функцию Cloud Run

Создайте корневую папку для вашего исходного кода.

mkdir codelab-crf-sidecar-gpu &&
cd codelab
-crf-sidecar-gpu &&
mkdir cr
-function &&
mkdir ollama
-gemma3 &&
cd cr
-function

Создайте подпапку с именем src. Внутри папки создайте файл index.ts.

mkdir src &&
touch src
/index.ts

Обновите index.ts, используя следующий код:

//import util from 'util';
import { cloudEvent, CloudEvent } from "@google-cloud/functions-framework";
import { StorageObjectData } from "@google/events/cloud/storage/v1/StorageObjectData";
import { Storage } from "@google-cloud/storage";

// Initialize the Cloud Storage client
const storage = new Storage();

import { genkit } from 'genkit';
import { ollama } from 'genkitx-ollama';

const ai = genkit({
   
plugins: [
       
ollama({
           
models: [
               
{
                   
name: 'gemma3:4b',
                   
type: 'generate', // type: 'chat' | 'generate' | undefined
               
},
           
],
           
serverAddress: 'http://127.0.0.1:11434', // default local address
       
}),
   
],
});


// Register a CloudEvent callback with the Functions Framework that will
// be triggered by Cloud Storage.

//functions.cloudEvent('helloGCS', await cloudEvent => {
cloudEvent("gcs-cloudevent", async (cloudevent: CloudEvent<StorageObjectData>) => {
   
console.log("---------------\nProcessing for ", cloudevent.subject, "\n---------------");

   
if (cloudevent.data) {

       
const data = cloudevent.data;

       
if (data && data.bucket && data.name) {
           
const bucketName = cloudevent.data.bucket;
           
const fileName = cloudevent.data.name;
           
const filePath = `${cloudevent.data.bucket}/${cloudevent.data.name}`;

           
console.log(`Attempting to download: ${filePath}`);

           
try {
               
// Get a reference to the bucket
               
const bucket = storage.bucket(bucketName!);

               
// Get a reference to the file
               
const file = bucket.file(fileName!);

               
// Download the file's contents
               
const [content] = await file.download();

               
// 'content' is a Buffer. Convert it to a string.
               
const fileContent = content.toString('utf8');

               
console.log(`Sending file to Gemma 3 for summarization`);
               
const { text } = await ai.generate({
                   
model: 'ollama/gemma3:4b',
                   
prompt: `Summarize the following document in just a few sentences ${fileContent}`,
               
});

               
console.log(text);

           
} catch (error: any) {

               
console.error('An error occurred:', error.message);
           
}
       
} else {
           
console.warn("CloudEvent bucket name is missing!", cloudevent);
       
}
   
} else {
       
console.warn("CloudEvent data is missing!", cloudevent);
   
}
});

Теперь в корневом каталоге crf-sidecar-gpu создайте файл package.json со следующим содержимым:

{
    "main": "lib/index.js",
    "name": "ingress-crf-genkit",
    "version": "1.0.0",
    "scripts": {
        "build": "tsc"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "description": "",
    "dependencies": {
        "@google-cloud/functions-framework": "^3.4.0",
        "@google-cloud/storage": "^7.0.0",
        "genkit": "^1.1.0",
        "genkitx-ollama": "^1.1.0",
        "@google/events": "^5.4.0"
    },
    "devDependencies": {
        "typescript": "^5.5.2"
    }
}

Создайте tsconfig.json также на уровне корневого каталога со следующим содержимым:

{
 
"compileOnSave": true,
 
"include": [
   
"src"
 
],
 
"compilerOptions": {
   
"module": "commonjs",
   
"noImplicitReturns": true,
   
"outDir": "lib",
   
"sourceMap": true,
   
"strict": true,
   
"target": "es2017",
   
"skipLibCheck": true,
   
"esModuleInterop": true
 
}
}

6. Разверните функцию

На этом этапе вы развернете функцию Cloud Run, выполнив следующую команду.

Примечание. Максимальное количество экземпляров должно быть установлено на число, меньшее или равное вашей квоте графического процессора.

gcloud beta run deploy $FUNCTION_NAME \
  --region $REGION \
  --function gcs-cloudevent \
  --base-image nodejs22 \
  --source . \
  --no-allow-unauthenticated \
  --max-instances 2 # this should be less than or equal to your GPU quota

7. Создайте коляску

Вы можете узнать больше о хостинге Ollama в службе Cloud Run по адресу https://cloud.google.com/run/docs/tutorials/gpu-gemma-with-ollama.

Перейдите в каталог вашей коляски:

cd ../ollama-gemma3

Создайте файл Dockerfile со следующим содержимым:

FROM ollama/ollama:latest

# Listen on all interfaces, port 11434
ENV OLLAMA_HOST 0.0.0.0:11434

# Store model weight files in /models
ENV OLLAMA_MODELS /models

# Reduce logging verbosity
ENV OLLAMA_DEBUG false

# Never unload model weights from the GPU
ENV OLLAMA_KEEP_ALIVE -1

# Store the model weights in the container image
ENV MODEL gemma3:4b
RUN ollama serve & sleep 5 && ollama pull $MODEL

# Start Ollama
ENTRYPOINT ["ollama", "serve"]

Создайте образ

gcloud builds submit \
   --tag $REGION-docker.pkg.dev/$PROJECT_ID/$AR_REPO/ollama-gemma3 \
   --machine-type e2-highcpu-32

8. Обновите функцию с помощью коляски

Чтобы добавить дополнительный компонент к существующей службе, заданию или функции, вы можете обновить файл YAML, включив в него дополнительный компонент.

Получите YAML для функции Cloud Run, которую вы только что развернули, выполнив:

gcloud run services describe $FUNCTION_NAME --format=export > add-sidecar-service.yaml

Теперь добавьте коляску в CRf, обновив YAML следующим образом:

  1. вставьте следующий фрагмент YAML непосредственно над строкой runtimeClassName: run.googleapis.com/linux-base-image-update . -image должен совпадать с элементом входного контейнера -image
    - image: YOUR_IMAGE_SIDECAR:latest
        name
: gemma-sidecar
        env
:
       
- name: OLLAMA_FLASH_ATTENTION
          value
: '1'
        resources
:
          limits
:
            cpu
: 6000m
            nvidia
.com/gpu: '1'
            memory
: 16Gi
        volumeMounts
:
       
- name: gcs-1
          mountPath
: /root/.ollama
        startupProbe
:
          failureThreshold
: 2
          httpGet
:
            path
: /
            port: 11434
          initialDelaySeconds: 60
          periodSeconds: 60
          timeoutSeconds: 60
      nodeSelector:
        run.googleapis.com/
accelerator: nvidia-l4
      volumes
:
       
- csi:
            driver
: gcsfuse.run.googleapis.com
            volumeAttributes
:
              bucketName
: YOUR_BUCKET_GEMMA_NAME
          name
: gcs-1
  1. Выполните следующую команду, чтобы обновить фрагмент YAML с помощью переменных среды:
sed -i "s|YOUR_IMAGE_SIDECAR|$IMAGE_SIDECAR|; s|YOUR_BUCKET_GEMMA_NAME|$BUCKET_GEMMA_NAME|" add-sidecar-service.yaml

Готовый файл YAML должен выглядеть примерно так:

##############################################
# DO NOT COPY - For illustration purposes only
##############################################

apiVersion
: serving.knative.dev/v1
kind
: Service
metadata
:
  annotations
:    
    run
.googleapis.com/build-base-image: us-central1-docker.pkg.dev/serverless-runtimes/google-22/runtimes/nodejs22
    run
.googleapis.com/build-enable-automatic-updates: 'true'
    run
.googleapis.com/build-function-target: gcs-cloudevent
    run
.googleapis.com/build-id: f0122905-a556-4000-ace4-5c004a9f9ec6
    run
.googleapis.com/build-image-uri:<YOUR_IMAGE_CRF>
    run
.googleapis.com/build-name: <YOUR_BUILD_NAME>
    run
.googleapis.com/build-source-location: <YOUR_SOURCE_LOCATION>
    run
.googleapis.com/ingress: all
    run
.googleapis.com/ingress-status: all
    run
.googleapis.com/urls: '["<YOUR_CLOUD_RUN_FUNCTION_URLS"]'
  labels
:
    cloud
.googleapis.com/location: <YOUR_REGION>
  name
: <YOUR_FUNCTION_NAME>
 
namespace: '392295011265'
spec
:
 
template:
    metadata
:
      annotations
:
        autoscaling
.knative.dev/maxScale: '4'
        run
.googleapis.com/base-images: '{"":"us-central1-docker.pkg.dev/serverless-runtimes/google-22/runtimes/nodejs22"}'
        run
.googleapis.com/client-name: gcloud
        run
.googleapis.com/client-version: 514.0.0
        run
.googleapis.com/startup-cpu-boost: 'true'
      labels
:
        client
.knative.dev/nonce: hzhhrhheyd
        run
.googleapis.com/startupProbeType: Default
    spec
:
      containerConcurrency
: 80
      containers
:
     
- image: <YOUR_FUNCTION_IMAGE>
        ports
:
       
- containerPort: 8080
          name
: http1
        resources
:
          limits
:
            cpu
: 1000m
            memory
: 512Mi
        startupProbe
:
          failureThreshold
: 1
          periodSeconds
: 240
          tcpSocket
:
            port
: 8080
          timeoutSeconds
: 240
     
- image: <YOUR_SIDECAR_IMAGE>:latest
        name
: gemma-sidecar
        env
:
       
- name: OLLAMA_FLASH_ATTENTION
          value
: '1'
        resources
:
          limits
:
            cpu
: 6000m
            nvidia
.com/gpu: '1'
            memory
: 16Gi
        volumeMounts
:
       
- name: gcs-1
          mountPath
: /root/.ollama
        startupProbe
:
          failureThreshold
: 2
          httpGet
:
            path
: /
            port: 11434
          initialDelaySeconds: 60
          periodSeconds: 60
          timeoutSeconds: 60
      nodeSelector:
        run.googleapis.com/
accelerator: nvidia-l4
      volumes
:
       
- csi:
            driver
: gcsfuse.run.googleapis.com
            volumeAttributes
:
              bucketName
: <YOUR_BUCKET_NAME>
          name
: gcs-1
      runtimeClassName
: run.googleapis.com/linux-base-image-update
      serviceAccountName
: <YOUR_SA_ADDRESS>
      timeoutSeconds
: 300
  traffic
:
 
- latestRevision: true
    percent
: 100

##############################################
# DO NOT COPY - For illustration purposes only
##############################################

Теперь обновите функцию с помощью коляски, выполнив следующую команду.

gcloud run services replace add-sidecar-service.yaml

Наконец, создайте триггер eventarc для функции. Эта команда также добавляет его в функцию.

Примечание. Если вы создали многорегиональную корзину, вам нужно изменить параметр --location

gcloud eventarc triggers create my-crf-summary-trigger  \
    --location=$REGION \
    --destination-run-service=$FUNCTION_NAME  \
    --destination-run-region=$REGION \
    --event-filters="type=google.cloud.storage.object.v1.finalized" \
    --event-filters="bucket=$BUCKET_DOCS_NAME" \
    --service-account=$SERVICE_ACCOUNT_ADDRESS

9. Проверьте свою функцию

Загрузите обычный текстовый файл для обобщения. Не знаете, что подвести итог? Попросите Близнецов дать вам краткое описание истории собак на 1-2 страницах! Затем загрузите этот простой текстовый файл в корзину $BUCKET_DOCS_NAME для модели Gemma3:4b, чтобы записать сводку в журналы функций.

В журналах вы увидите что-то похожее на следующее:

---------------
Processing for objects/dogs.txt
---------------
Attempting to download: <YOUR_PROJECT_ID>-codelab-crf-sidecar-gpu-docs/dogs.txt
Sending file to Gemma 3 for summarization
...
Here's a concise summary of the document "Humanity's Best Friend":
The dog's domestication, beginning roughly 20,000-40,000 years ago, represents a unique, deeply intertwined evolutionary partnership with humans, predating the domestication of any other animal
<
...>
solidifying their long-standing role as humanity's best friend.

10. Поиск неисправностей

Вот некоторые ошибки и опечатки, с которыми вы можете столкнуться:

  1. Если вы получаете сообщение об ошибке, указывающее, что PORT 8080 is in use , убедитесь, что ваш файл Dockerfile для вашего дополнительного устройства Ollama использует порт 11434. Также убедитесь, что вы используете правильный образ дополнительного устройства, если в вашем репозитории AR есть несколько изображений Ollama. Функция Cloud Run работает на порту 8080, и если вы использовали другой образ Ollama в качестве вспомогательного устройства, которое также обслуживается на порту 8080, вы столкнетесь с этой ошибкой.
  2. Если вы получаете сообщение об ошибке failed to build: (error ID: 7485c5b6): function.js does not exist , убедитесь, что ваши файлы package.json и tsconfig.json находятся на том же уровне, что и каталог src.
  3. Если вы получаете сообщение об ошибке ERROR: (gcloud.run.services.replace) spec.template.spec.node_selector: Max instances must be set to 4 or fewer in order to set GPU requirements. , в файле YAML измените autoscaling.knative.dev/maxScale: '100' на 1 или на значение, меньшее или равное вашей квоте графического процессора.