1. סקירה כללית
מטרת סדרת ה-codelabs של Serverless Migration Station (הדרכות מעשיות בקצב אישי) והסרטונים שקשורים אליה היא לעזור למפתחים של Google Cloud Serverless לחדש את האפליקציות שלהם. לשם כך, הם מקבלים הדרכה לגבי העברה אחת או יותר, בעיקר מעבר משירותים מדור קודם. כך האפליקציות שלכם יהיו ניידות יותר, ותקבלו יותר אפשרויות וגמישות. תוכלו לשלב את האפליקציות עם מגוון רחב יותר של מוצרי Cloud ולגשת אליהם, ולשדרג בקלות רבה יותר לגרסאות חדשות יותר של השפה. הסדרה הזו מתמקדת בהתחלה במשתמשי הענן הראשונים, בעיקר מפתחים של App Engine (סביבה רגילה), אבל היא רחבה מספיק כדי לכלול פלטפורמות אחרות של Serverless כמו Cloud Functions ו-Cloud Run, או במקומות אחרים אם רלוונטי.
מטרת ה-Codelab הזה היא להראות למפתחי Python 2 App Engine איך להעביר משימות משיכה (pull) מ-App Engine Task Queue אל Cloud Pub/Sub. יש גם העברה מרומזת מ-App Engine NDB אל Cloud NDB לגישה ל-Datastore (הנושא הזה מכוסה בעיקר במודול 2), וגם שדרוג ל-Python 3.
במודול 18 למדתם איך להוסיף לאפליקציה שימוש במשימות pull. במודול הזה תעבירו את השימוש הזה ל-Cloud Pub/Sub באפליקציה המוגמרת של מודול 18. משתמשים בתורי משימות למשימות push יבצעו מיגרציה ל-Cloud Tasks ויעיינו במודולים 7-9 במקום זאת.
כאן אפשר להבין איך
- החלפת השימוש ב-App Engine Task Queue (משימות משיכה) ב-Cloud Pub/Sub
- החלפת השימוש ב-App Engine NDB ב-Cloud NDB (ראו גם מודול 2)
- העברת האפליקציה ל-Python 3
הדרישות
- פרויקט ב-Google Cloud Platform עם חשבון לחיוב פעיל ב-GCP
- מיומנויות בסיסיות ב-Python
- ידע מעשי בפקודות נפוצות של Linux
- ידע בסיסי בפיתוח ופריסה של אפליקציות App Engine
- אפליקציה לדוגמה של App Engine עם מודול 18 שעובד
סקר
איך תשתמשו במדריך הזה?
איך היית מדרג את חוויית השימוש שלך ב-Python?
איזה דירוג מתאים לדעתך לחוויית השימוש שלך בשירותי Google Cloud?
2. רקע
תור המשימות של App Engine תומך במשימות מסוג push ומסוג pull. כדי לשפר את הניידות של האפליקציה, מומלץ ב-Google Cloud לעבור משירותים חבילים מדור קודם, כמו Task Queue, לשירותים עצמאיים אחרים של Cloud או לשירותים מקבילים של צד שלישי.
- משתמשים ב-Task Queue push task צריכים לעבור ל-Cloud Tasks.
- משתמשים ב-Task Queue pull task צריכים לעבור ל-Cloud Pub/Sub.
מודולים 7-9 עוסקים בהעברה של משימות מסוג push, ומודולים 18-19 מתמקדים בהעברה של משימות מסוג pull. Cloud Tasks מתאים יותר למשימות push ב-Task Queue, אבל Pub/Sub לא מתאים למשימות pull ב-Task Queue.
ל-Pub/Sub יש יותר תכונות מאשר לפונקציונליות של משיכת נתונים שזמינה ב-Task Queue. לדוגמה, ל-Pub/Sub יש גם פונקציונליות של push, אבל Cloud Tasks דומה יותר למשימות push של Task Queue, ולכן push של Pub/Sub לא נכלל באף אחד ממודולי ההעברה. ב-Codelab הזה (מודול 19) נדגים איך להחליף את מנגנון התורים מתורי משיכה (pull queue) של Task Queue ל-Pub/Sub, וגם איך לבצע מיגרציה מ-App Engine NDB ל-Cloud NDB כדי לגשת ל-Datastore, תוך חזרה על המיגרציה ממודול 2.
הקוד של מודול 18 מוצג כדוגמה לאפליקציית Python 2, אבל המקור עצמו תואם ל-Python 2 ול-Python 3, והוא נשאר כזה גם אחרי המעבר ל-Cloud Pub/Sub (ול-Cloud NDB) כאן במודול 19.
במדריך הזה נסביר איך:
- הגדרה/עבודה מקדימה
- עדכון ההגדרות
- שינוי קוד האפליקציה
3. הגדרה/עבודה מקדימה
בקטע הזה נסביר איך:
- הגדרת פרויקט בענן
- קבלת אפליקציה לדוגמה של ערך בסיס
- (Re)Deploy and validate baseline app
- הפעלת שירותים או ממשקי API חדשים של Google Cloud
השלבים האלה מבטיחים שתתחילו עם קוד תקין ושהוא יהיה מוכן להעברה לשירותי ענן.
1. הגדרת פרויקט
אם השלמתם את ה-Codelab של מודול 18, תוכלו להשתמש שוב באותו פרויקט (ובאותו קוד). אפשר גם ליצור פרויקט חדש לגמרי או להשתמש מחדש בפרויקט קיים אחר. צריך לוודא שלפרויקט יש חשבון לחיוב פעיל ואפליקציית App Engine מופעלת. כדאי למצוא את מזהה הפרויקט כי תצטרכו אותו במהלך ה-codelab הזה, ותצטרכו להשתמש בו בכל פעם שתיתקלו במשתנה PROJECT_ID.
2. קבלת אפליקציה לדוגמה של ערך בסיס
אחד מהתנאים המוקדמים הוא אפליקציית App Engine פעילה של מודול 18, לכן מומלץ להשלים את ה-codelab (הקישור למעלה) או להעתיק את הקוד של מודול 18 מהמאגר. בין אם אתם משתמשים ב-CMP שלכם או ב-CMP שלנו, כאן נתחיל ("התחלה"). ב-codelab הזה מוסבר איך לבצע את ההעברה, ובסופו מוצג קוד שדומה למה שמופיע בתיקיית המאגר של מודול 19 ("FINISH").
- התחלה: תיקיית מודול 18 (Python 2)
- סיום: תיקיית מודול 19 (Python 2 ו-3)
- מאגר שלם (לשיבוט או להורדה של קובץ ZIP)
לא משנה באיזו אפליקציה של מודול 18 אתם משתמשים, התיקייה צריכה להיראות כמו בדוגמה הבאה, ואולי היא תכלול גם את התיקייה lib:
$ ls README.md appengine_config.py queue.yaml templates app.yaml main.py requirements.txt
3. (Re)Deploy and validate baseline app
כדי לפרוס את האפליקציה Module 18:
- אם יש תיקייה בשם
lib, מוחקים אותה ומריצים את הפקודהpip install -t lib -r requirements.txtכדי לאכלס מחדש אתlib. יכול להיות שתצטרכו להשתמש ב-pip2במקום זאת אם גם Python 2 וגם Python 3 מותקנים במחשב הפיתוח שלכם. - מוודאים שהתקנתם והפעלתם את כלי שורת הפקודה
gcloud, ובדקתם את השימוש בו. - (אופציונלי) מגדירים את פרויקט בענן באמצעות
gcloud config set projectPROJECT_IDאם לא רוצים להזין אתPROJECT_IDבכל פקודתgcloudשמריצים. - פריסת האפליקציה לדוגמה באמצעות
gcloud app deploy - מוודאים שהאפליקציה פועלת כמו שצריך ללא בעיות. אם השלמתם את סדנת ה-codelab בנושא מודול 18, באפליקציה יוצגו המבקרים המובילים יחד עם הביקורים האחרונים (כפי שמוצג בהמשך). אם לא, יכול להיות שלא יהיו נתוני מבקרים להצגה.

