1. מבוא
סקירה כללית
ב-Codelab הזה תלמדו איך לארח מודל gemma3:4b ב-sidecar עבור פונקציית Cloud Run. כשמעלים קובץ לקטגוריה של Cloud Storage, פונקציית Cloud Run מופעלת. הפונקציה תשלח את תוכן הקובץ ל-Gemma 3 ב-sidecar לסיכום.
מה תלמדו
- איך לבצע היקש באמצעות פונקציית Cloud Run ומודל LLM שמתארח ב-sidecar באמצעות GPU
- איך משתמשים בהגדרת תעבורת נתונים יוצאת ישירה של VPC עבור GPU ב-Cloud Run כדי להעלות את המודל ולהכניס אותו לשימוש בסביבת הייצור מהר יותר
- איך משתמשים ב-Genkit כדי ליצור ממשק עם מודל ollama שמתארח
2. לפני שמתחילים
כדי להשתמש בתכונת ה-GPU, צריך לבקש הגדלה של המכסה באזור נתמך. המכסה הנדרשת היא nvidia_l4_gpu_allocation_no_zonal_redundancy, שנמצאת ב-Cloud Run Admin API. זהו קישור ישיר לבקשת מכסה.
3. הגדרה ודרישות
מגדירים משתני סביבה שישמשו לאורך כל ה-Codelab.
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"
יוצרים קטגוריה שתארח את המודל שעבר כוונון עדין. ב-codelab הזה נעשה שימוש בקטגוריה אזורית. אפשר גם להשתמש בדלי מרובה אזורים.
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 בהתאם (כפי שמוצג בסוף ה-Codelab הזה).
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
ובמאגר Docs.
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_DOCS_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin
יוצרים מאגר ב-Artifact Registry עבור תמונת Ollama שתשמש ב-sidecar
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
קודם כול, צריך להוריד את מודל 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?"
אחרי שמסיימים את הצ'אט עם ollama, אפשר לצאת מהצ'אט על ידי הפעלת הפקודה
/bye
לאחר מכן, בחלון הטרמינל הראשון, מריצים את הפקודה הבאה כדי להפסיק את ההפעלה של ollama באופן מקומי
# 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
אם אתם משתמשים ב-Cloud Workstations, תוכלו למצוא את המודלים של 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 על ידי הרצת הפקודה הבאה.
הערה: מספר המופעים המקסימלי צריך להיות מספר שקטן מהמכסה של ה-GPU או שווה לה.
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
עוברים לספרייה של קובץ ה-sidecar:
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. עדכון הפונקציה באמצעות ה-sidecar
כדי להוסיף sidecar לשירות, למשימה או לפונקציה קיימים, אפשר לעדכן את קובץ ה-YAML כך שיכיל את ה-sidecar.
מאחזרים את קובץ ה-YAML של פונקציית Cloud Run שפרסתם זה עתה על ידי הפעלת הפקודה:
gcloud run services describe $FUNCTION_NAME --format=export > add-sidecar-service.yaml
עכשיו מוסיפים את ה-sidecar ל-CRf על ידי עדכון ה-YAML באופן הבא:
- מוסיפים את קטע ה-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
- מריצים את הפקודה הבאה כדי לעדכן את קטע ה-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
##############################################
עכשיו מעדכנים את הפונקציה באמצעות ה-sidecar על ידי הפעלת הפקודה הבאה.
gcloud run services replace add-sidecar-service.yaml
לבסוף, יוצרים את טריגר Eventarc לפונקציה. הפקודה הזו גם מוסיפה את ה-URL לפונקציה.
הערה: אם יצרתם קטגוריה במספר אזורים, תצטרכו לשנות את הפרמטר --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. בדיקת הפונקציה
מעלים קובץ טקסט פשוט לסיכום. לא יודעים מה לסכם? אפשר לבקש מ-Gemini תיאור מהיר של ההיסטוריה של הכלבים באורך של עמוד אחד או שניים. לאחר מכן מעלים את קובץ הטקסט הפשוט הזה ל-bucket של $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. פתרון בעיות
הנה כמה שגיאות שקשורות לטעויות הקלדה שאתם עשויים להיתקל בהן:
- אם מופיעה השגיאה
PORT 8080 is in use, צריך לוודא שקובץ ה-Dockerfile של Ollama sidecar משתמש ביציאה 11434. בנוסף, אם יש לכם כמה תמונות Ollama במאגר ה-AR, חשוב לוודא שאתם משתמשים בתמונת ה-sidecar הנכונה. הפונקציה של Cloud Run פועלת ביציאה 8080, ואם השתמשתם באימג' אחר של Ollama כ-sidecar שפועל גם הוא ביציאה 8080, תיתקלו בשגיאה הזו. - אם מוצגת השגיאה
failed to build: (error ID: 7485c5b6): function.js does not exist, צריך לוודא שהקבצים package.json ו-tsconfig.json נמצאים באותה רמה כמו הספרייה src. - אם מופיעה השגיאה
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 או לערך שקטן ממכסת ה-GPU או שווה לה.