الصورة اليومية: التمرين المعملي 3: إنشاء صورة مجمّعة لأحدث الصور

1. نظرة عامة

في هذا الدرس التطبيقي حول الترميز، يمكنك إنشاء خدمة Cloud Run، وهي خدمة مجمّعة جديدة سيتم تشغيلها بواسطة Cloud Scheduler على فترات زمنية منتظمة. تجلب الخدمة أحدث الصور التي تم تحميلها وتنشئ صورًا مجمّعة من تلك الصور: تعثر على قائمة الصور الحديثة في Cloud Firestore، ثم تنزِّل ملفات الصور الفعلية من Cloud Storage.

df20f5d0402b54b4.png

المُعطيات

  • Cloud Run
  • Cloud Scheduler
  • تخزين في السحابة الإلكترونية
  • Cloud Firestore

2. الإعداد والمتطلبات

إعداد بيئة ذاتية

  1. سجِّل الدخول إلى Google Cloud Console وأنشئ مشروعًا جديدًا أو أعِد استخدام مشروع حالي. إذا لم يكن لديك حساب على Gmail أو Google Workspace، عليك إنشاء حساب.

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

  • اسم المشروع هو الاسم المعروض للمشاركين في هذا المشروع. وهي عبارة عن سلسلة أحرف لا تستخدمها Google APIs، ويمكنك تحديثها في أي وقت.
  • يجب أن يكون رقم تعريف المشروع فريدًا في جميع مشاريع Google Cloud وغير قابل للتغيير (لا يمكن تغييره بعد ضبطه). تنشئ Cloud Console سلسلة فريدة تلقائيًا. فعادةً لا تهتم بما هو. في معظم الدروس التطبيقية حول الترميز، يجب الرجوع إلى رقم تعريف المشروع (والذي يتم تحديده عادةً على أنّه PROJECT_ID). لذلك، إذا لم يعجبك، يمكنك إنشاء رقم تعريف عشوائي آخر، أو يمكنك تجربة رقم تعريف المشروع الخاص بك ومعرفة ما إذا كان متاحًا. بعد أن يصبح "مجمّد" بعد إنشاء المشروع.
  • هناك قيمة ثالثة، وهي رقم المشروع الذي تستخدمه بعض واجهات برمجة التطبيقات. اطّلِع على مزيد من المعلومات حول هذه القيم الثلاث في المستندات.
  1. بعد ذلك، عليك تفعيل الفوترة في Cloud Console لاستخدام الموارد/واجهات برمجة التطبيقات في Cloud. إنّ تنفيذ هذا الدرس التطبيقي حول الترميز لن يكون مكلفًا أو مكلفًا على الإطلاق. لإيقاف تشغيل الموارد حتى لا تتحمل الفوترة بعد أكثر من هذا البرنامج التعليمي، اتبع أي عملية "تنظيف". التعليمات الموجودة في نهاية الدرس التطبيقي حول الترميز. يكون مستخدمو Google Cloud الجدد مؤهَّلون للانضمام إلى برنامج فترة تجريبية مجانية بقيمة 300 دولار أمريكي.

بدء Cloud Shell

مع أنّه يمكن إدارة Google Cloud عن بُعد من الكمبيوتر المحمول، ستستخدم في هذا الدرس التطبيقي Google Cloud Shell، وهي بيئة سطر أوامر يتم تشغيلها في السحابة الإلكترونية.

من وحدة تحكّم Google Cloud Platform، انقر على رمز Cloud Shell في شريط الأدوات العلوي الأيسر:

bce75f34b2c53987.png

من المفترَض أن تستغرق عملية إدارة الحسابات والاتصال بالبيئة بضع لحظات فقط. عند الانتهاء، من المفترض أن يظهر لك شيء مثل هذا:

f6ef2b5f13479f3a.png

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

3- تفعيل واجهات برمجة التطبيقات

ستحتاج إلى "أداة جدولة المهام في السحابة الإلكترونية" لتشغيل خدمة "تشغيل في السحابة الإلكترونية" على فترات زمنية منتظمة. تأكّد من أنّه مفعَّل:

gcloud services enable cloudscheduler.googleapis.com

من المفترض أن يتم الانتهاء من العملية بنجاح:

Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.

4. استنساخ الرمز

استنسِخ الرمز إذا لم يسبق لك إجراء ذلك في التمرين المعملي السابق للرموز:

git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop

يمكنك بعد ذلك الانتقال إلى الدليل الذي يحتوي على الخدمة:

cd serverless-photosharing-workshop/services/collage/nodejs

وسيكون لديك تنسيق الملفات التالي للخدمة:

services
 |
 ├── collage
      |
      ├── nodejs
           |
           ├── Dockerfile
           ├── index.js
           ├── package.json

داخل المجلد، لديك 3 ملفات:

  • يحتوي index.js على رمز Node.js.
  • يحدد package.json تبعيات المكتبة
  • تحدِّد السمة Dockerfile صورة الحاوية.

5- استكشاف الرمز البرمجي

التبعيات

يحدّد ملف package.json ملحقات المكتبة المطلوبة:

{
  "name": "collage_service",
  "version": "0.0.1",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "bluebird": "^3.7.2",
    "express": "^4.17.1",
    "imagemagick": "^0.1.3",
    "@google-cloud/firestore": "^4.9.9",
    "@google-cloud/storage": "^5.8.3"
  }
}

ونعتمد على مكتبة Cloud Storage لقراءة ملفات الصور وحفظها في Cloud Storage. أعلنّا عن اعتمادية على Cloud Firestore لاسترجاع البيانات الوصفية للصور التي خزّنناها سابقًا. Express هو إطار عمل ويب لـ JavaScript أو عُقدة. يتم استخدام Bluebird لمعالجة الوعود، أما Imagemagick فهو مكتبة لمعالجة الصور.

ملف شامل

تحدِّد السمة Dockerfile صورة الحاوية للتطبيق:

FROM node:14-slim

# installing Imagemagick
RUN set -ex; \
  apt-get -y update; \
  apt-get -y install imagemagick; \
  rm -rf /var/lib/apt/lists/*

WORKDIR /picadaily/services/collage
COPY package*.json ./
RUN npm install --production
COPY . .
CMD [ "npm", "start" ]

نستخدم صورة أساسية للعقدة 14 خفيفة. نحن بصدد تثبيت مكتبة imagemagick. ثم نثبّت وحدات NPM التي تحتاجها التعليمة البرمجية، ونشغل رمز العقدة مع npm start.

index.js

لنلقِ نظرة عن كثب على رمز index.js:

const express = require('express');
const imageMagick = require('imagemagick');
const Promise = require("bluebird");
const path = require('path');
const {Storage} = require('@google-cloud/storage');
const Firestore = require('@google-cloud/firestore');

نحتاج إلى الاعتماديات المختلفة اللازمة لتشغيل برنامجنا: Express هو إطار عمل Node Web الذي سنستخدمه، وImageMagick مكتبة لإجراء معالجة الصور، وBluebird عبارة عن مكتبة للتعامل مع وعود JavaScript، واستخدام Path للتعامل مع الملفات والأدلة، في حين تُستخدم مساحة التخزين وFirestore على التوالي مع Google Cloud Storage (مجموعات الصور الخاصة بنا) ومخزن بيانات Cloud Firestore.

const app = express();

app.get('/', async (req, res) => {
    try {
        console.log('Collage request');

        /* ... */

    } catch (err) {
        console.log(`Error: creating the collage: ${err}`);
        console.error(err);
        res.status(500).send(err);
    }
});

أعلاه، لدينا بنية معالج العُقد: يستجيب تطبيقنا لطلبات HTTP GET. ونعالج بعض الأخطاء في حال حدوث أي خطأ. دعونا الآن نلقي نظرة على ما بداخل هذا الهيكل.

const thumbnailFiles = [];
const pictureStore = new Firestore().collection('pictures');
const snapshot = await pictureStore
    .where('thumbnail', '==', true)
    .orderBy('created', 'desc')
    .limit(4).get();

if (snapshot.empty) {
    console.log('Empty collection, no collage to make');
    res.status(204).send("No collage created.");
} else {

    /* ... */

}

