كيفية نشر موقع إلكتروني لواجهة مستخدم توليدية على Cloud Run

1. مقدمة

نظرة عامة

في هذا الدرس التطبيقي، ستنشئ موقعًا إلكترونيًا يتم إنشاء محتواه بشكل فوري باستخدام نماذج Gemini اللغوية الكبيرة من Google، ثم ستنشره. سيكون الموقع الإلكتروني عبارة عن أداة تنقّل بسيطة بأسلوب "اختر مغامرتك" لاستكشاف المواضيع، حيث يؤدي كل نقرة إلى إنشاء صفحة جديدة تتضمّن روابط جديدة استنادًا إلى اختيارك. ستنشئ هذا التطبيق باستخدام Node.js وFastify، وستستخدم حزمة تطوير البرامج (SDK) من Vertex AI لاستدعاء Gemini، وستنشره كخدمة آمنة وجاهزة للإنتاج على Cloud Run، وستؤمّنه باستخدام Identity-Aware Proxy (IAP).

الإجراءات التي ستنفذّها

  • إنشاء تطبيق Node.js Fastify يستخدم Vertex AI
  • نشر التطبيق على Cloud Run من المصدر بدون Dockerfile
  • تأمين نقطة نهاية Cloud Run باستخدام Identity-Aware Proxy (IAP)

أهداف الدورة التعليمية

  • كيفية استخدام حزمة تطوير البرامج (SDK) الخاصة بـ Vertex AI لـ Node.js من أجل إنشاء المحتوى
  • كيفية نشر تطبيق Node.js على Cloud Run
  • كيفية تأمين تطبيق Cloud Run باستخدام IAP

2. إعداد المشروع

  1. إذا لم يكن لديك حساب Google، عليك إنشاء حساب Google.
    • استخدام حساب شخصي بدلاً من حساب تديره المؤسسة التعليمية أو حساب تابع للعمل. قد تتضمّن حسابات العمل والحسابات المُدارة من المؤسسات التعليمية قيودًا تمنعك من تفعيل واجهات برمجة التطبيقات اللازمة لهذا الدرس التطبيقي.
  2. سجِّل الدخول إلى Google Cloud Console.
  3. فعِّل الفوترة في Cloud Console.
    • يجب أن تكلّف إكمال هذا المختبر أقل من دولار أمريكي واحد من موارد السحابة الإلكترونية.
    • يمكنك اتّباع الخطوات في نهاية هذا المختبر لحذف الموارد وتجنُّب المزيد من الرسوم.
    • يمكن للمستخدمين الجدد الاستفادة من فترة تجريبية مجانية بقيمة 300 دولار أمريكي.
  4. أنشِئ مشروعًا جديدًا أو اختَر إعادة استخدام مشروع حالي.
    • إذا ظهر لك خطأ بشأن حصة المشروع، أعِد استخدام مشروع حالي أو احذف مشروعًا حاليًا لإنشاء مشروع جديد.

3- فتح "محرّر Cloud Shell"

  1. انقر على هذا الرابط للانتقال مباشرةً إلى محرّر Cloud Shell
  2. إذا طُلب منك منح الإذن في أي وقت اليوم، انقر على منح الإذن للمتابعة. انقر لتفويض Cloud Shell
  3. إذا لم تظهر المحطة الطرفية في أسفل الشاشة، افتحها باتّباع الخطوات التالية:
    • انقر على عرض.
    • انقر على Terminalفتح نافذة طرفية جديدة في "محرِّر Cloud Shell"
  4. في الوحدة الطرفية، اضبط مشروعك باستخدام الأمر التالي:
    • التنسيق:
      gcloud config set project [PROJECT_ID]
      
    • مثال:
      gcloud config set project lab-project-id-example
      
    • إذا تعذّر عليك تذكُّر رقم تعريف مشروعك، اتّبِع الخطوات التالية:
      • يمكنك إدراج جميع أرقام تعريف المشاريع باستخدام:
        gcloud projects list | awk '/PROJECT_ID/{print $2}'
        
      ضبط رقم تعريف المشروع في نافذة Cloud Shell Editor
  5. من المفترض أن تظهر لك هذه الرسالة:
    Updated property [core/project].
    
    إذا ظهرت لك WARNING وطُلب منك Do you want to continue (Y/n)?، من المحتمل أنّك أدخلت رقم تعريف المشروع بشكل غير صحيح. اضغط على n، ثم على Enter، وحاوِل تنفيذ الأمر gcloud config set project مرة أخرى.
  1. ضبط متغيّر البيئة GOOGLE_CLOUD_PROJECT
    export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
    

