מעבר מ-App Engine Memcache ל-Cloud Memorystore (מודול 13)

1. סקירה כללית

מטרת סדרת ה-codelabs של Serverless Migration Station (הדרכות מעשיות בקצב אישי) והסרטונים שקשורים אליה היא לעזור למפתחים של Google Cloud Serverless לחדש את האפליקציות שלהם. לשם כך, הם מקבלים הדרכה לגבי העברה אחת או יותר, בעיקר מעבר משירותים מדור קודם. כך האפליקציות שלכם יהיו ניידות יותר, ותקבלו יותר אפשרויות וגמישות. תוכלו לשלב את האפליקציות עם מגוון רחב יותר של מוצרי Cloud ולגשת אליהם, ולשדרג בקלות רבה יותר לגרסאות חדשות יותר של השפה. הסדרה הזו מתמקדת בהתחלה במשתמשי הענן הראשונים, בעיקר מפתחים של App Engine (סביבה רגילה), אבל היא רחבה מספיק כדי לכלול פלטפורמות אחרות של Serverless כמו Cloud Functions ו-Cloud Run, או במקומות אחרים אם רלוונטי.

המטרה של ה-Codelab הזה היא להראות למפתחים של App Engine ב-Python 2 איך לבצע מיגרציה מ-App Engine Memcache ל-Cloud Memorystore (ל-Redis). יש גם העברה מרומזת מ-App Engine ndb אל Cloud NDB, אבל היא מתוארת בעיקר ב-Codelab מודול 2. כדאי לעיין בו כדי לקבל מידע נוסף עם הוראות מפורטות.

כאן אפשר להבין איך

  • הגדרת מופע של Cloud Memorystore (מ-Cloud Console או מהכלי gcloud)
  • הגדרת מחבר של חיבור לרשת (VPC) מאפליקציית serverless ב-Cloud (מ-Cloud Console או מהכלי gcloud)
  • העברה מ-App Engine Memcache ל-Cloud Memorystore
  • הטמעה של שמירה במטמון באמצעות Cloud Memorystore באפליקציה לדוגמה
  • העברה מ-App Engine ndb ל-Cloud NDB

הדרישות

סקר

איך תשתמשו במדריך הזה?

רק לקרוא לקרוא ולהשלים את התרגילים

איך היית מדרג את חוויית השימוש שלך ב-Python?

מתחילים ביניים מומחים

איזה דירוג מתאים לדעתך לחוויית השימוש שלך בשירותי Google Cloud?

מתחילים ביניים מומחים

2. רקע

Codelab זה מדגים איך להעביר אפליקציה לדוגמה מ-App Engine Memcache (ומ-NDB) ל-Cloud Memorystore (ול-Cloud NDB). התהליך הזה כולל החלפה של תלות בשירותים בחבילה של App Engine, וכך האפליקציות שלכם ניידות יותר. אתם יכולים להמשיך להשתמש ב-App Engine או לשקול מעבר לאחת מהחלופות שתיארנו קודם.

המיגרציה הזו דורשת יותר מאמץ בהשוואה למיגרציות אחרות בסדרה הזו. המוצר המומלץ להחלפת App Engine Memcache הוא Cloud Memorystore, שירות מנוהל לחלוטין של אחסון במטמון מבוסס-ענן. ‫Memorystore תומך בשני מנועי קאש פופולריים של קוד פתוח: Redis ו-Memcached. מודול ההעברה הזה משתמש ב-Cloud Memorystore for Redis. מידע נוסף זמין במאמר סקירה כללית על Memorystore ו-Redis.

מכיוון ש-Memorystore דורש שרת פעיל, נדרש גם Cloud VPC. במילים אחרות, צריך ליצור מחבר Serverless VPC Access כדי שאפליקציית App Engine תוכל להתחבר למכונת Memorystore דרך כתובת ה-IP הפרטית שלה. בסיום התרגיל, האפליקציה תעודכן כך שהיא תפעל כמו קודם, אבל Cloud Memorystore יהיה שירות ה-caching במקום שירות Memcache של App Engine.

המדריך הזה מתחיל עם אפליקציית הדוגמה של מודול 12 ב-Python 2, ואחריו שדרוג קל נוסף ואופציונלי ל-Python 3. אם אתם כבר יודעים איך לגשת לשירותים בחבילה של App Engine מ-Python 3 באמצעות Python 3 App Engine SDK, אתם יכולים להתחיל עם גרסת Python 3 של אפליקציית הדוגמה Module 12. כדי לעשות זאת, תצטרכו להפסיק את השימוש ב-SDK, כי Memorystore לא נכלל בחבילת השירותים של App Engine. הסבר על שימוש ב-Python 3 App Engine SDK לא נכלל במדריך הזה.

במדריך הזה מפורטים השלבים העיקריים הבאים:

  1. הגדרה/עבודה מקדימה
  2. הגדרת שירותי שמירה במטמון
  3. עדכון קובצי תצורה
  4. עדכון האפליקציה הראשית

3. הגדרה/עבודה מקדימה

הכנת פרויקט בענן

מומלץ לעשות שימוש חוזר באותו פרויקט שבו השתמשתם כדי להשלים את ה-Codelab של מודול 12. אפשר גם ליצור פרויקט חדש לגמרי או להשתמש בפרויקט קיים אחר. לכל codelab בסדרה הזו יש קטע START (קוד הבסיס שממנו מתחילים) וקטע FINISH (האפליקציה שהועברה). קוד ה-FINISH מסופק כדי שתוכלו להשוות את הפתרונות שלכם לפתרונות שלנו במקרה של בעיות. תמיד אפשר לחזור להתחלה אם משהו משתבש. נקודות הבדיקה האלה נועדו לוודא שתצליחו ללמוד איך לבצע את ההעברות.

בכל פרויקט ב-Cloud שבו תשתמשו, הקפידו לוודא שיש לו חשבון פעיל לחיוב. בנוסף, צריך לוודא ש-App Engine מופעל. חשוב לעיין בהשלכות העלויות הכלליות של ביצוע ההדרכות האלה ולוודא שאתם מבינים אותן. אבל בניגוד לשיעורים מעשיים אחרים בסדרה הזו, ב-Codelab הזה נעשה שימוש במשאבי Cloud שלא נכללים בתוכנית בחינם, ולכן תצטברו עלויות מסוימות במהלך התרגיל. מידע ספציפי יותר על העלויות יסופק יחד עם המלצות לצמצום השימוש, כולל הוראות בסוף המאמר לשחרור משאבים כדי לצמצם את חיובים.

