لمحة عن هذا الدرس التطبيقي حول الترميز
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
بعد ذلك، امنح حساب "مشرف Google Workspace" إذن الوصول إلى حزمة Gemma 3.
gcloud storage buckets add-iam-policy-binding gs://$BUCKET_GEMMA_NAME \
--member=serviceAccount:$SERVICE_ACCOUNT_ADDRESS \
--role=roles/storage.objectAdmin
ومجموعة "مستندات Google".
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. تنزيل نموذج 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
بعد تشغيل Olama، يمكنك طرح بعض الأسئلة على النموذج، مثل:
"why is the sky blue?"
بعد الانتهاء من المحادثة مع "أولاما"، يمكنك الخروج من المحادثة من خلال تنفيذ
/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
إذا كنت تستخدم محطات عمل السحابة الإلكترونية، يمكنك العثور على نماذج 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. تعديل الدالة باستخدام العنصر الجانبي
لإضافة ملف sidecar إلى خدمة أو وظيفة أو مهمة حالية، يمكنك تعديل ملف YAML ليحتوي على ملف sidecar.
استرجع ملف YAML لدالة Cloud Run التي تم نشرها للتو عن طريق تنفيذ:
gcloud run services describe $FUNCTION_NAME --format=export > add-sidecar-service.yaml
أضِف الآن المحتوى الجانبي إلى ملف 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. تأكَّد أيضًا من استخدام صورة العرض الجانبي الصحيحة في حال كانت لديك عدة صور Ollama في مستودع الواقع المعزّز. يتم عرض دالة 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 أو إلى قيمة أقل من أو تساوي حصة وحدة معالجة الرسومات.