לפני שמבצעים העברה של אפליקציית הדוגמה Module 18, צריך קודם להפעיל את שירותי הענן שבהם האפליקציה ששונתה תשתמש.
4. הפעלת שירותים או ממשקי API חדשים של Google Cloud
האפליקציה הישנה השתמשה בשירותים בחבילה של App Engine שלא דורשים הגדרה נוספת, אבל שירותי Cloud עצמאיים כן דורשים הגדרה, והאפליקציה המעודכנת תשתמש גם ב-Cloud Pub/Sub וגם ב-Cloud Datastore (באמצעות ספריית הלקוח Cloud NDB). ל-App Engine ולשני ממשקי ה-API של Cloud יש מכסות של מסלול 'תמיד בחינם', ולכן אם לא תחרגו מהמגבלות האלה, לא תחויבו על השלמת המדריך הזה. אפשר להפעיל את Cloud APIs דרך מסוף Cloud או דרך שורת הפקודה, בהתאם להעדפה שלכם.
מתוך Cloud Console
נכנסים אל דף הספרייה של API Manager (בפרויקט הנכון) ב-Cloud Console, ומחפשים את Cloud Datastore ואת Cloud Pub/Sub APIs באמצעות סרגל החיפוש באמצע הדף:

לוחצים על הלחצן הפעלה לכל API בנפרד. יכול להיות שתתבקשו להזין פרטי חיוב. לדוגמה, זהו הדף Cloud Pub/Sub API Library:

משורת הפקודה
הפעלת ממשקי API דרך המסוף מספקת מידע חזותי, אבל יש אנשים שמעדיפים את שורת הפקודה. מריצים את הפקודה gcloud services enable pubsub.googleapis.com datastore.googleapis.com כדי להפעיל את שני ממשקי ה-API בו-זמנית:
$ gcloud services enable pubsub.googleapis.com datastore.googleapis.com Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.
יכול להיות שתתבקשו להזין פרטי חיוב. אם רוצים להפעיל ממשקי Cloud API אחרים ולדעת מהם מזהי ה-URI שלהם, אפשר למצוא אותם בחלק התחתון של כל דף בספריית ה-API. לדוגמה, אפשר לראות את pubsub.googleapis.com כ'שם השירות' בחלק התחתון של הדף Pub/Sub שמופיע למעלה.
אחרי שתשלימו את השלבים, הפרויקט שלכם יוכל לגשת לממשקי ה-API. עכשיו צריך לעדכן את האפליקציה כדי להשתמש בממשקי ה-API האלה.
4. יצירת משאבי Pub/Sub
סיכום של סדר הפעולות בתהליך העבודה של תור המשימות מתוך מודול 18:
- במודול 18 נעשה שימוש בקובץ
queue.yamlכדי ליצור תור משיכה בשםpullq. - האפליקציה מוסיפה משימות לתור המשימות כדי לעקוב אחרי המבקרים.
- העובד מעבד את המשימות בסופו של דבר, והוא מושכר לפרק זמן מוגבל (שעה).
- המשימות מבוצעות כדי לסכם את מספר המבקרים האחרון.
- המשימות נמחקות מהתור אחרי שהן מסתיימות.
תשכפלו תהליך עבודה דומה באמצעות Pub/Sub. בקטע הבא מוסבר על המינוח הבסיסי של Pub/Sub, ומוצגות שלוש דרכים שונות ליצירת משאבי Pub/Sub שנדרשים.
המינוח של App Engine Task Queue (שליפה) לעומת Cloud Pub/Sub
כדי לעבור ל-Pub/Sub, צריך לבצע שינוי קל במינוח. בהמשך מפורטות הקטגוריות העיקריות יחד עם מונחים רלוונטיים משני המוצרים. מומלץ לעיין גם במדריך להעברת נתונים (מיגרציה), שכולל השוואות דומות.
- מבנה נתונים של תור: ב-Task Queue, הנתונים נכנסים לתורי משימות מסוג pull. ב-Pub/Sub, הנתונים נכנסים לנושאים.
- יחידות של נתונים בתור: משימות משיכה עם Task Queue נקראות הודעות עם Pub/Sub.
- מעבדי נתונים: ב-Task Queue, עובדים מקבלים גישה למשימות מסוג pull. ב-Pub/Sub, צריך מינויים/מנויים כדי לקבל הודעות.
- חילוץ נתונים: שליפת משימת שליפה זהה לשליפת הודעה מנושא (באמצעות מינוי).
- ניקוי או השלמה: מחיקה של משימה בתור משימות בתור משימות מסוג pull אחרי שמסיימים אותה דומה לאישור של הודעת Pub/Sub
למרות שהשינויים במוצרים מתווספים לתור, תהליך העבודה נשאר דומה יחסית:
- במקום תור משיכה (pull queue), האפליקציה משתמשת בנושא בשם
pullq. - במקום להוסיף משימות לתור משיכות, האפליקציה שולחת הודעות לנושא (
pullq). - במקום שעובד ישכור משימות מתור משיכה (pull queue), מנוי בשם
workerשולף הודעות מהנושאpullq. - האפליקציה מעבדת את נתוני ההודעות ומגדילה את מספר המבקרים ב-Datastore.
- במקום למחוק משימות מתור משיכה (pull queue), האפליקציה מאשרת את ההודעות שעברו עיבוד.
ב-Task Queue, ההגדרה כוללת יצירה של תור משימות מסוג pull. ב-Pub/Sub, ההגדרה מחייבת יצירה של נושא ושל מינוי. במודול 18, עיבדנו את queue.yaml מחוץ להרצת האפליקציה. עכשיו צריך לעשות את אותו הדבר עם Pub/Sub.
יש שלוש אפשרויות ליצירת נושאים ומינויים:
- ממסוף Cloud
- משורת הפקודה, או
- מקוד (סקריפט קצר של Python)
בוחרים באחת מהאפשרויות שלמטה ופועלים לפי ההוראות המתאימות כדי ליצור את משאבי ה-Pub/Sub.
ממסוף Cloud
כדי ליצור נושא מ-Cloud Console:
- נכנסים לדף Pub/Sub Topics במסוף Cloud.
- לוחצים על יצירת נושא בחלק העליון. נפתח חלון דו-שיח חדש (ראו תמונה למטה).
- בשדה Topic ID, מזינים
pullq. - מבטלים את הסימון של כל האפשרויות המסומנות ובוחרים באפשרות מפתח הצפנה בניהול Google.
- לוחצים על הלחצן ליצירת נושא.
כך נראית תיבת הדו-שיח ליצירת נושא:

אחרי שיצרתם נושא, צריך ליצור מינוי לנושא הזה:
- נכנסים לדף המינויים של Pub/Sub במסוף Cloud.
- לוחצים על יצירת מינוי בחלק העליון (ראו תמונה למטה).
- בשדה Subscription ID (מזהה המינוי), מזינים את הערך
worker. - בתפריט הנפתח Select a Cloud Pub/Sub topic, בוחרים באפשרות
pullqורושמים את 'שם הנתיב המלא', לדוגמה,projects/PROJECT_ID/topics/pullq - בסוג המסירה, בוחרים באפשרות משיכה.
- משאירים את כל שאר האפשרויות כמו שהן ולוחצים על הלחצן יצירה.
כך נראה מסך יצירת המינוי:

אפשר גם ליצור מינוי מהדף נושאים. הקיצור הזה יכול לעזור לכם לשייך נושאים למינויים. מידע נוסף על יצירת מינויים זמין במסמכי התיעוד.
משורת הפקודה
משתמשי Pub/Sub יכולים ליצור נושאים ומינויים באמצעות הפקודות gcloud pubsub topics create TOPIC_ID ו-gcloud pubsub subscriptions create SUBSCRIPTION_ID --topic=TOPIC_ID, בהתאמה. הפעלת הפקודות האלה עם TOPIC_ID של pullq ו-SUBSCRIPTION_ID של worker מניבה את הפלט הבא עבור הפרויקט PROJECT_ID:
$ gcloud pubsub topics create pullq Created topic [projects/PROJECT_ID/topics/pullq]. $ gcloud pubsub subscriptions create worker --topic=pullq Created subscription [projects/PROJECT_ID/subscriptions/worker].
אפשר גם לעיין בדף הזה במדריך למתחילים. שימוש בשורת הפקודה יכול לפשט תהליכי עבודה שבהם נושאים ומינויים נוצרים באופן קבוע, ואפשר להשתמש בפקודות כאלה בסקריפטים של מעטפת למטרה הזו.
מקוד (סקריפט קצר של Python)
דרך נוספת לאוטומציה של יצירת נושאים ומינויים היא באמצעות Pub/Sub API בקוד המקור. בהמשך מופיע הקוד של maker.py script בתיקיית המאגר Module 19.
from __future__ import print_function
import google.auth
from google.api_core import exceptions
from google.cloud import pubsub
_, PROJECT_ID = google.auth.default()
TOPIC = 'pullq'
SBSCR = 'worker'
ppc_client = pubsub.PublisherClient()
psc_client = pubsub.SubscriberClient()
TOP_PATH = ppc_client.topic_path(PROJECT_ID, TOPIC)
SUB_PATH = psc_client.subscription_path(PROJECT_ID, SBSCR)
def make_top():
try:
top = ppc_client.create_topic(name=TOP_PATH)
print('Created topic %r (%s)' % (TOPIC, top.name))
except exceptions.AlreadyExists:
print('Topic %r already exists at %r' % (TOPIC, TOP_PATH))
def make_sub():
try:
sub = psc_client.create_subscription(name=SUB_PATH, topic=TOP_PATH)
print('Subscription created %r (%s)' % (SBSCR, sub.name))
except exceptions.AlreadyExists:
print('Subscription %r already exists at %r' % (SBSCR, SUB_PATH))
try:
psc_client.close()
except AttributeError: # special Py2 handler for grpcio<1.12.0
pass
make_top()
make_sub()
הפעלת הסקריפט הזה מניבה את הפלט הצפוי (בתנאי שאין שגיאות):
$ python3 maker.py Created topic 'pullq' (projects/PROJECT_ID/topics/pullq) Subscription created 'worker' (projects/PROJECT_ID/subscriptions/worker)
קריאה ל-API כדי ליצור משאבים שכבר קיימים גורמת לחריגה google.api_core.exceptions.AlreadyExists שמוחזרת על ידי ספריית הלקוח, ומטופלת בצורה חלקה על ידי הסקריפט:
$ python3 maker.py Topic 'pullq' already exists at 'projects/PROJECT_ID/topics/pullq' Subscription 'worker' already exists at 'projects/PROJECT_ID/subscriptions/worker'
אם אתם חדשים ב-Pub/Sub, כדאי לקרוא את מאמר המידע על הארכיטקטורה של Pub/Sub.
5. עדכון ההגדרות
העדכונים בהגדרות כוללים שינוי של קובצי הגדרות שונים וגם יצירה של תורים מקבילים של App Engine, אבל בסביבה העסקית של Cloud Pub/Sub.
מחיקת queue.yaml
אנחנו מפסיקים את השימוש ב-Task Queue לחלוטין, לכן צריך למחוק את queue.yaml כי Pub/Sub לא משתמש בקובץ הזה. במקום ליצור תור משיכה, תיצרו נושא (ומינוי) ב-Pub/Sub.
requirements.txt
מוסיפים את google-cloud-ndb ואת google-cloud-pubsub ל-requirements.txt כדי להצטרף ל-flask ממודול 18. יחידת לימוד 19 המעודכנת requirements.txt אמורה להיראות כך:
flask
google-cloud-ndb
google-cloud-pubsub
בקובץ requirements.txt הזה לא מופיעים מספרי גרסאות, ולכן הגרסאות העדכניות ביותר נבחרות. אם מתגלות בעיות תאימות, מומלץ לפעול לפי הנוהל המקובל של שימוש במספרי גרסאות כדי להבטיח שהאפליקציה תפעל בגרסאות מסוימות.
app.yaml
השינויים ב-app.yaml שונים בהתאם להחלטה שלכם אם להישאר עם Python 2 או לשדרג ל-Python 3.
Python 2
העדכון של requirements.txt שמופיע למעלה מוסיף שימוש בספריות הלקוח של Google Cloud. הם דורשים תמיכה נוספת מ-App Engine, כלומר כמה ספריות מובנות, setuptools ו-grpcio. כדי להשתמש בספריות מובנות, צריך להוסיף קטע libraries בקובץ app.yaml ולציין את מספרי הגרסאות של הספריות, או את הערך latest כדי להשתמש בגרסה העדכנית ביותר שזמינה בשרתי App Engine. מודול 18 app.yaml עדיין לא כולל אחד מהקטעים האלה:
לפני:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
מוסיפים libraries section ל-app.yaml יחד עם רשומות ל-setuptools ול-grpcio, ובוחרים את הגרסאות העדכניות שלהם. כדאי גם להוסיף placeholder runtime ל-Python 3, עם הערה שמוציאה אותו משימוש, לצד גרסה עדכנית של 3.x, למשל 3.10, בזמן הכתיבה. בעקבות השינויים האלה, app.yaml נראה עכשיו כך:
אחרי:
#runtime: python310
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: setuptools
version: latest
- name: grpcio
version: latest
Python 3
למשתמשי Python 3 ול-app.yaml, מדובר בהסרת פריטים. בקטע הזה נמחק את הקטע handlers, את ההנחיות threadsafe ו-api_version, ולא ניצור קטע libraries.
סביבות זמן ריצה מהדור השני לא מספקות ספריות מובנות של צד שלישי, ולכן לא צריך להוסיף קטע libraries ב-app.yaml. בנוסף, כבר לא נדרשת העתקה (שנקראת לפעמים vendoring או self-bundling) של חבילות צד שלישי שאינן מוכללות. צריך לציין בסעיף requirements.txt רק ספריות של צד שלישי שהאפליקציה משתמשת בהן.
הקטע handlers בקובץ app.yaml מיועד לציון רכיבי handler של אפליקציות (סקריפטים) וקבצים סטטיים. מכיוון שסביבת זמן הריצה של Python 3 מחייבת מסגרות אינטרנט לבצע ניתוב משלהן, צריך לשנות את כל המטפלים בסקריפטים ל-auto. אם האפליקציה שלכם (כמו באפליקציה של מודול 18) לא מציגה קבצים סטטיים, כל המסלולים יהיו auto, ולכן הם לא יהיו רלוונטיים. לכן גם אין צורך בקטע handlers, אז מוחקים אותו.
בנוסף, ההנחיות threadsafe ו-api_version לא נמצאות בשימוש ב-Python 3, לכן צריך למחוק גם אותן. השורה התחתונה היא שצריך למחוק את כל החלקים של app.yaml כך שתישאר רק ההוראה runtime, שמציינת גרסה עדכנית של Python 3, למשל 3.10. כך נראה app.yaml לפני ואחרי העדכונים האלה:
לפני:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
אחרי:
runtime: python310
למי שלא מוכן למחוק הכול מ-app.yaml for Python 3, סיפקנו קובץ חלופי בתיקיית המאגר של מודול 19.app3.yaml אם אתם רוצים להשתמש בו במקום זאת לפריסות, הקפידו לצרף את שם הקובץ הזה לסוף הפקודה: gcloud app deploy app3.yaml (אחרת, ברירת המחדל תהיה פריסה של האפליקציה עם קובץ Python 2 app.yaml שלא שיניתם).
appengine_config.py
אם משדרגים ל-Python 3, אין צורך ב-appengine_config.py, ולכן אפשר למחוק אותו. הסיבה לכך היא שבתמיכה בספריות של צד שלישי נדרש רק לציין אותן ב-requirements.txt. משתמשי Python 2, כדאי להמשיך לקרוא.
במודול 18 appengine_config.py יש קוד מתאים לתמיכה בספריות של צד שלישי, לדוגמה, Flask וספריות הלקוח של Cloud שנוספו ל-requirements.txt:
לפני:
from google.appengine.ext import vendor
# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
עם זאת, הקוד הזה לבדו לא מספיק כדי לתמוך בספריות המובנות שנוספו (setuptools, grpcio). צריך להוסיף עוד כמה שורות, ולכן צריך לעדכן את appengine_config.py כך שייראה כך:
אחרי:
import pkg_resources
from google.appengine.ext import vendor
# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)
פרטים נוספים על השינויים שנדרשים כדי לתמוך בספריות לקוח של Cloud זמינים במסמכי המיגרציה של שירותים בחבילה.
עדכוני הגדרות אחרים
אם יש לכם תיקייה בשם lib, מחקו אותה. אם אתם משתמשים ב-Python 2, כדי למלא מחדש את התיקייה lib, מריצים את הפקודה הבאה:
pip install -t lib -r requirements.txt # or pip2
אם גם Python 2 וגם Python 3 מותקנים במערכת הפיתוח, יכול להיות שתצטרכו להשתמש בפקודה pip2 במקום בפקודה pip.
6. שינוי קוד האפליקציה
בקטע הזה מוצגים עדכונים לקובץ האפליקציה הראשי, main.py, שבהם השימוש בתורי משימות של App Engine Task Queue מוחלף ב-Cloud Pub/Sub. לא בוצעו שינויים בתבנית האינטרנט, templates/index.html. שתי האפליקציות צריכות לפעול בצורה זהה ולהציג את אותם נתונים.
עדכון ייבוא והפעלה
יש כמה עדכונים לגבי ייבוא והפעלה:
- בייבוא, מחליפים את App Engine NDB ואת Task Queue ב-Cloud NDB וב-Pub/Sub.
- שינוי השם של
pullqמשםQUEUEלשםTOPIC. - במשימות מסוג pull, העובד שכר אותן לשעה, אבל ב-Pub/Sub, פסק הזמן נמדד לפי כל הודעה, ולכן צריך למחוק את הקבוע
HOUR. - כדי להשתמש ב-Cloud APIs, צריך להפעיל לקוח API. לכן, צריך להפעיל לקוחות ל-Cloud NDB ול-Cloud Pub/Sub. האחרון מספק לקוחות גם לנושאים וגם למינויים.
- כדי להשתמש ב-Pub/Sub, צריך את מזהה הפרויקט בענן, לכן צריך לייבא אותו מ-
google.auth.default(). - ב-Pub/Sub נדרשים 'שמות נתיבים מלאים' לנושאים ולמינויים, ולכן צריך ליצור אותם באמצעות
*_path()פונקציות הנוחות.
בהמשך מופיעים הייבוא וההגדרה הראשונית מתוך מודול 18, ואחריהם מוסבר איך הקטעים אמורים להיראות אחרי הטמעת השינויים שלמעלה, כאשר רוב הקוד החדש הוא משאבי Pub/Sub שונים:
לפני:
from flask import Flask, render_template, request
from google.appengine.api import taskqueue
from google.appengine.ext import ndb
HOUR = 3600
LIMIT = 10
TASKS = 1000
QNAME = 'pullq'
QUEUE = taskqueue.Queue(QNAME)
app = Flask(__name__)
אחרי:
from flask import Flask, render_template, request
import google.auth
from google.cloud import ndb, pubsub
LIMIT = 10
TASKS = 1000
TOPIC = 'pullq'
SBSCR = 'worker'
app = Flask(__name__)
ds_client = ndb.Client()
ppc_client = pubsub.PublisherClient()
psc_client = pubsub.SubscriberClient()
_, PROJECT_ID = google.auth.default()
TOP_PATH = ppc_client.topic_path(PROJECT_ID, TOPIC)
SUB_PATH = psc_client.subscription_path(PROJECT_ID, SBSCR)
עדכונים במודל הנתונים
מודל הנתונים של Visit לא משתנה. כדי לגשת ל-Datastore, צריך להשתמש במנהל ההקשר של לקוח Cloud NDB API, ds_client.context(). בקוד, המשמעות היא שצריך לעטוף את הקריאות ל-Datastore גם ב-store_visit() וגם ב-fetch_visits() בתוך בלוקים של Python with. העדכון הזה זהה למה שמוסבר במודול 2.
השינוי הכי רלוונטי ל-Pub/Sub הוא החלפת הוספה לתור של משימת שליפה של Task Queue בפרסום של הודעת Pub/Sub בנושא pullq. בהמשך מופיע הקוד לפני ואחרי ביצוע העדכונים האלה:
לפני:
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
def store_visit(remote_addr, user_agent):
'create new Visit in Datastore and queue request to bump visitor count'
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
QUEUE.add(taskqueue.Task(payload=remote_addr, method='PULL'))
def fetch_visits(limit):
'get most recent visits'
return Visit.query().order(-Visit.timestamp).fetch(limit)
אחרי:
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
def store_visit(remote_addr, user_agent):
'create new Visit in Datastore and queue request to bump visitor count'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
ppc_client.publish(TOP_PATH, remote_addr.encode('utf-8'))
def fetch_visits(limit):
'get most recent visits'
with ds_client.context():
return Visit.query().order(-Visit.timestamp).fetch(limit)
עדכונים במודל הנתונים VisitorCount
מודל הנתונים של VisitorCount לא משתנה וfetch_counts(), למעט עטיפת השאילתה שלו ב-Datastore בתוך בלוק with, כפי שמוצג בהמשך:
לפני:
class VisitorCount(ndb.Model):
visitor = ndb.StringProperty(repeated=False, required=True)
counter = ndb.IntegerProperty()
def fetch_counts(limit):
'get top visitors'
return VisitorCount.query().order(-VisitorCount.counter).fetch(limit)
אחרי:
class VisitorCount(ndb.Model):
visitor = ndb.StringProperty(repeated=False, required=True)
counter = ndb.IntegerProperty()
def fetch_counts(limit):
'get top visitors'
with ds_client.context():
return VisitorCount.query().order(-VisitorCount.counter).fetch(limit)
עדכון קוד העובד
הקוד של העובד מתעדכן כך ש-NDB מוחלף ב-Cloud NDB ו-Task Queue מוחלף ב-Pub/Sub, אבל תהליך העבודה נשאר זהה.
- עוטפים את הקריאות ל-Datastore בבלוק
withשל מנהל ההקשר Cloud NDB. - ניקוי תור המשימות כולל מחיקה של כל המשימות מתור המשימות מסוג pull. ב-Pub/Sub, מזהי אישור נאספים ב-
acksואז נמחקים או מאושרים בסוף. - משימות מסוג pull בתור למשימות מושכרות באופן דומה למשימות מסוג pull ב-Pub/Sub. מחיקה של משימות מסוג pull מתבצעת באמצעות אובייקטים של משימות, אבל מחיקה של הודעות Pub/Sub מתבצעת באמצעות מזהי האישור שלהן.
- מטענים ייעודיים (payloads) של הודעות Pub/Sub דורשים בייטים (לא מחרוזות Python), ולכן יש קידוד ופענוח של UTF-8 כשמפרסמים הודעות בנושא מסוים ומושכים הודעות ממנו, בהתאמה.
מחליפים את log_visitors() בקוד המעודכן שמופיע בהמשך, שמיישם את השינויים שמתוארים למעלה:
לפני:
@app.route('/log')
def log_visitors():
'worker processes recent visitor counts and updates them in Datastore'
# tally recent visitor counts from queue then delete those tasks
tallies = {}
tasks = QUEUE.lease_tasks(HOUR, TASKS)
for task in tasks:
visitor = task.payload
tallies[visitor] = tallies.get(visitor, 0) + 1
if tasks:
QUEUE.delete_tasks(tasks)
# increment those counts in Datastore and return
for visitor in tallies:
counter = VisitorCount.query(VisitorCount.visitor == visitor).get()
if not counter:
counter = VisitorCount(visitor=visitor, counter=0)
counter.put()
counter.counter += tallies[visitor]
counter.put()
return 'DONE (with %d task[s] logging %d visitor[s])\r\n' % (
len(tasks), len(tallies))
אחרי:
@app.route('/log')
def log_visitors():
'worker processes recent visitor counts and updates them in Datastore'
# tally recent visitor counts from queue then delete those tasks
tallies = {}
acks = set()
rsp = psc_client.pull(subscription=SUB_PATH, max_messages=TASKS)
msgs = rsp.received_messages
for rcvd_msg in msgs:
acks.add(rcvd_msg.ack_id)
visitor = rcvd_msg.message.data.decode('utf-8')
tallies[visitor] = tallies.get(visitor, 0) + 1
if acks:
psc_client.acknowledge(subscription=SUB_PATH, ack_ids=acks)
try:
psc_client.close()
except AttributeError: # special handler for grpcio<1.12.0
pass
# increment those counts in Datastore and return
if tallies:
with ds_client.context():
for visitor in tallies:
counter = VisitorCount.query(VisitorCount.visitor == visitor).get()
if not counter:
counter = VisitorCount(visitor=visitor, counter=0)
counter.put()
counter.counter += tallies[visitor]
counter.put()
return 'DONE (with %d task[s] logging %d visitor[s])\r\n' % (
len(msgs), len(tallies))
לא חלים שינויים ב-handler הראשי של האפליקציה root(). גם בקובץ תבנית ה-HTML, templates/index.html, לא נדרשים שינויים, כך שכל העדכונים הדרושים כלולים כאן. הגעתם אל אפליקציית מודול 19 החדשה באמצעות Cloud Pub/Sub.
7. סיכום/ניקוי
כדאי לפרוס את האפליקציה כדי לוודא שהיא פועלת כמצופה ושהיא פועלת בכל פלט שמשתקף. צריך גם להריץ את ה-worker כדי לעבד את נתוני מספר המבקרים. אחרי אימות האפליקציה, מבצעים את שלבי הניקוי ושוקלים את השלבים הבאים.
פריסה ואימות של האפליקציה
מוודאים שכבר יצרתם את הנושא pullq ואת המינוי worker. אם סיימתם את השלב הזה ואפליקציית הדוגמה מוכנה, פורסים את האפליקציה באמצעות gcloud app deploy. הפלט צריך להיות זהה לאפליקציה של מודול 18, מלבד העובדה שהצלחתם להחליף את כל מנגנון התורים הבסיסי:

חלק זה של האפליקציה מאומת עכשיו על ידי ממשק הקצה של האפליקציה באינטרנט. החלק הזה של האפליקציה מבצע שאילתה ומציג את המבקרים המובילים ואת הביקורים האחרונים, אבל צריך לזכור שהאפליקציה רושמת את הביקור הזה וגם יוצרת משיכת נתונים כדי להוסיף את המבקר לספירה הכוללת. המשימה הזו נמצאת עכשיו בתור וממתינה לעיבוד.
אפשר להריץ את הפקודה הזו באמצעות שירות לקצה העורפי של App Engine, עבודת cron, גלישה אל /log או שליחת בקשת HTTP משורת הפקודה. הנה דוגמה להפעלה ופלט של קריאה לקוד של ה-worker עם curl (צריך להחליף את PROJECT_ID):
$ curl https://PROJECT_ID.appspot.com/log DONE (with 1 task[s] logging 1 visitor[s])
המספר המעודכן ישתקף בביקור הבא באתר. זהו!
הסרת המשאבים
כללי
אם סיימתם לעכשיו, מומלץ להשבית את האפליקציה שלכם ב-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/imagesconsole.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com- הקישורים לאחסון שלמעלה תלויים ב
PROJECT_IDובמיקום *LOC*ation, לדוגמה,usאם האפליקציה מאוחסנת בארה"ב.
מצד שני, אם אתם לא מתכוונים להמשיך עם האפליקציה הזו או עם Codelabs אחרים שקשורים להעברה, ואתם רוצים למחוק הכול באופן סופי, אתם יכולים להשבית את הפרויקט.
ספציפי ל-Codelab הזה
השירותים שמופיעים בהמשך הם ייחודיים ל-codelab הזה. מידע נוסף זמין במסמכי התיעוד של כל מוצר:
- לרכיבים שונים של Cloud Pub/Sub יש תוכנית בחינם. כדי לקבל מושג טוב יותר לגבי ההשלכות על העלויות, כדאי לבדוק את דף התמחור.
- שירות App Engine Datastore מסופק על ידי Cloud Datastore (Cloud Firestore במצב Datastore), שגם לו יש רמת שירות בחינם. מידע נוסף זמין במחירון שלו.
השלבים הבאים
בנוסף למדריך הזה, יש מודולים אחרים להעברה שמתמקדים במעבר משירותים קודמים בחבילה, שכדאי לעיין בהם:
- מודול 2: מעבר מ-App Engine
ndbאל Cloud NDB - יחידות 7-9: מעבר מ-App Engine Task Queue (משימות push) ל-Cloud Tasks
- מודולים 12-13: מעבר מ-App Engine Memcache ל-Cloud Memorystore
- מודולים 15-16: מעבר מ-App Engine Blobstore ל-Cloud Storage
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 הזה, כדאי לחפש את הבעיה לפני ששולחים דיווח. קישורים לחיפוש וליצירה של בעיות חדשות:
מקורות מידע על העברת נתונים
בטבלה שלמטה מופיעים קישורים לתיקיות של מאגר המידע של מודול 18 (התחלה) ומודול 19 (סיום).
Codelab | Python 2 | Python 3 |
(n/a) | ||
מודול 19 (ה-Codelab הזה) | (זהה ל-Python 2, אלא אם מעדכנים את app.yaml כמו שמתואר למעלה, ואז משתמשים ב-app3.yaml) |
מקורות אונליין
בהמשך מופיעים מקורות מידע שרלוונטיים למדריך הזה:
תור משימות ב-App Engine
- סקירה כללית בנושא תור המשימות של App Engine
- סקירה כללית על תורי משימות מסוג pull ב-App Engine
- אפליקציה לדוגמה מלאה של תור משימות מסוג pull ב-App Engine
- יצירת תורי משימות מסוג pull
- סרטון השקת תור המשימות של Google I/O 2011 ( אפליקציית הדוגמה Votelator)
queue.yamlמידע נוסף-
queue.yamlלעומת Cloud Tasks - מדריך להעברת נתונים (מיגרציה) מתורי המתנה (pull queues) אל Pub/Sub
Cloud Pub/Sub
- דף המוצר של Cloud Pub/Sub
- שימוש בספריות לקוח של Pub/Sub
- דוגמאות של ספריות לקוח ב-Python ל-Pub/Sub
- מאמרי עזרה בנושא ספריית הלקוח של Python ב-Pub/Sub
- יצירה וניהול של נושאים ב-Pub/Sub
- הנחיות למתן שמות לנושאים ב-Pub/Sub
- יצירה וניהול של מינויים ל-Pub/Sub
- אפליקציה לדוגמה של App Engine (גמיש) (אפשר לפרוס גם בסביבה רגילה; Python 3)
- מאגר לאפליקציה לדוגמה שמופיעה למעלה
- הרשמות לשליפת הודעות ב-Pub/Sub
- הרשמות לדחיפה ב-Pub/Sub
- אפליקציה לדוגמה של App Engine Pub/Sub push (Python 3)
- מאגר אפליקציות לדוגמה של App Engine Pub/Sub push
- מידע על התמחור של Pub/Sub
- Cloud Tasks או Cloud Pub/Sub? (דחיפה לעומת משיכה)
App Engine NDB ו-Cloud NDB (Datastore)
- מסמכי NDB של App Engine
- מאגר App Engine NDB
- מסמכי התיעוד של Google Cloud NDB
- מאגר Google Cloud NDB
- מידע על התמחור של Cloud Datastore
פלטפורמת App Engine
- מסמכי App Engine
- זמן ריצה של Python 2 App Engine (סביבה סטנדרטית)
- שימוש בספריות מובנות של App Engine ב-Python 2 App Engine
- זמן ריצה של Python 3 App Engine (סביבה רגילה)
- ההבדלים בין סביבות זמן הריצה של Python 2 ו-Python 3 App Engine (סביבה סטנדרטית)
- מדריך להעברה מ-Python 2 ל-Python 3 ב-App Engine (סביבה רגילה)
- מידע על התמחור ועל המכסות ב-App Engine
- השקת פלטפורמת App Engine מהדור השני (2018)
- השוואה בין פלטפורמות מהדור הראשון לבין פלטפורמות מהדור השני
- תמיכה לטווח ארוך בסביבות זמן ריצה מדור קודם
- דוגמאות להעברת נתונים של מסמכים
- דוגמאות למיגרציה שנוצרו על ידי הקהילה
מידע אחר על Cloud
- Python ב-Google Cloud Platform
- ספריות לקוח Python של Google Cloud
- רמת השימוש 'תמיד בחינם' ב-Google Cloud
- Google Cloud SDK (כלי לשורת פקודה
gcloud) - כל מסמכי התיעוד של Google Cloud
סרטונים
- Serverless Migration Station
- מסעות ללא שרת
- הרשמה למינוי לערוץ Google Cloud Tech
- הרשמה לניוזלטר של Google Developers
רישיון
עבודה זו מורשית תחת רישיון Creative Commons שמותנה בייחוס 2.0 כללי.