קבלת אפליקציה לדוגמה של ערך בסיס

החל מקוד הבסיס של מודול 12 שאיתו אנחנו מתחילים, ה-codelab הזה מדריך אתכם בתהליך ההעברה שלב אחר שלב. בסיום, תגיעו לאפליקציה פעילה של מודול 13 שדומה מאוד לקוד באחת מתיקיות ה-FINISH. הנה מקורות המידע:

תיקיית START צריכה להכיל את הקבצים הבאים:

$ ls
README.md               app.yaml                main.py                 requirements.txt        templates                

אם אתם מתחילים מהגרסה של Python 2, יהיה גם קובץ appengine_config.py ואולי תיקייה lib אם השלמתם את ה-codelab של מודול 12.

(פריסה מחדש) של האפליקציה של מודול 12

השלבים שנותרו לביצוע לפני המעבר:

  1. אם צריך, כדאי לעיין שוב בgcloudכלי לשורת הפקודה
  2. (אם צריך) פורסים מחדש את הקוד של מודול 12 ב-App Engine

משתמשי Python 2 צריכים למחוק את התיקייה lib ולהתקין אותה מחדש באמצעות הפקודות הבאות:

rm -rf ./lib; pip install -t lib -r requirements.txt                

עכשיו כל המשתמשים (Python 2 ו-Python 3) צריכים להעלות את הקוד ל-App Engine באמצעות הפקודה הבאה:

gcloud app deploy                

אחרי ההטמעה המוצלחת, צריך לוודא שהאפליקציה נראית ופועלת בדיוק כמו האפליקציה במודול 12, אפליקציית אינטרנט שעוקבת אחרי ביקורים ומאחסנת אותם במטמון למשך שעה עבור אותו משתמש:

dfe56a02ae59ddd8.png

מכיוון שהביקורים האחרונים נשמרים במטמון, רענון הדף אמור להיות מהיר יחסית.

4. הגדרת שירותי שמירה במטמון

Cloud Memorystore לא בלי שרת (serverless). נדרש מופע, ובמקרה הזה מופע של Redis שפועל. בניגוד ל-Memcache,‏ Memorystore הוא מוצר Cloud עצמאי ואין לו תוכנית בחינם. לכן חשוב לעיין במידע על התמחור של Memorystore for Redis לפני שממשיכים. כדי לצמצם את העלויות של התרגיל הזה, מומלץ להשתמש בכמות המינימלית של משאבים להפעלה: רמת שירות Basic וקיבולת של 1GB.

מופע Memorystore נמצא ברשת אחרת מזו של אפליקציית App Engine (מופעים), ולכן צריך ליצור מחבר Serverless VPC Access כדי שאפליקציית App Engine תוכל לגשת למשאבי Memorystore. כדי לצמצם את העלויות של VPC, מומלץ לבחור את סוג האינסטנס (f1-micro) ולבקש את המספר הקטן ביותר של אינסטנסים (אנחנו ממליצים על מינימום 2, מקסימום 3). אפשר גם לעיין בדף המידע על התמחור של VPC.

אנחנו חוזרים על ההמלצות האלה לצמצום עלויות בכל שלב בתהליך היצירה של כל משאב נדרש. בנוסף, כשיוצרים משאבי Memorystore ו-VPC ב-Cloud Console, בפינה השמאלית העליונה מוצג מחשבון התמחור של כל מוצר, שנותן הערכה של העלות החודשית (ראו את האיור שלמטה). הערכים האלה משתנים אוטומטית אם משנים את האפשרויות. זו דוגמה למה שצריך להופיע:

7eb35ebf7248c010.png

שני המשאבים נדרשים, ולא משנה איזה מהם יוצרים קודם. אם יוצרים את מופע Memorystore קודם, אפליקציית App Engine לא יכולה להגיע אליו בלי מחבר ה-VPC. באופן דומה, אם יוצרים את מחבר ה-VPC קודם, אין ברשת ה-VPC הזו שום דבר שאפליקציית App Engine יכולה לתקשר איתו. במדריך הזה יוצרים קודם את מכונת Memorystore ואז את מחבר ה-VPC.

אחרי ששני המשאבים יהיו אונליין, תוסיפו את המידע הרלוונטי ל-app.yaml כדי שהאפליקציה תוכל לגשת למטמון. אפשר גם לעיין במדריכים בנושא Python 2 או Python 3 במסמכים הרשמיים. כדאי לעיין גם במדריך בנושא שמירת נתונים במטמון בדף ההעברה של Cloud NDB ‏ ( Python 2 או Python 3).

יצירת מכונה של Cloud Memorystore

ל-Cloud Memorystore אין רמת שירות בחינם, ולכן מומלץ להקצות את כמות המשאבים המינימלית כדי להשלים את ה-Codelab. כדי לצמצם את העלויות, אפשר להשתמש בהגדרות הבאות:

  • בוחרים את רמת השירות הנמוכה ביותר: Basic (ברירת המחדל במסוף: Standard, ברירת המחדל ב-gcloud: Basic).
  • בוחרים את נפח האחסון הקטן ביותר: 1GB (ברירת המחדל במסוף: 16GB, ברירת המחדל ב-gcloud: 1GB).
  • בדרך כלל, הגרסאות החדשות ביותר של כל תוכנה דורשות את כמות המשאבים הגדולה ביותר, אבל גם לא מומלץ לבחור את הגרסה הכי ישנה. הגרסה השנייה הכי עדכנית כרגע היא Redis version 5.0 (ברירת המחדל במסוף: 6.x)

בקטע הבא נסביר איך ליצור את המכונה מ-Cloud Console, בהתאם להגדרות האלה. אם אתם מעדיפים לעשות את זה משורת הפקודה, דלגו קדימה.

מתוך Cloud Console

נכנסים אל הדף Cloud Memorystore במסוף Cloud (יכול להיות שתתבקשו להזין פרטי חיוב). אם עדיין לא הפעלתם את Memorystore, תופיע בקשה להפעלה:

68318997e3105db6.png

