1. Einführung
Übersicht
In diesem Codelab erfahren Sie, wie Sie ein gemma3:4b-Modell in einem Sidecar für eine Cloud Run Functions-Funktion hosten. Wenn eine Datei in einen Cloud Storage-Bucket hochgeladen wird, wird die Cloud Run-Funktion ausgelöst. Die Funktion sendet den Inhalt der Datei zur Zusammenfassung an Gemma 3 im Sidecar.
Lerninhalte
- Inferenzen mit einer Cloud Run-Funktion und einem in einem Sidecar gehosteten LLM mit GPUs ausführen
- Konfiguration für ausgehenden Direct VPC-Traffic für eine Cloud Run-GPU verwenden, um das Modell schneller hochzuladen und bereitzustellen
- Genkit für die Interaktion mit Ihrem gehosteten Ollama-Modell verwenden
2. Hinweis
Wenn Sie die GPU-Funktion verwenden möchten, müssen Sie eine Kontingenterhöhung für eine unterstützte Region beantragen. Das erforderliche Kontingent ist „nvidia_l4_gpu_allocation_no_zonal_redundancy“ unter „Cloud Run Admin API“. Hier ist der direkte Link zum Anfordern von Kontingent.
3. Einrichtung und Anforderungen
Legen Sie Umgebungsvariablen fest, die in diesem Codelab verwendet werden.
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
Erstellen Sie das Dienstkonto mit dem folgenden Befehl:
gcloud iam service-accounts create $SERVICE_ACCOUNT \
--display-name="SA for codelab crf sidecar with gpu"
Wir verwenden dasselbe Dienstkonto, das als Identität der Cloud Run-Funktion verwendet wird, als Dienstkonto für den Eventarc-Trigger, um die Cloud Run-Funktion aufzurufen. Sie können auch ein anderes Dienstkonto für Eventarc erstellen.
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/run.invoker
Gewähren Sie dem Dienstkonto auch Zugriff zum Empfangen von Eventarc-Ereignissen.
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_ADDRESS" \
--role="roles/eventarc.eventReceiver"
Erstellen Sie einen Bucket, in dem Ihr feinabgestimmtes Modell gehostet wird. In diesem Codelab wird ein regionaler Bucket verwendet. Sie können auch einen multiregionalen Bucket verwenden.
gsutil mb -l $REGION gs://$BUCKET_GEMMA_NAME
Gewähren Sie dem Dienstkonto dann Zugriff auf den Bucket.
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_GEMMA_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin
Erstellen Sie nun einen regionalen Bucket, in dem die Dokumente gespeichert werden, die zusammengefasst werden sollen. Sie können auch einen multiregionalen Bucket verwenden, sofern Sie den Eventarc-Trigger entsprechend aktualisieren (siehe Ende dieses Codelabs).
gsutil mb -l $REGION gs://$BUCKET_DOCS_NAME
Gewähren Sie dem Dienstkonto dann Zugriff auf den Gemma 3-Bucket.
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_GEMMA_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin
und den Dokument-Bucket.
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_DOCS_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin
Erstellen Sie ein Artifact Registry-Repository für das Ollama-Image, das im Sidecar verwendet wird.
gcloud artifacts repositories create $AR_REPO \
--repository-format=docker \
--location=$REGION \
--description="codelab for CR function and gpu sidecar" \
--project=$PROJECT_ID
4. Gemma 3-Modell herunterladen
Laden Sie zuerst das Gemma 3 4b-Modell von Ollama herunter. Dazu müssen Sie Ollama installieren und das Modell „gemma3:4b“ lokal ausführen.
curl -fsSL https://ollama.com/install.sh | sh
ollama serve
Führen Sie nun in einem separaten Terminalfenster den folgenden Befehl aus, um das Modell herunterzuladen. Wenn Sie Cloud Shell verwenden, können Sie ein zusätzliches Terminalfenster öffnen, indem Sie in der Menüleiste oben rechts auf das Pluszeichen klicken.
ollama run gemma3:4b
Sobald Ollama ausgeführt wird, können Sie dem Modell Fragen stellen, z.B.:
"why is the sky blue?"
Wenn Sie mit dem Chatten mit Ollama fertig sind, können Sie den Chat mit dem folgenden Befehl beenden:
/bye
Führen Sie dann im ersten Terminalfenster den folgenden Befehl aus, um die lokale Bereitstellung von Ollama zu beenden:
# on Linux / Cloud Shell press Ctrl^C or equivalent for your shell
Hier finden Sie Informationen dazu, wo Ollama die Modelle herunterlädt, je nach Betriebssystem.
https://github.com/ollama/ollama/blob/main/docs/faq.md#where-are-models-stored
Wenn Sie Cloud Workstations verwenden, finden Sie die heruntergeladenen Ollama-Modelle hier: /home/$USER/.ollama/models
Prüfen Sie, ob Ihre Modelle hier gehostet werden:
ls /home/$USER/.ollama/models
Verschieben Sie das Modell „gemma3:4b“ jetzt in Ihren GCS-Bucket.
gsutil cp -r /home/$USER/.ollama/models gs://$BUCKET_GEMMA_NAME
5. Cloud Run-Funktion erstellen
Erstellen Sie einen Stammordner für Ihren Quellcode.
mkdir codelab-crf-sidecar-gpu &&
cd codelab-crf-sidecar-gpu &&
mkdir cr-function &&
mkdir ollama-gemma3 &&
cd cr-function
Erstellen Sie einen Unterordner mit dem Namen „src“. Erstellen Sie im Ordner eine Datei mit dem Namen „index.ts“.
mkdir src &&
touch src/index.ts
Aktualisieren Sie „index.ts“ mit dem folgenden Code:
//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);
}
});
Erstellen Sie nun im Stammverzeichnis crf-sidecar-gpu eine Datei namens package.json mit folgendem Inhalt:
{
"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"
}
}
Erstellen Sie auch im Stammverzeichnis eine tsconfig.json mit folgendem Inhalt:
{
"compileOnSave": true,
"include": [
"src"
],
"compilerOptions": {
"module": "commonjs",
"noImplicitReturns": true,
"outDir": "lib",
"sourceMap": true,
"strict": true,
"target": "es2017",
"skipLibCheck": true,
"esModuleInterop": true
}
}
6. Funktion implementieren
In diesem Schritt stellen Sie die Cloud Run-Funktion mit dem folgenden Befehl bereit.
Hinweis: Die maximale Anzahl von Instanzen sollte auf eine Zahl festgelegt werden, die kleiner oder gleich Ihrem GPU-Kontingent ist.
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. Sidecar erstellen
Weitere Informationen zum Hosten von Ollama in einem Cloud Run-Dienst finden Sie unter https://cloud.google.com/run/docs/tutorials/gpu-gemma-with-ollama.
Wechseln Sie in das Verzeichnis für Ihr Sidecar:
cd ../ollama-gemma3
Erstellen Sie eine Dockerfile-Datei mit folgendem Inhalt:
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"]
Image erstellen
gcloud builds submit \
--tag $REGION-docker.pkg.dev/$PROJECT_ID/$AR_REPO/ollama-gemma3 \
--machine-type e2-highcpu-32
8. Funktion mit dem Sidecar aktualisieren
Wenn Sie einem vorhandenen Dienst, Job oder einer vorhandenen Funktion einen Sidecar hinzufügen möchten, können Sie die YAML-Datei aktualisieren, sodass sie den Sidecar enthält.
Rufen Sie die YAML-Datei für die Cloud Run-Funktion ab, die Sie gerade bereitgestellt haben:
gcloud run services describe $FUNCTION_NAME --format=export > add-sidecar-service.yaml
Fügen Sie nun den Sidecar zum CRf hinzu, indem Sie das YAML so aktualisieren:
- Fügen Sie das folgende YAML-Fragment direkt über der Zeile
runtimeClassName: run.googleapis.com/linux-base-image-updateein. Der-imagesollte mit dem Ingress-Container-Element-imageübereinstimmen.
- 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
- Führen Sie den folgenden Befehl aus, um das YAML-Fragment mit Ihren Umgebungsvariablen zu aktualisieren:
sed -i "s|YOUR_IMAGE_SIDECAR|$IMAGE_SIDECAR|; s|YOUR_BUCKET_GEMMA_NAME|$BUCKET_GEMMA_NAME|" add-sidecar-service.yaml
Ihre fertige YAML-Datei sollte in etwa so aussehen:
##############################################
# 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
##############################################
Aktualisieren Sie die Funktion nun mit dem Sidecar, indem Sie den folgenden Befehl ausführen.
gcloud run services replace add-sidecar-service.yaml
Erstellen Sie zum Schluss den Eventarc-Trigger für die Funktion. Mit diesem Befehl wird sie auch der Funktion hinzugefügt.
Hinweis: Wenn Sie einen multiregionalen Bucket erstellt haben, müssen Sie den Parameter --location ändern.
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. Funktion testen
Laden Sie eine Nur-Text-Datei zur Zusammenfassung hoch. Sie wissen nicht, was zusammengefasst werden soll? Fragen Sie Gemini nach einer kurzen, ein- bis zweiseitigen Beschreibung der Geschichte der Hunde. Laden Sie diese Nur-Text-Datei dann in Ihren $BUCKET_DOCS_NAME-Bucket hoch, damit das Gemma3:4b-Modell eine Zusammenfassung in die Funktionslogs schreibt.
In den Logs sehen Sie etwa Folgendes:
---------------
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. Fehlerbehebung
Hier sind einige Fehler, die aufgrund von Tippfehlern auftreten können:
- Wenn Sie einen Fehler mit
PORT 8080 is in useerhalten, prüfen Sie, ob in Ihrem Dockerfile für den Ollama-Sidecar-Container Port 11434 verwendet wird. Achten Sie außerdem darauf, dass Sie das richtige Sidecar-Image verwenden, falls Sie mehrere Ollama-Images in Ihrem AR-Repository haben. Die Cloud Run-Funktion wird auf Port 8080 bereitgestellt. Wenn Sie ein anderes Ollama-Image als Sidecar verwendet haben, das ebenfalls auf Port 8080 bereitgestellt wird, tritt dieser Fehler auf. - Wenn der Fehler
failed to build: (error ID: 7485c5b6): function.js does not existangezeigt wird, prüfen Sie, ob sich die Dateien „package.json“ und „tsconfig.json“ auf derselben Ebene wie das Verzeichnis „src“ befinden. - Wenn Sie den Fehler
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.erhalten, ändern Sie in Ihrer YAML-Dateiautoscaling.knative.dev/maxScale: '100'in 1 oder in einen Wert, der kleiner oder gleich Ihrem GPU-Kontingent ist.