1. مقدمة
نظرة عامة
في هذا الدرس التطبيقي حول الترميز، ستتعرّف على كيفية استضافة نموذج gemma3:4b في حاوية مشتركة لوظيفة Cloud Run. عند تحميل ملف إلى حزمة Cloud Storage، سيؤدي ذلك إلى تشغيل وظيفة Cloud Run. سترسل الدالة محتوى الملف إلى Gemma 3 في الشريط الجانبي لتلخيصه.
ما ستتعلمه
- كيفية إجراء الاستنتاج باستخدام دالة Cloud Run ونموذج لغوي كبير مستضاف في حاوية جانبية باستخدام وحدات معالجة الرسومات
- كيفية استخدام إعدادات الخروج المباشر من سحابة VPC لوحدة معالجة الرسومات في Cloud Run من أجل تحميل النموذج وعرضه بشكل أسرع
- كيفية استخدام genkit للتفاعل مع نموذج ollama المستضاف
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. يمكنك إنشاء حساب خدمة مختلف لـ 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
بعد ذلك، امنح حساب الخدمة إذن الوصول إلى الحزمة.
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
بعد ذلك، امنح حساب الخدمة إذن الوصول إلى حزمة 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 التي سيتم استخدامها في الحاوية الجانبية
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 من خلال تشغيل الأمر التالي.
ملاحظة: يجب ضبط الحد الأقصى لعدد المثيلات على رقم أقل من حصة وحدة معالجة الرسومات أو مساوٍ لها.
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 إلى خدمة أو مهمة أو دالة حالية، يمكنك تعديل ملف YAML ليحتوي على الحاوية.
استرجِع ملف 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
##############################################
عدِّل الآن الدالة باستخدام الحاوية الجانبية من خلال تنفيذ الأمر التالي.
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- اختبار الدالة
حمِّل ملف نص عادي لتلخيصه. لا تعرف ما الذي يجب تلخيصه؟ اطلب من Gemini تقديم وصف سريع من صفحة واحدة أو صفحتَين لتاريخ الكلاب. بعد ذلك، حمِّل ملف النص العادي هذا إلى حزمة $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. تأكَّد أيضًا من استخدام صورة sidecar الصحيحة في حال توفّر عدة صور Ollama في مستودع AR. تعمل وظيفة Cloud Run على المنفذ 8080، وإذا كنت قد استخدمت صورة Ollama مختلفة كحاوية جانبية تعمل أيضًا على المنفذ 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.، غيِّرautoscaling.knative.dev/maxScale: '100'في ملف YAML إلى 1 أو إلى قيمة أقل من أو تساوي حصة وحدة معالجة الرسومات.