אחרי שתפעילו אותו (יכול להיות שגם את החיוב), תגיעו ללוח הבקרה של Memorystore. כאן אפשר לראות את כל המופעים שנוצרו בפרויקט. לפרויקט שמוצג למטה אין ישויות אב, ולכן מוצגת ההודעה 'אין שורות להצגה'. כדי ליצור מופע Memorystore, לוחצים על Create instance (יצירת מופע) בחלק העליון:

63547aa575838a36.png

בדף הזה יש טופס שצריך למלא עם ההגדרות הרצויות כדי ליצור את מופע Memorystore:

b77d927287fdf4c7.png

כדי לצמצם את העלויות של המדריך הזה ושל אפליקציית הדוגמה, כדאי לפעול לפי ההמלצות שצוינו קודם. אחרי שבוחרים את האפשרויות הרצויות, לוחצים על יצירה. תהליך היצירה נמשך כמה דקות. בסיום, מעתיקים את כתובת ה-IP של המופע ואת מספר היציאה כדי להוסיף אותם אל app.yaml.

משורת הפקודה

אמנם יצירת מופעי Memorystore מ-Cloud Console מספקת מידע ויזואלי, אבל יש אנשים שמעדיפים את שורת הפקודה. לפני שממשיכים, חשוב לוודא שgcloud מותקן ומאותחל.

בדומה למסוף Cloud, צריך להפעיל את Cloud Memorystore for Redis. מריצים את הפקודה gcloud services enable redis.googleapis.com וממתינים לסיום שלה, כמו בדוגמה הזו:

$ gcloud services enable redis.googleapis.com
Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.

אם השירות כבר הופעל, הפעלת הפקודה (שוב) לא תגרום לתופעות לוואי (שליליות). אחרי שמפעילים את השירות, יוצרים מכונת Memorystore. הפקודה תיראה כך:

gcloud redis instances create NAME --redis-version VERSION \
    --region REGION --project PROJECT_ID

בוחרים שם למופע Memorystore שלכם. בשיעור ה-Lab הזה נעשה שימוש בשם demo-ms ובמזהה הפרויקט my-project. האזור של האפליקציה לדוגמה הוא us-central1 (זהה ל-us-central), אבל אתם יכולים להשתמש באזור שקרוב יותר אליכם אם זמן האחזור חשוב לכם. צריך לבחור את אותו אזור כמו באפליקציית App Engine. אפשר לבחור כל גרסת Redis שרוצים, אבל אנחנו משתמשים בגרסה 5 כמומלץ קודם. בהתאם להגדרות האלה, זו הפקודה שתצטרכו להזין (יחד עם הפלט שקשור אליה):

$ gcloud redis instances create demo-ms --region us-central1 \
    --redis-version redis_5_0 --project my-project

Create request issued for: [demo-ms]
Waiting for operation [projects/my-project/locations/us-central1/operations/operation-xxxx] to complete...done.
Created instance [demo-ms].

בניגוד לברירות המחדל של Cloud Console, ‏gcloud מוגדר כברירת מחדל עם משאבים מינימליים. התוצאה היא שלא נדרשו בנתונים של הפקודה הזו לא רמת השירות ולא נפח האחסון. יצירת מופע Memorystore נמשכת כמה דקות. בסיום, שימו לב לכתובת ה-IP ולמספר היציאה של המופע, כי הם יתווספו ל-app.yaml בקרוב.

אישור שהמופע נוצר

מ-Cloud Console או משורת הפקודה

בין אם יצרתם את המופע דרך Cloud Console או דרך שורת הפקודה, תוכלו לוודא שהוא זמין ומוכן לשימוש באמצעות הפקודה הבאה: gcloud redis instances list --region REGION

זו הפקודה לבדיקת מופעים באזור us-central1, וגם הפלט הצפוי שבו מוצג המופע שיצרנו:

$ gcloud redis instances list --region us-central1
INSTANCE_NAME  VERSION    REGION       TIER   SIZE_GB  HOST         PORT  NETWORK  RESERVED_IP     STATUS  CREATE_TIME
demo-ms        REDIS_5_0  us-central1  BASIC  1        10.aa.bb.cc  6379  default  10.aa.bb.dd/29  READY   2022-01-28T09:24:45

כשמתבקשים לספק את פרטי המופע או להגדיר את האפליקציה, חשוב להשתמש ב-HOST וב-PORT (ולא ב-RESERVED_IP). לוח הבקרה של Cloud Memorystore ב-Cloud Console אמור להציג עכשיו את המופע הזה:

c5a6948ec1c056ed.png

ממכונה וירטואלית ב-Compute Engine

אם יש לכם מכונה וירטואלית (VM) ב-Compute Engine, אתם יכולים גם לשלוח פקודות ישירות מ-VM למופע Memorystore כדי לוודא שהוא פועל. חשוב לזכור שלשימוש במכונה וירטואלית יכולות להיות עלויות משויכות, בלי קשר למשאבים שבהם אתם כבר משתמשים.

יצירת מחבר של חיבור לרשת (VPC) מאפליקציית serverless

בדומה ל-Cloud Memorystore, אפשר ליצור את מחבר ה-VPC של Cloud ללא שרת במסוף Cloud או בשורת הפקודה. באופן דומה, ל-Cloud VPC אין תוכנית חינמית, ולכן מומלץ להקצות את כמות המשאבים המינימלית כדי להשלים את ה-codelab, כדי לשמור על עלויות מינימליות. אפשר להשיג זאת באמצעות ההגדרות הבאות:

  • בוחרים את המספר המינימלי של מופעים: 3 (קונסולה וgcloud ברירת מחדל: 10)
  • בוחרים את סוג המכונה הכי זול: f1-micro (ברירת המחדל במסוף: e2-micro, אין ברירת מחדל ל-gcloud)

בקטע הבא מוסבר איך ליצור את המחבר מ-Cloud Console באמצעות ההגדרות של Cloud VPC שצוינו למעלה. אם אתם מעדיפים לעשות זאת משורת הפקודה, דלגו לקטע הבא.

מתוך מסוף Cloud

נכנסים לדף Cloud Networking "Serverless VPC access"‎ במסוף Cloud (יכול להיות שתתבקשו להזין פרטי חיוב). אם עדיין לא הפעלתם את ה-API, תתבקשו לעשות זאת:

e3b9c0651de25e97.png