4. تفعيل واجهات برمجة التطبيقات

في الوحدة الطرفية، فعِّل واجهات برمجة التطبيقات:

gcloud services enable \
  run.googleapis.com \
  aiplatform.googleapis.com \
  cloudresourcemanager.googleapis.com \
  iap.googleapis.com

إذا طُلب منك منح الإذن، انقر على منح الإذن للمتابعة. انقر لتفويض Cloud Shell

قد يستغرق تنفيذ هذا الأمر بضع دقائق، ولكن من المفترض أن يعرض في النهاية رسالة نجاح مشابهة لما يلي:

Operation "operations/acf.p2-73d90d00-47ee-447a-b600" finished successfully.

5- إعداد مشروع Node.js

  1. أنشئ مجلدًا باسم gen-ui-on-cloudrun لتخزين رمز المصدر اللازم للنشر:
    mkdir gen-ui-on-cloudrun && cd gen-ui-on-cloudrun
    
  2. ابدأ مشروع Node.js:
    npm init -y
    
  3. اضبط المشروع لاستخدام وحدات ES وحدِّد نصًا برمجيًا لبدء التشغيل من خلال تنفيذ الأوامر التالية:
    npm pkg set type="module"
    
  4. ثبِّت fastify لخادم الويب و@google/genai لحزمة تطوير البرامج Vertex AI:
    npm install fastify @google/genai
    

6. إنشاء الرمز البرمجي للتطبيق

  1. أنشئ ملف index.ts جديدًا وافتحه لرمز مصدر التطبيق:
    cloudshell edit ~/gen-ui-on-cloudrun/index.ts
    
    سيفتح الأمر cloudshell edit الملف index.ts في المحرِّر أعلى الوحدة الطرفية.
  2. أضِف رمز المصدر التالي لخادم واجهة المستخدم التوليدية في ملف index.ts:
    import fastifyLib from 'fastify';
    import { GoogleGenAI } from '@google/genai';
    
    const fastify = fastifyLib({ logger: true });
    
    const ai = new GoogleGenAI({
        vertexai: true,
        project: process.env.GOOGLE_CLOUD_PROJECT,
        location: process.env.GOOGLE_CLOUD_LOCATION || 'europe-west1',
    });
    
    const SYSTEM_INSTRUCTION = `The user should have submitted an html page and the id of the element just clicked.
    Given the next page description, create a new webpage with a link back to "Start Over" (the / route), a brief overview of the topic, and a list of clickable link elements related to the page.
    When an element is clicked, the webpage should link to the base route / with the nextPageDescription as a query string parameter.
    All information needed to generate the next page should be included in the nextPageDescription without additional context.
    Each nextPageDescription should be less than 1500 characters.
    
    Example:
    If the current HTML page is for a small pet store, it might include a link to an "About" page.
    The href for the about page link should be /?nextPageDescription=about%20page%20for%20small%20pet%20store%20website
    
    All responses should be valid HTML without markdown backticks.`;
    
    interface QueryParams {
        nextPageDescription?: string;
    }
    
    fastify.get<{ Querystring: QueryParams }>('/', async (request, reply) => {
        const {
            nextPageDescription = 'A web page with interesting fun facts where I can select a fact to learn more about that topic.'
        } = request.query;
    
        try {
            const response = await ai.models.generateContent({
                model: 'gemini-2.5-flash',
                contents: nextPageDescription,
                config: {
                    systemInstruction: SYSTEM_INSTRUCTION,
                    temperature: 0.9,
                }
            });
    
            reply.type('text/html; charset=utf-8').send(response.text);
        } catch (error: any) {
            request.log.error(error);
            reply.status(500).send('An error occurred calling the AI.');
        }
    });
    
    const start = async () => {
        try {
            await fastify.listen({ port: Number(process.env.PORT) || 8080, host: '0.0.0.0' });
        } catch (err) {
            fastify.log.error(err);
            process.exit(1);
        }
    };
    
    start();
    

