1. مقدمة
نظرة عامة
في هذا الدرس التطبيقي حول الترميز، ستتعلّم كيفية إنشاء مسار معالجة بالذكاء الاصطناعي غير متزامن مستنِد إلى الأحداث. ستنشر نموذجًا مفتوح المصدر باستخدام Ollama على مجموعة العاملين في Cloud Run. تسحب مجموعة العمال الرسائل من موضوع Pub/Sub وتعالجها باستخدام نموذج gemma3:4b.
أهداف الدورة التعليمية
- كيفية استخدام مجموعات العاملين مع اشتراك Pub/Sub Pull
- كيفية استخدام Ollama لإجراء الاستدلال كمجموعة من العاملين
2. قبل البدء
تفعيل واجهات برمجة التطبيقات
قبل البدء في استخدام هذا الدرس التطبيقي، فعِّل واجهات برمجة التطبيقات التالية من خلال تنفيذ ما يلي:
gcloud services enable run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
pubsub.googleapis.com \
storage.googleapis.com
3- الإعداد والمتطلبات
لإعداد المراجع المطلوبة، اتّبِع الخطوات التالية:
- اضبط متغيّرات البيئة لهذا الدرس التطبيقي حول الترميز:
export PROJECT_ID=<YOUR_PROJECT_ID>
export REGION=<YOUR_REGION>
export BUCKET_NAME=$PROJECT_ID-gemma3-4b
export SERVICE_ACCOUNT_NAME=ollama-worker-sa
export SERVICE_ACCOUNT_EMAIL=${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com
export TOPIC_NAME=ollama-prompts
export SUBSCRIPTION_NAME=ollama-prompts-sub
export AR_REPO_NAME=ollama-worker-repo
export PULL_MSG_IMAGE_NAME=pubsub-pull-msg
export OLLAMA_IMAGE_NAME=ollama-coordinator
- إنشاء حساب خدمة لمجموعة العمال
gcloud iam service-accounts create ${SERVICE_ACCOUNT_NAME} \
--display-name="Ollama Worker Service Account"
- منح حساب الخدمة إذن الوصول إلى Pub/Sub
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:${SERVICE_ACCOUNT_EMAIL}" \
--role="roles/pubsub.subscriber"
- إنشاء مستودع AR لصورة مجموعة العاملين
gcloud artifacts repositories create ${AR_REPO_NAME} \
--repository-format=docker \
--location=${REGION}
- إنشاء موضوع واشتراك Pub/Sub
gcloud pubsub topics create $TOPIC_NAME
gcloud pubsub subscriptions create $SUBSCRIPTION_NAME --topic $TOPIC_NAME
4. تنزيل النموذج واستضافته على GCS
بدلاً من استرداد النموذج مباشرةً داخل الحاوية أثناء عملية التصميم، ما قد يكون بطيئًا وغير فعّال، سنستردّ النموذج إلى جهاز محلي باستخدام واجهة سطر الأوامر في Ollama، ثم نحمّل ملفات النموذج إلى حزمة GCS. بعد ذلك، ستثبّت مجموعة العمال هذا الحزمة للوصول إلى النموذج.
- تثبيت Ollama على جهازك:
نفِّذ الأمر التالي لتثبيت Ollama على Linux. بالنسبة إلى أنظمة التشغيل الأخرى، يُرجى الرجوع إلى الموقع الإلكتروني لتطبيق Ollama.
curl -fsSL https://ollama.com/install.sh | sh
- ابدأ تشغيل خدمة Ollama واسحب النموذج:
أولاً، ابدأ خدمة Ollama في الخلفية.
ollama serve &
ollama pull gemma3:4b
- إنشاء حزمة GCS:
أنشئ حزمة GCS باستخدام متغيّر البيئة BUCKET_NAME الذي ضبطته سابقًا.
gsutil mb gs://${BUCKET_NAME}
- حمِّل ملفات النموذج إلى حزمة GCS:
يخزّن Ollama ملفات النماذج في الدليل ~/.ollama/models. حمِّل محتوى هذا الدليل إلى حزمة GCS. سيؤدي هذا الإجراء إلى نسخ جميع النماذج التي نزّلتها.
gsutil -m cp -r ~/.ollama/models/* gs://${BUCKET_NAME}/
- منح حساب الخدمة إذن الوصول إلى حزمة Cloud Storage
gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \
--member=serviceAccount:${SERVICE_ACCOUNT_EMAIL} \
--role=roles/storage.objectViewer
5- إنشاء مهمة Cloud Run
تستخدم مهمة Cloud Run حاويتين:
- ollama-coordinator: لاستضافة ollama وعرض نموذج gemma 3 4B
- pubsub-pull-msg: لسحب البيانات من اشتراك Pub/Sub وتمرير الرسالة إلى حاوية ollama-coordinator
أولاً، عليك إنشاء حاوية ollama-coordinator.
- أنشئ دليلاً رئيسيًا لبرنامج التدريب العملي:
mkdir codelab-ollama-wp
cd codelab-ollama-wp
- إنشاء دليل لحاوية ollama-coordinator
mkdir ollama-coordinator
cd ollama-coordinator
- أنشئ
Dockerfileيتضمّن المحتوى التالي
# Use the official Ollama image as a base image
FROM ollama/ollama
# Expose the port that Ollama listens on
EXPOSE 11434
# Set the entrypoint to start the Ollama server
ENTRYPOINT ["ollama", "serve"]
- إنشاء حاوية ollama
gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${OLLAMA_IMAGE_NAME} --timeout=20m
بعد ذلك، ستنشئ الحاوية pubsub-pull-msg.
- إنشاء دليل لحاوية pubsub-pull-msg
cd ..
mkdir pubsub-pull-msg
cd pubsub-pull-msg
- إنشاء
Dockerfile
# Use the official Python image as a base image
FROM python:3.9-slim
# Set the working directory in the container
WORKDIR /app
# Copy the requirements file into the container
COPY requirements.txt .
# Install the required Python packages
RUN pip install --no-cache-dir -r requirements.txt
# Copy the Python script into the container
COPY main.py .
# Set the entrypoint to run the Python script
CMD ["python", "main.py"]
- أنشئ ملف
requirements.txtيتضمّن المحتوى التالي
google-cloud-pubsub
requests
- أنشئ ملف
main.pyيتضمّن المحتوى التالي
import os
import sys
import requests
import json
from google.cloud import pubsub_v1
# --- Main Application Logic ---
print("--- Sidecar container script started ---")
# --- Environment and Configuration ---
project_id = os.environ.get("PROJECT_ID")
subscription_name = os.environ.get("SUBSCRIPTION_NAME")
ollama_api_url = "http://localhost:11434/api/generate"
if not project_id or not subscription_name:
print("FATAL: PROJECT_ID and SUBSCRIPTION_NAME must be set.")
sys.exit(1)
print(f"PROJECT_ID: {project_id}")
print(f"SUBSCRIPTION_NAME: {subscription_name}")
def callback(message):
"""Processes a single Pub/Sub message."""
print(f"Received message ID: {message.message_id}")
try:
prompt = message.data.decode("utf-8")
print(f"Decoded prompt: '{prompt}'")
data = {"model": "gemma3:4b", "prompt": prompt, "stream": False}
print("Sending request to Ollama...")
response = requests.post(ollama_api_url, json=data, timeout=300)
response.raise_for_status()
print("Successfully received response from Ollama.")
ollama_response = response.json()
print(f"Ollama response: {json.dumps(ollama_response)[:200]}...")
message.ack()
print(f"Message {message.message_id} acknowledged.")
except requests.exceptions.RequestException as e:
print(f"Error calling Ollama API: {e}")
message.nack()
print(f"Message {message.message_id} not acknowledged.")
except Exception as e:
print(f"An unexpected error occurred in callback: {e}")
message.nack()
print(f"Message {message.message_id} not acknowledged.")
def main():
"""Starts the Pub/Sub subscriber."""
subscriber = pubsub_v1.SubscriberClient()
subscription_path = subscriber.subscription_path(project_id, subscription_name)
streaming_pull_future = subscriber.subscribe(subscription_path, callback=callback)
print(f"Subscribed to {subscription_path}. Listening for messages...")
try:
# .result() will block indefinitely.
streaming_pull_future.result()
except Exception as e:
print(f"A fatal error occurred in the subscriber: {e}")
streaming_pull_future.cancel()
streaming_pull_future.result()
if __name__ == "__main__":
main()
- الآن، أنشئ حاوية pubsub-pull-msg
gcloud builds submit --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${PULL_MSG_IMAGE_NAME}
6. تفعيل الوظيفة وتنفيذها
في هذه الخطوة، ستنشئ مهمة Cloud Run من خلال نشر ملف yaml.
انتقِل إلى المجلد الجذر لإنشاء ملف yaml.
cd ..
- أنشئ ملفًا
worker-pool.template.yamlيتضمّن المحتوى التالي
apiVersion: run.googleapis.com/v1
kind: WorkerPool
metadata:
name: codelab-ollama-wp
labels:
cloud.googleapis.com/location: europe-west1
annotations:
run.googleapis.com/launch-stage: BETA
run.googleapis.com/scalingMode: manual
run.googleapis.com/manualInstanceCount: '1'
run.googleapis.com/gcs-fuse-mounter-enabled: "true"
spec:
template:
metadata:
annotations:
run.googleapis.com/gpu: "1"
run.googleapis.com/gpu-zonal-redundancy-disabled: 'true'
spec:
serviceAccountName: ${SERVICE_ACCOUNT_EMAIL}
nodeSelector:
run.googleapis.com/accelerator: nvidia-l4
volumes:
- name: gcs-bucket
csi:
driver: gcsfuse.run.googleapis.com
readOnly: true
volumeAttributes:
bucketName: ${BUCKET_NAME}
containers:
- image: ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${PULL_MSG_IMAGE_NAME}
name: pubsub-pull-msg
env:
- name: PROJECT_ID
value: ${PROJECT_ID}
- name: SUBSCRIPTION_NAME
value: "ollama-prompts-sub"
- name: PYTHONUNBUFFERED
value: "1"
resources:
limits:
cpu: '1'
memory: 1Gi
- image: ${REGION}-docker.pkg.dev/${PROJECT_ID}/${AR_REPO_NAME}/${OLLAMA_IMAGE_NAME}
name: ollama-coordinator
env:
- name: OLLAMA_MODELS
value: /mnt/models
volumeMounts:
- name: gcs-bucket
mountPath: /mnt/models
resources:
limits:
cpu: '6'
nvidia.com/gpu: '1'
memory: 16Gi
بعد ذلك، حدِّد عناوين URL الكاملة للصور واستخدِم sed لاستبدال المتغيّرات في ملف النموذج، ما يؤدي إلى إنشاء worker-pool.yaml النهائي.
sed -e "s|\${SERVICE_ACCOUNT_EMAIL}|${SERVICE_ACCOUNT_EMAIL}|g" \
-e "s|\${BUCKET_NAME}|${BUCKET_NAME}|g" \
-e "s|\${PULL_MSG_IMAGE_NAME}|${PULL_MSG_IMAGE_NAME}|g" \
-e "s|\${OLLAMA_IMAGE_NAME}|${OLLAMA_IMAGE_NAME}|g" \
-e "s|\${PROJECT_ID}|${PROJECT_ID}|g" \
-e "s|\${REGION}|${REGION}|g" \
-e "s|\${AR_REPO_NAME}|${AR_REPO_NAME}|g" \
worker-pool.template.yaml > worker-pool.yaml
يمكنك الآن النشر
gcloud beta run worker-pools replace worker-pool.yaml
والاختبار
gcloud pubsub topics publish ${TOPIC_NAME} --message="What is 1 + 1?"
ثم اعرض السجلّات. قد تحتاج إلى الانتظار لمدة دقيقة أو يمكنك الانتقال إلى صفحة مجموعة العاملين في Cloud Console ومشاهدة السجلّات في الوقت الفعلي.
gcloud alpha run worker-pools logs read "codelab-ollama-wp" --limit 10
وسيظهر لك إشعار
Ollama response: {"model": "gemma3:4b", "created_at": "2025-11-06T23:48:39.572079369Z", "response": "1 + 1 = 2\n", ...
7. تهانينا!
تهانينا على إكمال هذا الدرس العملي.
ننصحك بمراجعة مستندات Cloud Run.
المواضيع التي تناولناها
- كيفية استخدام مجموعات العاملين في Cloud Run مع اشتراك Pub/Sub Pull
- كيفية استخدام Ollama لإجراء الاستدلال كمجموعة عاملة في Cloud Run
8. تَنظيم
لتجنُّب تحمّل رسوم في حسابك على Google Cloud مقابل الموارد المستخدَمة في هذا البرنامج التعليمي، احذف المشروع الذي يحتوي على الموارد أو احتفظ بالمشروع واحذف الموارد الفردية.
حذف المشروع
أسهل طريقة لإيقاف الفوترة هي حذف المشروع الذي أنشأته لتنفيذ البرنامج التعليمي.
لحذف المشروع، اتّبِع الخطوات التالية:
- في Google Cloud Console، انتقِل إلى صفحة إدارة الموارد.
- في قائمة المشاريع، اختَر المشروع الذي تريد حذفه، ثم انقر على حذف.
- في مربّع الحوار، اكتب رقم تعريف المشروع، ثم انقر على إيقاف لحذف المشروع.
حذف موارد فردية
لحذف الموارد الفردية، نفِّذ الأوامر التالية:
- احذف مجموعة العاملين في Cloud Run:
gcloud beta run worker-pools delete codelab-ollama-wp --region ${REGION}
- احذف حزمة GCS:
gsutil -m rm -r gs://${BUCKET_NAME}
- احذف الاشتراك والموضوع على Pub/Sub:
gcloud pubsub subscriptions delete ${SUBSCRIPTION_NAME}
gcloud pubsub topics delete ${TOPIC_NAME}
- احذف مستودع Artifact Registry:
gcloud artifacts repositories delete ${AR_REPO_NAME} --location=${REGION} --quiet
- احذف حساب الخدمة:
gcloud iam service-accounts delete ${SERVICE_ACCOUNT_EMAIL} --quiet
تنظيف الملفات المخزَّنة على الجهاز
لتنظيف الملفات المحلية، اتّبِع الخطوات التالية:
- إيقاف خدمة Ollama المحلية:إذا بدأت Ollama باستخدام
ollama serve &، يمكنك إيقافها من خلال العثور على معرّف العملية (PID) ثم استخدام الأمرkill.# Find the process ID of the Ollama server pgrep ollama # Replace <PID> with the actual process ID obtained from the previous command kill <PID> - احذف النماذج التي تم تنزيلها:
rm -rf ~/.ollama/models
- ألغِ تثبيت Ollama:
اتّبِع التعليمات الواردة في موقع Ollama الإلكتروني لإزالة تثبيت Ollama من جهازك.