אחרי שמפעילים את ה-API (ואולי גם את החיוב), מגיעים ללוח הבקרה שבו מוצגים כל מחברי ה-VPC שנוצרו. בפרויקט שמוצג בצילום המסך שלמטה אין שורות, ולכן מופיעה ההודעה 'אין שורות להצגה'. במסוף, לוחצים על Create Connector (יצירת מחבר) בחלק העליון:

b74b49b9d73b7dcf.png

ממלאים את הטופס עם ההגדרות הרצויות:

6b26b2aafa719f73.png

בוחרים את ההגדרות המתאימות לאפליקציות שלכם. במדריך הזה ובאפליקציה לדוגמה עם הצרכים המינימליים, כדאי לצמצם את העלויות, ולכן מומלץ לפעול לפי ההמלצות שצוינו קודם. אחרי שבוחרים את האפשרויות הרצויות, לוחצים על יצירה. הקצאת מחבר VPC תימשך כמה דקות.

משורת הפקודה

לפני שיוצרים מחבר VPC, צריך להפעיל קודם את Serverless VPC Access API. אחרי הפעלת הפקודה הבאה, הפלט אמור להיראות כך:

$ gcloud services enable vpcaccess.googleapis.com
Operation "operations/acf.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.

אחרי שמפעילים את ה-API, יוצרים מחבר VPC באמצעות פקודה שנראית כך:

gcloud compute networks vpc-access connectors create CONNECTOR_NAME \
    --range 10.8.0.0/28 --region REGION --project PROJECT_ID

בוחרים שם למחבר וכתובת IP התחלתית של בלוק CIDR של /28 שלא נמצא בשימוש. במדריך הזה אנחנו יוצאים מנקודת הנחה ש:

  • מזהה פרויקט: my-project
  • שם מחבר ה-VPC: demo-vpc
  • מספר מופעים מינימלי: 2 (ברירת מחדל) ומספר מופעים מקסימלי: 3
  • סוג המכונה: f1-micro
  • אזור: us-central1
  • בלוק CIDR של IPv4: 10.8.0.0/28 (כמומלץ במסוף Cloud)

אם מריצים את הפקודה הבאה בהתאם להנחות שלמעלה, הפלט אמור להיראות כך:

$ gcloud compute networks vpc-access connectors create demo-vpc \
    --max-instances 3 --range 10.8.0.0/28 --machine-type f1-micro \
    --region us-central1  --project my-project

Create request issued for: [demo-vpc]
Waiting for operation [projects/my-project/locations/us-central1/operations/xxx] to complete...done.
Created connector [demo-vpc].

בפקודה שלמעלה לא מצוינים ערכי ברירת מחדל, כמו מספר מינימלי של 2 מופעים ורשת בשם default. יצירת מחבר VPC נמשכת כמה דקות.

אישור שיצרתם מחבר

אחרי שהתהליך מסתיים, מריצים את פקודת gcloud הבאה, בהנחה שהאזור הוא us-central1, כדי לוודא שהיא נוצרה ומוכנה לשימוש:

$ gcloud compute networks vpc-access connectors list --region us-central1
CONNECTOR_ID  REGION       NETWORK  IP_CIDR_RANGE  SUBNET  SUBNET_PROJECT  MIN_THROUGHPUT  MAX_THROUGHPUT  STATE
demo-vpc      us-central1  default  10.8.0.0/28                            200             300             READY

באופן דומה, במרכז הבקרה אמור להופיע עכשיו המחבר שיצרתם:

e03db2c8140ed014.png

שימו לב למזהה הפרויקט בענן, לשם מחבר ה-VPC ולאזור.

אחרי שיצרתם את משאבי הענן הנוספים שנדרשים, בין אם באמצעות שורת הפקודה או במסוף, הגיע הזמן לעדכן את הגדרות האפליקציה כדי לתמוך בשימוש בהם.

5. עדכון קובצי תצורה

השלב הראשון הוא לבצע את כל העדכונים הנדרשים בקובצי התצורה. המטרה העיקרית של ה-codelab הזה היא לעזור למשתמשים ב-Python 2 לעבור ל-Python 3. עם זאת, בכל אחד מהקטעים הבאים מופיע גם מידע על העברה נוספת ל-Python 3.

requirements.txt

בקטע הזה מוסיפים חבילות לתמיכה ב-Cloud Memorystore וב-Cloud NDB. ב-Cloud Memorystore ל-Redis, מספיק להשתמש בלקוח Redis הרגיל ל-Python ‏ (redis), כי אין ספריית לקוח של Cloud Memorystore כשלעצמה. הוספה של redis ושל google-cloud-ndb ל-requirements.txt, הצטרפות ל-flask מיחידת לימוד 12:

flask
redis
google-cloud-ndb

בקובץ requirements.txt הזה לא מופיעים מספרי גרסאות, ולכן הגרסאות העדכניות ביותר נבחרות. אם מתגלות בעיות תאימות, צריך לציין מספרי גרסאות כדי לנעול גרסאות תקינות.

app.yaml

קטעים חדשים להוספה

זמן הריצה של Python 2 App Engine מחייב חבילות ספציפיות של צד שלישי כשמשתמשים ב-Cloud APIs כמו Cloud NDB, כלומר grpcio ו-setuptools. משתמשי Python 2 צריכים לציין ספריות מובנות כמו אלה יחד עם גרסה זמינה ב-app.yaml. אם עדיין אין לכם קטע libraries, יוצרים אותו ומוסיפים את שתי הספריות כמו בדוגמה הבאה:

libraries:
- name: grpcio
  version: latest
- name: setuptools
  version: latest

כשמעבירים את האפליקציה שלכם, יכול להיות שכבר יש בה קטע libraries. אם כן, ואחד מהם או שניהם חסרים, פשוט מוסיפים אותם לקטע libraries הקיים.grpciosetuptools

לאחר מכן, אפליקציית הדוגמה שלנו צריכה את המידע על מופע Cloud Memorystore ומחבר VPC, לכן מוסיפים את שני הקטעים החדשים הבאים אל app.yaml, בלי קשר לזמן הריצה של Python שבו אתם משתמשים:

env_variables:
    REDIS_HOST: 'YOUR_REDIS_HOST'
    REDIS_PORT: 'YOUR_REDIS_PORT'