يُعدّ هذا الرمز خادم ويب يستمع إلى طلبات HTTP GET على المسار الجذر (/). وعند تلقّي طلب، يستخدم مَعلمة طلب البحث nextPageDescription (أو قيمة تلقائية) كطلب من نموذج Gemini 2.5 Flash من خلال Vertex AI. يتم توجيه النموذج من خلال SYSTEM_INSTRUCTION لعرض صفحة HTML تحتوي على روابط، ويتضمّن كل رابط nextPageDescription لإنشاء الصفحة التالية.

7. إنشاء حساب خدمة

تحتاج إلى حساب خدمة لخدمة Cloud Run من أجل المصادقة باستخدام Vertex AI API.

  1. أنشئ حساب خدمة باسم gen-navigator-sa:
    gcloud iam service-accounts create gen-navigator-sa --display-name="Generative Navigator Service Account"
    
  2. امنح حساب الخدمة الإذن باستخدام Vertex AI:
    gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \
        --member="serviceAccount:gen-navigator-sa@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \
        --role="roles/aiplatform.user"
    

8. النشر على Cloud Run

يمكنك الآن نشر التطبيق على Cloud Run مباشرةً من رمز المصدر، بدون الحاجة إلى ملف Dockerfile.

  1. نفِّذ الأمر gcloud لنشر التطبيق:
    cd ~/gen-ui-on-cloudrun
    gcloud beta run deploy generative-web-navigator \
        --source . \
        --no-build \
        --base-image=nodejs24 \
        --command="node" \
        --args="index.ts" \
        --region=europe-west1 \
        --no-allow-unauthenticated \
        --iap \
        --service-account="gen-navigator-sa@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com" \
        --set-env-vars GOOGLE_CLOUD_PROJECT="$GOOGLE_CLOUD_PROJECT",GOOGLE_CLOUD_LOCATION="europe-west1"
    
    نستخدم هنا بعض العلامات المهمة:
    • --source . --no-build --base-image=nodejs24: يطلب هذا الأمر من Cloud Run نشر الرمز المصدري من الدليل الحالي وتخطّي مرحلة الإنشاء وتشغيل التطبيق باستخدام صورة أساسية مُنشأة مسبقًا من Node.js 24.
    • --no-allow-unauthenticated: يضمن ذلك ألا يتمكّن من الوصول إلى الخدمة سوى المستخدمين الذين تمّت المصادقة عليهم.
    • --iap: يتيح ذلك لخدمة Identity-Aware Proxy (IAP) إدارة الوصول إلى تطبيقك. تتيح لك خدمة "الوصول إلى التطبيقات بدون كلمة مرور" التحكّم في الوصول استنادًا إلى هوية المستخدم وسياقه، بدلاً من عناوين IP فقط.
  2. بعد بضع دقائق، ستظهر لك رسالة مثل:
    Service [generative-web-navigator] revision [generative-web-navigator-12345-abc] has been deployed and is serving 100 percent of traffic.
    

لقد نشرت تطبيقك، ولكن لا يزال عليك ضبط ميزة "الشراء داخل التطبيق" للسماح بالوصول.

9- ضبط إعدادات الوصول إلى "الشراء داخل التطبيق"