ستحتاج خدمة الصور المجمَّعة إلى أربع صور على الأقل (تم إنشاء الصور المصغّرة الخاصة بها)، لذا احرص على تحميل 4 صور أولاً.

نسترد آخر 4 صور حمّلها المستخدمون، من البيانات الوصفية المخزنة في Cloud Firerstore. ونتحقّق مما إذا كانت المجموعة الناتجة فارغة أم لا، ثم ننتقل إلى الخطوة التالية في الفرع الآخر من رمزنا.

لنجمع قائمة بأسماء الملفات:

snapshot.forEach(doc => {
    thumbnailFiles.push(doc.id);
});
console.log(`Picture file names: ${JSON.stringify(thumbnailFiles)}`);

سننزِّل كل ملف من هذه الملفات من حزمة الصور المصغّرة التي يأتي اسمها من متغيّر بيئة تم ضبطه في وقت النشر:

const thumbBucket = storage.bucket(process.env.BUCKET_THUMBNAILS);

await Promise.all(thumbnailFiles.map(async fileName => {
    const filePath = path.resolve('/tmp', fileName);
    await thumbBucket.file(fileName).download({
        destination: filePath
    });
}));
console.log('Downloaded all thumbnails');

بعد تحميل أحدث الصور المصغّرة، سنستخدم مكتبة ImageMagick لإنشاء شبكة بحجم 4×4 من هذه الصور المصغّرة. نستخدِم مكتبة Bluebird وتطبيق Promise لتحويل الرمز المستند إلى معاودة الاتصال إلى رمز متوافق مع async / await، ثم ننتظر الوعد المتمثل في إنشاء صورة مجمّعة:

const collagePath = path.resolve('/tmp', 'collage.png');

const thumbnailPaths = thumbnailFiles.map(f => path.resolve('/tmp', f));
const convert = Promise.promisify(im.convert);
await convert([
    '(', ...thumbnailPaths.slice(0, 2), '+append', ')',
    '(', ...thumbnailPaths.slice(2), '+append', ')',
    '-size', '400x400', 'xc:none', '-background', 'none',  '-append',
    collagePath]);
console.log("Created local collage picture");

نظرًا لأنه قد تم حفظ الصورة المجمَّعة على القرص محليًا في المجلد المؤقت، نحتاج الآن إلى تحميلها على Cloud Storage، ثم عرض استجابة ناجحة (رمز الحالة 2xx):

await thumbBucket.upload(collagePath);
console.log("Uploaded collage to Cloud Storage bucket ${process.env.BUCKET_THUMBNAILS}");

res.status(204).send("Collage created.");

حان الوقت الآن لجعل نص Node Script يستمع للطلبات الواردة:

const PORT = process.env.PORT || 8080;

app.listen(PORT, () => {
    console.log(`Started collage service on port ${PORT}`);
});

وفي نهاية الملف المصدر، لدينا تعليمات لجعل Express يبدأ فعلاً تطبيق الويب على المنفذ الافتراضي 8080.

6- الاختبار محليًا

اختبِر الرمز البرمجي محليًا للتأكّد من عمله قبل نشره على السحابة الإلكترونية.

في المجلد collage/nodejs، ثبِّت اعتماديات npm وابدأ تشغيل الخادم:

npm install; npm start

إذا سارت الأمور على ما يرام، من المفترض أن يبدأ تشغيل الخادم على المنفذ 8080:

Started collage service on port 8080

استخدِم CTRL-C للخروج.

7. الإنشاء والنشر في Cloud Run

قبل النشر على Cloud Run، اضبط منطقة Cloud Run على إحدى المناطق والنظام الأساسي المتوافقَين على managed:

gcloud config set run/region europe-west1
gcloud config set run/platform managed

يمكنك التحقّق من أنّه تم ضبط الإعدادات:

gcloud config list

...
[run]
platform = managed
region = europe-west1

بدلاً من إنشاء صورة الحاوية ونشرها باستخدام Cloud Build يدويًا، يمكنك أيضًا الاعتماد على Cloud Run لإنشاء صورة الحاوية نيابةً عنك باستخدام Google Cloud Buildpacks.