vpc_access_connector:
    name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR

זהו, סיימתם את העדכונים הנדרשים. עכשיו הקובץ המעודכן של app.yaml אמור להיראות כך:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

env_variables:
    REDIS_HOST: 'YOUR_REDIS_HOST'
    REDIS_PORT: 'YOUR_REDIS_PORT'

vpc_access_connector:
    name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR

בהמשך מוצגות דוגמאות לשינויים שצריך לבצע ב-app.yaml:

ec2bb027a67debb6.png

*הבדלים ב-Python 3

החלק הזה הוא אופציונלי ורלוונטי רק אם אתם מבצעים ניוד ל-Python 3. כדי לעשות את זה, צריך לבצע כמה שינויים בהגדרות של Python 2. אם אתם לא משדרגים בשלב הזה, אתם יכולים לדלג על הקטע הזה.

ההגדרות threadsafe ו-api_version לא משמשות לזמן הריצה של Python 3, ולכן צריך למחוק את שתיהן. זמן הריצה העדכני של App Engine לא תומך בספריות מובנות של צד שלישי ולא בהעתקה של ספריות לא מובנות. הדרישה היחידה לגבי חבילות של צד שלישי היא לפרט אותן בrequirements.txt. לכן אפשר למחוק את כל הקטע libraries של app.yaml.

בנוסף, זמן הריצה של Python 3 מחייב שימוש במסגרות אינטרנט שמבצעות ניתוב משלהן, ולכן הראינו למפתחים איך לבצע מיגרציה מ-webp2 ל-Flask במודול 1. כתוצאה מכך, צריך לשנות את כל המטפלים בסקריפטים ל-auto. האפליקציה הזו לא מציגה קבצים סטטיים, ולכן אין טעם לכלול רשימה של רכיבי handler (כי כולם הם auto). לכן, אפשר להסיר גם את כל הקטע handlers. כתוצאה מכך, המחרוזת החדשה והמקוצרת app.yaml שמותאמת ל-Python 3 צריכה להיות מקוצרת כך:

runtime: python39

env_variables:
    REDIS_HOST: 'YOUR_REDIS_HOST'
    REDIS_PORT: 'YOUR_REDIS_PORT'

vpc_access_connector:
    name: projects/PROJECT_ID/locations/REGION/connectors/CONNECTOR

סיכום ההבדלים ב-app.yaml כשמבצעים העברה ל-Python 3:

  • מחיקת ההגדרות של threadsafe ושל api_version
  • מחיקת החלק libraries
  • מחיקת הקטע [handlers] (או רק script handlers אם האפליקציה מציגה קבצים סטטיים)

החלפת הערכים

הערכים בקטעים החדשים של Memorystore ושל מחבר ה-VPC הם רק ערכי placeholder. מחליפים את הערכים באותיות רישיות (YOUR_REDIS_HOST, YOUR_REDIS_PORT, PROJECT_ID, REGION, CONNECTOR_NAME) בערכים ששמרתם כשיצרתם את המשאבים האלה קודם לכן. בנוגע למופע Memorystore, חשוב להשתמש ב-HOST (ולא ב-RESERVED_IP) וב-PORT. כך אפשר לקבל את HOST ואת PORT במהירות דרך שורת הפקודה, בהנחה ששם המופע הוא demo-ms ו-REGION הוא us-central1:

$ gcloud redis instances describe demo-ms --region us-central1 \
    --format "value(host,port)"
10.251.161.51   6379

אם כתובת ה-IP של מופע Redis בדוגמה שלנו היא 10.10.10.10, יציאה 6379 בפרויקט my-project שנמצא באזור us-central1 ושם מחבר ה-VPC הוא demo-vpc, הקטעים האלה בקובץ app.yaml ייראו כך:

env_variables:
    REDIS_HOST: '10.10.10.10'
    REDIS_PORT: '6379'

vpc_access_connector:
    name: projects/my-project/locations/us-central1/connectors/demo-vpc

יצירה או עדכון של הקובץ appengine_config.py

הוספת תמיכה בספריות מובנות של צד שלישי

בדומה למה שעשינו עם app.yaml קודם, מוסיפים שימוש בספריות grpcio ו-setuptools. שינוי appengine_config.py כדי לתמוך בספריות מובנות של צד שלישי. אם זה נשמע לכם מוכר, זה בגלל שנדרשנו לעשות את זה גם במודול 2 כשעברנו מ-App Engine ndb ל-Cloud NDB. השינוי הנדרש הוא הוספת התיקייה lib לקבוצת העבודה setuptools.pkg_resources:

4140b3800694f77e.png

*הבדלים ב-Python 3

החלק הזה הוא אופציונלי ורלוונטי רק אם אתם מבצעים ניוד ל-Python 3. אחד השינויים המבורכים בדור השני של App Engine הוא שכבר לא צריך להעתיק (לפעמים נקרא יצירת עותק מקוד של צד שלישי (vendoring)) חבילות של צד שלישי (שאינן מוכללות) ולהפנות לחבילות של צד שלישי שמוכללות ב-app.yaml, כלומר אפשר למחוק את כל קובץ appengine_config.py.

6. עדכון קובצי אפליקציות

יש רק קובץ בקשה אחד, main.py, ולכן כל השינויים בקטע הזה משפיעים רק על הקובץ הזה. צירפנו תמונה שממחישה את השינויים שנבצע כדי להעביר את האפליקציה הזו ל-Cloud Memorystore. הוא מיועד להמחשה בלבד ולא לניתוח מעמיק. העבודה מתבצעת בשינויים שאנחנו מבצעים בקוד.

5d043768ba7be742.png

בואו נתמודד עם כל קטע בנפרד, נתחיל מלמעלה.

עדכון ייבוא

בקטע הייבוא ב-main.py של מודול 12 נעשה שימוש ב-Cloud NDB וב-Cloud Tasks. אלה הייבואים:

לפני:

from flask import Flask, render_template, request
from google.appengine.api import memcache
from google.appengine.ext import ndb