عند تفعيل IAP على Cloud Run، تعترض IAP جميع الطلبات وتطلب من المستخدمين المصادقة والحصول على إذن قبل أن يتمكّنوا من الوصول إلى خدمتك. لكي تعمل هذه الميزة، عليك منح إذنَين:

  • السماح لخدمة IAP نفسها باستدعاء خدمة Cloud Run
  • امنح نفسك (أو مستخدمين أو مجموعات أخرى) إذن الوصول إلى التطبيق من خلال IAP.
  1. احصل على رقم مشروعك المطلوب لتحديد وكيل خدمة IAP:
    export PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format="value(projectNumber)")
    
  2. امنح وكيل خدمة IAP الدور roles/run.invoker على خدمة Cloud Run. يتيح ذلك لخدمة IAP استدعاء خدمتك بعد مصادقة المستخدم ومنحه الإذن.
    gcloud run services add-iam-policy-binding generative-web-navigator \
        --region=europe-west1 \
        --member="serviceAccount:service-$PROJECT_NUMBER@gcp-sa-iap.iam.gserviceaccount.com" \
        --role="roles/run.invoker"
    
  3. امنح حساب المستخدم دور roles/iap.httpsResourceAccessor. يتيح لك ذلك الوصول إلى موارد HTTPS المحمية بواسطة IAP.
    gcloud beta iap web add-iam-policy-binding \
        --resource-type=cloud-run \
        --region=europe-west1 \
        --service=generative-web-navigator \
        --member="user:$(gcloud config get-value account)" \
        --role="roles/iap.httpsResourceAccessor"
    

10. اختبار التطبيق

  1. احصل على عنوان URL للخدمة التي تم نشرها:
    gcloud run services describe generative-web-navigator --format='value(status.url)' --region=europe-west1
    
  2. انسخ عنوان URL وافتحه في متصفّح الويب. بما أنّ الخدمة محمية باستخدام ميزة "الشراء داخل التطبيق"، سيُطلب منك تسجيل الدخول باستخدام حسابك على Google إذا لم يسبق لك ذلك. بعد المصادقة، من المفترض أن تظهر لك الصفحة الأولى التي تم إنشاؤها تلقائيًا.
  3. انقر على أي رابط للانتقال إلى صفحة جديدة سينشئها الذكاء الاصطناعي استنادًا إلى الرابط الذي نقرت عليه.

لقد نجحت في ذلك. لقد نشرت بنجاح موقعًا إلكترونيًا لواجهة مستخدم توليدية على Cloud Run وحميته باستخدام IAP.

11. الخاتمة

تهانينا! لقد نشرت موقعًا إلكترونيًا آمنًا لواجهة مستخدم توليدية باستخدام Cloud Run وVertex AI وIAP.

(اختياري) إخلاء مساحة تخزين

إذا أردت حذف ما أنشأته، يمكنك حذف مشروعك على Cloud لتجنُّب تحمّل رسوم إضافية.

على الرغم من أنّ Cloud Run لا يفرض رسومًا عندما لا تكون الخدمة قيد الاستخدام، قد يتم تحصيل رسوم منك مقابل تخزين نتائج الإنشاء إذا تم إنشاء أي منها. يؤدي حذف مشروعك على السحابة الإلكترونية إلى إيقاف الفوترة لجميع الموارد المستخدَمة في هذا المشروع.

إذا أردت، يمكنك حذف المشروع باتّباع الخطوات التالية:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

يمكنك أيضًا حذف الموارد غير الضرورية من قرص cloudshell. يمكنك إجراء ما يلي:

  1. احذف دليل مشروع الدرس البرمجي:
    rm -rf ~/gen-ui-on-cloudrun
    
  2. تحذير! لا يمكن التراجع عن الإجراء التالي. إذا أردت حذف كل المحتوى على Cloud Shell لإخلاء بعض المساحة، يمكنك حذف دليل منزلك بأكمله. يجب التأكّد من حفظ كل ما تريد الاحتفاظ به في مكان آخر.
    sudo rm -rf $HOME