شغِّل الأمر التالي لإنشاء صورة الحاوية:

BUCKET_THUMBNAILS=thumbnails-$GOOGLE_CLOUD_PROJECT
SERVICE_NAME=collage-service
gcloud run deploy $SERVICE_NAME \
    --source . \
    --no-allow-unauthenticated \
    --update-env-vars BUCKET_THUMBNAILS=$BUCKET_THUMBNAILS

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

يُرجى العلم أيضًا أنّ النشر المستند إلى المصدر يستخدم artifact Registry لتخزين الحاويات المُنشأة. Artifact Registry هو إصدار حديث من Google Container Registry. سيطلب واجهة سطر الأوامر تفعيل واجهة برمجة التطبيقات إذا لم تكن مفعَّلة في المشروع، وسينشئ مستودعًا بالاسم cloud-run-source-deploy في المنطقة التي تنشر فيها.

تجعل العلامة --no-allow-unauthenticated خدمة تشغيل السحابة الإلكترونية خدمة داخلية لا يتم تشغيلها إلا من خلال حسابات خدمة محدَّدة.

8. إعداد أداة جدولة المهام في السحابة الإلكترونية

الآن وبعد أن أصبحت خدمة Cloud Run جاهزة وتم نشرها، حان الوقت لإنشاء جدول زمني منتظم لاستدعاء الخدمة كل دقيقة.

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

SERVICE_ACCOUNT=collage-scheduler-sa
gcloud iam service-accounts create $SERVICE_ACCOUNT \
   --display-name "Collage Scheduler Service Account"

يمكنك منح إذن لحساب الخدمة لاستدعاء خدمة Cloud Run:

gcloud run services add-iam-policy-binding $SERVICE_NAME \
   --member=serviceAccount:$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \
   --role=roles/run.invoker

إنشاء مهمة في Cloud Scheduler لتنفيذها كل دقيقة:

SERVICE_URL=$(gcloud run services describe $SERVICE_NAME --format 'value(status.url)')
gcloud scheduler jobs create http $SERVICE_NAME-job --schedule "* * * * *" \
   --http-method=GET \
   --location=europe-west1 \
   --uri=$SERVICE_URL \
   --oidc-service-account-email=$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \
   --oidc-token-audience=$SERVICE_URL

يمكنك الانتقال إلى قسم Cloud Scheduler في Cloud Console لمعرفة أنه تم إعداده ويشير إلى عنوان URL لخدمة Cloud Run:

35119e28c1da53f3.png

9. اختبار الخدمة

لاختبار عمل الإعداد، ابحث في حزمة thumbnails عن الصورة المجمَّعة (التي تُعرف باسم collage.png). يمكنك أيضًا التحقّق من سجلّات الخدمة من خلال اتّباع الخطوات التالية:

93922335a384be2e.png

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

إذا كنت لا تريد مواصلة الدروس التطبيقية الأخرى ضمن هذه السلسلة، يمكنك إخلاء بعض الموارد من أجل توفير التكاليف والتحلّي بصفات المواطنين الصالحين في السحابة الإلكترونية بشكل عام. يمكنك تنظيف الموارد بشكل فردي على النحو التالي.

حذف الخدمة:

gcloud run services delete $SERVICE_NAME -q

حذف مهمة أداة جدولة المهام في السحابة الإلكترونية:

gcloud scheduler jobs delete $SERVICE_NAME-job -q

بدلاً من ذلك، يمكنك حذف المشروع بالكامل:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

11. تهانينا!

تهانينا! لقد أنشأتَ خدمة مُجدوَلة: بفضل Cloud Scheduler، الذي ينقل رسالة كل دقيقة حول موضوع Pub/Sub، تم استدعاء خدمة الصورة المجمّعة في Cloud Run ويمكنها إلحاق الصور معًا لإنشاء الصورة الناتجة.

المواضيع التي تناولناها

  • Cloud Run
  • Cloud Scheduler
  • تخزين في السحابة الإلكترونية
  • Cloud Firestore

الخطوات التالية