כדי לעבור ל-Memorystore, צריך לקרוא משתני סביבה, ולכן נדרש המודול os של Python, וגם redis, לקוח Python Redis. מכיוון ש-Redis לא יכול לשמור במטמון אובייקטים של Python, צריך להשתמש ב-pickle כדי להעביר את רשימת הביקורים האחרונים, ולכן צריך לייבא גם אותו. אחד היתרונות של Memcache הוא שהסריאליזציה של האובייקטים מתבצעת אוטומטית, בעוד שב-Memorystore צריך לעשות את זה באופן ידני. לבסוף, משדרגים מ-App Engine ndb ל-Cloud NDB על ידי החלפת google.appengine.ext.ndb ב-google.cloud.ndb. אחרי השינויים האלה, הייבוא שלכם אמור להיראות כך:

אחרי:

import os
import pickle
from flask import Flask, render_template, request
from google.cloud import ndb
import redis

עדכון האתחול

האתחול של מודול 12 כולל יצירת מופע של אובייקט האפליקציה Flask‏ app והגדרת קבוע לשעה שלמה של שמירה במטמון:

לפני:

app = Flask(__name__)
HOUR = 3600

כדי להשתמש ב-Cloud APIs צריך לקוח, לכן צריך ליצור מופע של לקוח Cloud NDB מיד אחרי Flask. לאחר מכן, מקבלים את כתובת ה-IP ואת מספר היציאה של מופע Memorystore ממשתני הסביבה שהגדרתם בשלב app.yaml. אחרי שמקבלים את המידע הזה, יוצרים מופע של לקוח Redis. כך נראה הקוד אחרי העדכונים:

אחרי:

app = Flask(__name__)
ds_client = ndb.Client()
HOUR = 3600
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = os.environ.get('REDIS_PORT', '6379')
REDIS = redis.Redis(host=REDIS_HOST, port=REDIS_PORT)

*העברה ל-Python 3

החלק הזה הוא אופציונלי, והוא רלוונטי רק אם אתם מתחילים מגרסת Python 3 של אפליקציית מודול 12. במקרה כזה, יש כמה שינויים נדרשים שקשורים לייבוא ולאתחול.

קודם כל, מכיוון ש-Memcache הוא שירות בחבילה של App Engine, השימוש בו באפליקציית Python 3 מחייב את App Engine SDK, במיוחד את עטיפת אפליקציית WSGI (וגם הגדרה נדרשת אחרת):

לפני:

from flask import Flask, render_template, request
from google.appengine.api import memcache, wrap_wsgi_app
from google.appengine.ext import ndb

app = Flask(__name__)
app.wsgi_app = wrap_wsgi_app(app.wsgi_app)
HOUR = 3600

אנחנו עוברים ל-Cloud Memorystore (שלא נכלל בחבילת השירותים של App Engine כמו Memcache), ולכן צריך להסיר את השימוש ב-SDK. הפעולה פשוטה: מוחקים את השורה שמייבאת את memcache ואת wrap_wsgi_app. אפשר גם למחוק את הקו לשיחות wrap_wsgi_app(). העדכונים האלה משאירים את החלק הזה של האפליקציה (למעשה, את כל האפליקציה) זהה לגרסה של Python 2.

אחרי:

import os
import pickle
from flask import Flask, render_template, request
from google.cloud import ndb
import redis

app = Flask(__name__)
ds_client = ndb.Client()
HOUR = 3600
REDIS_HOST = os.environ.get('REDIS_HOST', 'localhost')
REDIS_PORT = os.environ.get('REDIS_PORT', '6379')
REDIS = redis.Redis(host=REDIS_HOST, port=REDIS_PORT)

לבסוף, מסירים את השימוש ב-SDK מ-app.yaml (מוחקים את השורה: app_engine_apis: true) ומ-requirements.txt (מוחקים את השורה: appengine-python-standard).

מעבר ל-Cloud Memorystore (ול-Cloud NDB)

מודל הנתונים של Cloud NDB נועד להיות תואם לזה של App Engine ndb, כלומר ההגדרה של אובייקטים מסוג Visit נשארת זהה. בדומה להעברה של מודול 2 אל Cloud NDB, כל הקריאות ל-Datastore ב-store_visit() וב-fetch_visits() מורחבות ומוטמעות בבלוק with חדש (כי נדרש שימוש במנהל ההקשר של Cloud NDB). אלה השיחות לפני השינוי:

לפני:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    return Visit.query().order(-Visit.timestamp).fetch(limit)

מוסיפים בלוק with ds_client.context() לשתי הפונקציות, ומכניסים את הקריאות ל-Datastore לתוך הבלוק (עם הזחה). במקרה כזה, לא צריך לבצע שינויים בקריאות עצמן:

אחרי:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    with ds_client.context():
        return Visit.query().order(-Visit.timestamp).fetch(limit)

בשלב הבא, נבחן את השינויים שקשורים לשמירה במטמון. הנה הפונקציה main() ממודול 12:

לפני:

@app.route('/')
def root():
    'main application (GET) handler'
    # check for (hour-)cached visits
    ip_addr, usr_agt = request.remote_addr, request.user_agent
    visitor = '{}: {}'.format(ip_addr, usr_agt)
    visits = memcache.get('visits')

    # register visit & run DB query if cache empty or new visitor
    if not visits or visits[0].visitor != visitor:
        store_visit(ip_addr, usr_agt)
        visits = list(fetch_visits(10))
        memcache.set('visits', visits, HOUR)  # set() not add()

    return render_template('index.html', visits=visits)

ל-Redis יש קריאות get ו-set, בדיוק כמו ל-Memcache. כל מה שצריך לעשות זה להחליף את ספריות הלקוח המתאימות, נכון? כמעט. כמו שציינו קודם, אי אפשר לשמור במטמון רשימת Python באמצעות Redis (כי צריך קודם לבצע סריאליזציה, וזו פעולה ש-Memcache מבצע אוטומטית). לכן, בקריאה set(), צריך להשתמש ב-pickle.dumps() כדי להמיר את הביקורים למחרוזת באמצעות pickle. באופן דומה, כשמאחזרים ביקורים מהמטמון, צריך לבטל את הפיקול באמצעות pickle.loads() מיד אחרי get(). הנה ה-handler הראשי אחרי הטמעת השינויים האלה:

אחרי:

@app.route('/')
def root():
    'main application (GET) handler'
    # check for (hour-)cached visits
    ip_addr, usr_agt = request.remote_addr, request.user_agent
    visitor = '{}: {}'.format(ip_addr, usr_agt)
    rsp = REDIS.get('visits')
    visits = pickle.loads(rsp) if rsp else None

    # register visit & run DB query if cache empty or new visitor
    if not visits or visits[0].visitor != visitor:
        store_visit(ip_addr, usr_agt)
        visits = list(fetch_visits(10))
        REDIS.set('visits', pickle.dumps(visits), ex=HOUR)

    return render_template('index.html', visits=visits)

בשלב הזה סיימנו את השינויים שנדרשים ב-main.py כדי להמיר את השימוש של אפליקציית הדוגמה ב-Memcache לשימוש ב-Cloud Memorystore. מה לגבי תבנית ה-HTML וההעברה ל-Python 3?

האם לעדכן את קובץ תבנית ה-HTML ולבצע המרה ל-Python 3?

הפתעה! אין צורך לעשות דבר, כי האפליקציה תוכננה לפעול ב-Python 2 וב-Python 3 ללא שינויים בקוד או ספריות תאימות. אפשר לראות את main.py. זהים בתיקיות 'FINISH' בגרסאות mod13a (2.x) ו-mod13b (3.x). הדבר נכון גם לגבי requirements.txt , למעט הבדלים במספרי הגרסאות (אם נעשה בהם שימוש). ממשק המשתמש לא משתנה, ולכן אין עדכונים גם ב-templates/index.html.

כל מה שנדרש להרצת האפליקציה הזו ב-Python 3 App Engine הושלם קודם לכן בהגדרה: הנחיות מיותרות הוסרו מ-app.yaml, ושני הקבצים appengine_config.py והתיקייה lib נמחקו כי הם לא בשימוש ב-Python 3.

7. סיכום/ניקוי

בקטע הזה מסכמים את ה-codelab הזה על ידי פריסת האפליקציה, אימות הפעולה שלה כמצופה ובכל פלט שמשתקף. אחרי אימות האפליקציה, מבצעים ניקוי וחושבים על השלבים הבאים.

פריסה ואימות של האפליקציה

הבדיקה האחרונה היא תמיד פריסת אפליקציית הדוגמה. מפתחים ב-Python 2: צריך למחוק את lib ולהתקין מחדש באמצעות הפקודות שבהמשך. (אם מותקנות במערכת גם Python 2 וגם Python 3, יכול להיות שתצטרכו להריץ במפורש את pip2 במקום זאת).

rm -rf ./lib
pip install -t lib -r requirements.txt

מפתחים של Python 2 ו-Python 3 צריכים עכשיו לפרוס את האפליקציות שלהם באמצעות הפקודה:

gcloud app deploy

מכיוון שרק שיניתם את החיווט מתחת לפני השטח לשירות מטמון שונה לחלוטין, האפליקציה עצמה אמורה לפעול באופן זהה לאפליקציה של מודול 12:

Module 7 visitme app

בשלב הזה מסיימים את ה-codelab. מומלץ להשוות את אפליקציית הדוגמה המעודכנת לאחד משני התיקיות של מודול 13, mod13a (Python 2) או mod13b (Python 3).

הסרת המשאבים

כללי

אם סיימתם לעכשיו, מומלץ להשבית את האפליקציה שלכם ב-App Engine כדי להימנע מחיובים. עם זאת, אם רוצים לבצע עוד בדיקות או ניסויים, בפלטפורמת App Engine יש מכסת שימוש בחינם, ולכן כל עוד לא חורגים מרמת השימוש הזו, לא אמורים לחייב אתכם. החישוב הזה מתייחס ל-Compute, אבל יכול להיות שיהיו גם חיובים על שירותים רלוונטיים של App Engine. לכן, כדאי לעיין בדף התמחור שלו כדי לקבל מידע נוסף. אם ההעברה הזו כוללת שירותי ענן אחרים, הם יחויבו בנפרד. בכל מקרה, אם רלוונטי, כדאי לעיין בקטע 'ספציפי ל-codelab הזה' שבהמשך.

חשוב לדעת: פריסה בפלטפורמת מחשוב ללא שרת של Google Cloud, כמו App Engine, כרוכה בעלויות קלות של בנייה ואחסון. ל-Cloud Build יש מכסת שימוש משלו בחינם, כמו גם ל-Cloud Storage. האחסון של התמונה הזו תופס חלק מהמכסה. עם זאת, יכול להיות שאתם גרים באזור שבו אין תוכנית בחינם כזו, ולכן חשוב לעקוב אחרי השימוש בנפח האחסון הנדרש כדי לצמצם את העלויות הפוטנציאליות. התיקיות הספציפיות ב-Cloud Storage שצריך לבדוק כוללות:

  • console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
  • console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
  • הקישורים לאחסון שלמעלה תלויים בPROJECT_ID ובמיקום *LOC*ation, לדוגמה, us אם האפליקציה מאוחסנת בארה"ב.

מצד שני, אם אתם לא מתכוונים להמשיך עם האפליקציה הזו או עם Codelabs אחרים שקשורים להעברה, ואתם רוצים למחוק הכול באופן סופי, אתם יכולים להשבית את הפרויקט.

ספציפי ל-Codelab הזה

השירותים שמופיעים בהמשך הם ייחודיים ל-codelab הזה. מידע נוסף זמין במסמכי התיעוד של כל מוצר:

  • שירות Cloud Memorystore דורש מכונות ואין לו תוכנית בחינם. למידע נוסף על עלויות השימוש, אפשר לעיין בדף התמחור שלו.
  • מחברי חיבור לרשת (VPC) מאפליקציית serverless ב-Cloud דורשים מופעים ואין להם תוכנית בחינם. כדי לקבל מידע נוסף על עלויות השימוש, אפשר לעיין בקטע בנושא בדף התמחור של Cloud VPC.
  • ל-Cloud Datastore (Cloud Firestore במצב Datastore) יש מסלול בחינם. מידע נוסף זמין בדף התמחור.

במדריך הזה השתמשנו בארבעה מוצרי Cloud:

  • App Engine
  • Cloud Datastore
  • Cloud Memorystore
  • Cloud VPC

בהמשך מוסבר איך לבטל את ההקצאה של המשאבים האלה כדי להימנע מחיובים או לצמצם אותם.

כיבוי של מכונת Memorystore ומחבר VPC

אלה מוצרים ללא תוכנית בחינם, ולכן אתם מחויבים עליהם כבר עכשיו. אם לא משביתים את הפרויקט בענן (ראו את הקטע הבא), צריך למחוק גם את מופע Memorystore וגם את מחבר ה-VPC כדי שהחיוב ייפסק. בדומה ליצירת המשאבים האלה, אפשר גם לשחרר אותם דרך מסוף Cloud או שורת הפקודה.

מתוך מסוף Cloud

כדי למחוק את מכונת Memorystore, חוזרים ללוח הבקרה של Memorystore ולוחצים על מספר המכונה:

2b09baf1aa2e0a25.png

בדף הפרטים של המופע, לוחצים על 'מחיקה' ומאשרים:

f9d9eb1c1d4c6107.png

כדי למחוק את מחבר ה-VPC, עוברים ללוח הבקרה שלו, מסמנים את תיבת הסימון לצד המחבר שרוצים למחוק, לוחצים על 'מחיקה' ומאשרים:

ca5fbd9f4c7c9b60.png

משורת הפקודה

זוג הפקודות הבא של gcloud מוחק את מופע Memorystore ואת מחבר ה-VPC, בהתאמה:

  • gcloud redis instances delete INSTANCE --region REGION
  • gcloud compute networks vpc-access connectors delete CONNECTOR --region REGION

אם לא הגדרתם את מזהה הפרויקט באמצעות gcloud config set project, יכול להיות שתצטרכו לספק את --project PROJECT_ID. אם מופע Memorystore נקרא demo-ms ומחבר ה-VPC נקרא demo-vpc, ושניהם נמצאים באזור us-central1, מריצים את צמד הפקודות הבא ומאשרים:

$ gcloud redis instances delete demo-ms --region us-central1
You are about to delete instance [demo-ms] in [us-central1].
Any associated data will be lost.

Do you want to continue (Y/n)?

Delete request issued for: [demo-ms]
Waiting for operation [projects/PROJECT/locations/REGION/operations/operation-aaaaa-bbbbb-ccccc-ddddd] to complete...done.
Deleted instance [demo-ms].
$
$ gcloud compute networks vpc-access connectors delete demo-vpc --region us-central1
You are about to delete connector [demo-vpc] in [us-central1].
Any associated data will be lost.

Do you want to continue (Y/n)?

Delete request issued for: [demo-vpc]
Waiting for operation [projects/PROJECT/locations/REGION/operations/aaaaa-bbbb-cccc-dddd-eeeee] to complete...done.
Deleted connector [demo-vpc].

כל בקשה נמשכת כמה דקות. השלבים האלה הם אופציונליים אם בחרתם להשבית את כל פרויקט בענן כמו שמתואר קודם, אבל עדיין תחויבו עד שתהליך ההשבתה יושלם.

השלבים הבאים

בנוסף למדריך הזה, יש מודולים אחרים להעברה שמתמקדים במעבר משירותים קודמים בחבילה, שכדאי לעיין בהם:

‫App Engine כבר לא הפלטפורמה היחידה ללא שרת ב-Google Cloud. אם יש לכם אפליקציית App Engine קטנה או אפליקציה עם פונקציונליות מוגבלת ואתם רוצים להפוך אותה למיקרו-שירות עצמאי, או אם אתם רוצים לפצל אפליקציה מונוליטית לכמה רכיבים שאפשר לעשות בהם שימוש חוזר, אלה סיבות טובות לשקול מעבר ל-Cloud Functions. אם יצירת קונטיינרים הפכה לחלק מתהליך העבודה של פיתוח האפליקציה, במיוחד אם היא כוללת צינור CI/CD (אינטגרציה רציפה/פריסה או מסירה רציפה), כדאי לשקול מעבר אל Cloud Run. התרחישים האלה מוסברים במודולים הבאים:

  • מעבר מ-App Engine ל-Cloud Functions: ראו מודול 11
  • מעבר מ-App Engine ל-Cloud Run: אפשר לעיין במודול 4 כדי להעביר את האפליקציה לקונטיינר באמצעות Docker, או במודול 5 כדי לעשות זאת בלי קונטיינרים, בלי ידע ב-Docker או בלי Dockerfiles

המעבר לפלטפורמה אחרת בלי שרת (serverless) הוא אופציונלי, ומומלץ לבדוק מהן האפשרויות הכי טובות לאפליקציות ולתרחישי השימוש שלכם לפני שמבצעים שינויים.

לא משנה איזה מודול העברה תבחרו, תוכלו לגשת לכל התוכן של Serverless Migration Station (סדנאות קוד, סרטונים, קוד מקור [אם זמין]) במאגר הקוד הפתוח שלו. במאגר README יש גם הנחיות לגבי ההעברות שכדאי לבצע וסדר רלוונטי של מודולי ההעברה.

8. מקורות מידע נוספים

בהמשך מופיעים מקורות מידע נוספים למפתחים שרוצים לקבל מידע נוסף על מודול ההעברה הזה או על מודולים קשורים, וגם על מוצרים קשורים. הם כוללים מקומות שבהם אפשר לשלוח משוב על התוכן הזה, קישורים לקוד וקטעי תיעוד שונים שעשויים להיות שימושיים.

בעיות או משוב לגבי Codelabs

אם נתקלתם בבעיות ב-codelab הזה, כדאי לחפש את הבעיה לפני ששולחים דיווח. קישורים לחיפוש וליצירה של בעיות חדשות:

מקורות מידע על העברת נתונים

בטבלה שלמטה אפשר למצוא קישורים לתיקיות של מאגר המידע עבור מודול 12 (התחלה) ומודול 13 (סיום). אפשר גם לגשת אליהם ממאגר המידע של כל ההעברות של Codelabs של App Engine, שאפשר לשכפל או להוריד כקובץ ZIP.

Codelab

Python 2

Python 3

מודול 12

קוד

קוד

יחידת לימוד 13 (ה-Codelab הזה)

קוד

קוד

מקורות אונליין

בהמשך מופיעים מקורות מידע באינטרנט שעשויים להיות רלוונטיים למדריך הזה:

App Engine

‫App Engine NDB ו-Cloud NDB

‫App Engine Memcache ו-Cloud Memorystore

Cloud VPC

מידע אחר על Cloud

רישיון

עבודה זו מורשית תחת רישיון Creative Commons שמותנה בייחוס 2.0 כללי.