1. סקירה כללית
סדרת הServerless Migration Station של Codelabs (מדריכים מעשיים בקצב עצמי) וסרטונים קשורים נועדו לעזור להעביר מפתחים ללא שרת (serverless) של Google Cloud, באמצעות העברת אפליקציות מדור קודם באמצעות שירותי Google Cloud. כך האפליקציות שלכם יהיו יותר ניידות ויהיו לכם יותר אפשרויות וגמישות, כך שתוכלו להשתלב עם מגוון רחב יותר של מוצרי Cloud ולגשת אליהם בקלות, ולהשדרג בקלות רבה יותר לגרסאות חדשות יותר של שפות. הסדרה מתמקדת בהתחלה במשתמשי Cloud הראשונים, ובעיקר מפתחי App Engine (בסביבה סטנדרטית), אבל היא רחבה מספיק כדי לכלול פלטפורמות אחרות ללא שרת (serverless), כמו Cloud Functions ו-Cloud Run, או במקומות אחרים, אם רלוונטי.
המטרה של ה-Codelab הזו היא להראות למפתחי App Engine ב-Python 2 איך לעבור ממשימות המשיכה ממשימות המשיכה ב-App Engine אל Cloud Pub/Sub. יש גם העברה משתמעת מ-App Engine NDB ל-Cloud NDB בשביל גישה ל-Datastore (מתייחסת בעיקר למודול 2), וגם שדרוג ל-Python 3.
במודול 18 מוסבר איך להוסיף את השימוש במשימות משיכה לאפליקציה. במודול הזה תועברו את אפליקציית מודול 18 המוגמרת ותעבירו את השימוש אל Cloud Pub/Sub. משתמשים שמשתמשים בתכונה 'תורי משימות' למשימות push יועברו במקום זאת ל-Cloud Tasks, ויפנו למודולים 7-9 במקום זאת.
כאן אפשר להבין איך
- החלפת השימוש בתור המשימות של App Engine (משימות משיכה) ב-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 תומך גם במשימות דחיפה וגם במשימות משיכה. כדי לשפר את ניידות האפליקציות, אנחנו ממליצים לעבור משירותים בחבילה מדור קודם, כמו 'תור המשימות', לשירותים עצמאיים אחרים ב-Cloud או לשירותים מקבילים של צד שלישי.
- משתמשים במשימה ב-push שבתור המשימות צריכים לעבור אל Cloud Tasks.
- משתמשים במשימת משיכה בתור משימות צריכים לעבור אל Cloud Pub/Sub.
במודולי העברה 7-9 מוסבר על העברת משימות דחיפה, ואילו מודולים 18-19 מתמקדים בהעברה של משימות משיכה. Cloud Tasks תואם יותר משימות לדחיפה בתור המשימה, אבל Pub/Sub דומה יותר לביצועים אנלוגיים למשימות המשיכה בתור המשימה.
ב-Pub/Sub יש יותר תכונות בהשוואה לפונקציית המשיכה שמסופקת על ידי 'תור המשימות'. לדוגמה, ב-Pub/Sub יש גם פונקציונליות של push, אבל משימות ב-Cloud Tasks דומות יותר למשימות דחיפה בתור המשימה, כך שמודולי ההעברה לא נכללים בדחיפה של Pub/Sub. שיעור ה-Codelab של מודול 19 הזה מדגים שינוי של מנגנון ההוספה לתורים מתורי המשיכה בתור המשימה ל-Pub/Sub, וגם העברה של App Engine NDB ל-Cloud NDB לצורך גישה ל-Datastore, חזרה על ההעברה של מודול 2.
למרות שקוד מודול 18 'מפורסם' בתור אפליקציה לדוגמה של Python 2, המקור עצמו תואם ל-Python 2 ו-3, והוא נשאר בצורה הזו גם אחרי המעבר ל-Cloud Pub/Sub (ול-Cloud NDB) במודול 19.
המדריך הזה כולל את השלבים הבאים:
- הגדרה/עבודה מוקדמת
- עדכון ההגדרות האישיות
- שינוי קוד האפליקציה
3. הגדרה/עבודה מוקדמת
בקטע הזה נסביר איך:
- הגדרת פרויקט ב-Cloud
- אחזור של אפליקציה בסיסית לדוגמה
- (מחדש) פריסה ואימות של אפליקציה בסיסית
- הפעלת שירותים/ממשקי API חדשים של Google Cloud
השלבים האלה נועדו לוודא שאתם מתחילים לעבוד עם קוד ושהוא מוכן להעברה לשירותי Cloud.
1. הגדרת הפרויקט
אם השלמתם את Module 18 Codelab, צריך להשתמש שוב באותו פרויקט (ובקוד). לחלופין, אפשר ליצור פרויקט חדש לגמרי או להשתמש שוב בפרויקט קיים אחר. צריך לוודא שלפרויקט יש חשבון פעיל לחיוב ואפליקציית App Engine מופעלת. אתם יכולים למצוא את מזהה הפרויקט שלכם למקרה הצורך במהלך ה-Codelab הזה, ולהשתמש בו בכל פעם שאתם נתקלים במשתנה PROJECT_ID
.
2. אחזור של אפליקציה בסיסית לדוגמה
אחת מהדרישות המוקדמות היא אפליקציית App Engine פעילה של מודול 18. לכן, משלימים את Codelab (מומלץ; קישור למעלה) או מעתיקים את קוד המודול 18 מהמאגר. כאן נתחיל ("התחלה"). בין אם תשתמש במודעות שלך או בשלנו, כאן נתחיל. ה-Codelab הזה ינחה אותך לאורך ההעברה, ויסתיים בקוד שדומה למה שמופיע בתיקיית המאגר של מודול 19 (FINISH).
- START: תיקיית מודול 18 (Python 2)
- FINISH: תיקיית מודול 19 (Python בגרסה 2 ו-3)
- כל המאגר (לשכפול או הורדה של קובץ ZIP)
בלי קשר לאפליקציית מודול 18 שבה משתמשים, התיקייה צריכה להיראות כמו בדוגמה הבאה, אולי גם עם תיקיית lib
:
$ ls README.md appengine_config.py queue.yaml templates app.yaml main.py requirements.txt
3. (מחדש) פריסה ואימות של אפליקציה בסיסית
מבצעים את השלבים הבאים כדי לפרוס את אפליקציית מודול 18:
- אם קיימת תיקייה כזו, מוחקים את התיקייה
lib
ומריצים את הפקודהpip install -t lib -r requirements.txt
כדי לאכלס מחדש אתlib
. יכול להיות שתצטרכו להשתמש ב-pip2
במקום זאת, אם במחשב הפיתוח שלכם מותקנות גם Python 2 וגם גרסה 3. - חשוב לוודא שהתקנתם ואתחלתם את כלי שורת הפקודה
gcloud
, ושבדקתם את השימוש בו. - (אופציונלי) אם לא רוצים להזין את ה-
PROJECT_ID
עם כל פקודתgcloud
שיוצרים, מגדירים את הפרויקט ב-Cloud לערךgcloud config set project
PROJECT_ID
. - פריסת האפליקציה לדוגמה באמצעות
gcloud app deploy
- מוודאים שהאפליקציה פועלת כמצופה ללא בעיות. אם השלמתם את ה-Codelab של מודול 18, האפליקציה מציגה את המבקרים המובילים יחד עם הביקורים האחרונים (איור בהמשך). אם לא, ייתכן שלא יוצגו ספירות של מבקרים.
לפני שמעבירים את האפליקציה לדוגמה של מודול 18, צריך להפעיל קודם את שירותי הענן שהאפליקציה ששונתה תשתמש בהם.
4. הפעלת שירותים/ממשקי API חדשים של Google Cloud
באפליקציה הישנה נעשה שימוש בשירותים בחבילה של App Engine שלא מחייבים הגדרה נוספת, אבל שירותי Cloud עצמאיים כן, ובאפליקציה המעודכנת ייעשה שימוש גם ב-Cloud Pub/Sub וגם ב-Cloud Datastore (דרך ספריית הלקוח של Cloud NDB). App Engine ושני ממשקי ה-API של Cloud יכולים להיות "חינם תמיד" רמה, וכל עוד לא חורגים מהמגבלות האלה, לא תצברו חיובים על השלמת המדריך הזה. את ממשקי Cloud API אפשר להפעיל מ-Cloud Console או משורת הפקודה, בהתאם להעדפות שלכם.
ממסוף Cloud
נכנסים לדף הספרייה של API Manager (לפרויקט הנכון) במסוף Cloud ומחפשים את ממשקי Cloud Datastore ואת Cloud Pub/Sub API באמצעות סרגל החיפוש שבמרכז הדף:
לוחצים על הלחצן הפעלה לכל API בנפרד — ייתכן שתתבקשו להזין נתוני חיוב. לדוגמה, זה הדף של ספריית Cloud Pub/Sub API:
משורת הפקודה
הפעלת ממשקי 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 שלהם, תוכלו למצוא את מזהי ה-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' (משיכה) לעומת המונחים של Cloud Pub/Sub
כדי לעבור ל-Pub/Sub נדרשת התאמה קלה באוצר המילים. בהמשך מפורטות הקטגוריות הראשיות וגם המונחים הרלוונטיים משני המוצרים. מומלץ לעיין גם במדריך להעברת נתונים (מיגרציה) שכולל השוואות דומות.
- הוספת מבנה נתונים לרשימת הבאים בתור: באמצעות 'תור המשימות', הנתונים עוברים לתורי משיכה; עם Pub/Sub, הנתונים עוברים לנושאים.
- יחידות של נתונים בתור: משימות שליפת עם 'תור המשימות' נקראות הודעות ב-Pub/Sub.
- מעבדי נתונים: באמצעות 'תור המשימות', עובדים ניגשים למשימות משיכה; עם Pub/Sub, נדרשים מינויים/מנויים כדי לקבל הודעות
- חילוץ נתונים: ליסינג של משימת משיכה זהה לשליפת הודעה מנושא (באמצעות מינוי).
- ניקוי/השלמה: מחיקה של משימת 'הבאים בתור' מתור השליפה בסיום הפעולה מקבילה לאישור של הודעת Pub/Sub
למרות שהוספת המוצר לתור משתנה, תהליך העבודה נשאר דומה יחסית:
- במקום תור משיכה, האפליקציה משתמשת בנושא בשם
pullq
. - במקום להוסיף משימות לתור למשיכה, האפליקציה שולחת הודעות לנושא (
pullq
). - במקום עובד שמשכיר משימות מתור המשיכה, מנוי בשם
worker
שולף הודעות מהנושאpullq
. - האפליקציה מעבדת מטענים ייעודיים של הודעות, וכך מגדילה את מספר המבקרים ב-Datastore.
- במקום למחוק משימות מתור המשיכה, האפליקציה מאשרת את ההודעות שעברו עיבוד.
באמצעות 'תור המשימות', ההגדרה כוללת יצירת תור המשיכה. כדי להגדיר נושא ב-Pub/Sub, צריך ליצור גם נושא וגם מינוי. במודול 18, עיבדנו queue.yaml
מחוץ להפעלת האפליקציה; עכשיו צריך לעשות את אותו הדבר גם ב-Pub/Sub.
יש שלוש אפשרויות ליצירת נושאים ומינויים:
- ממסוף Cloud
- משורת הפקודה, או
- מקוד (סקריפט Python קצר)
כדי ליצור משאבי Pub/Sub, בוחרים באחת מהאפשרויות הבאות ופועלים לפי ההוראות המתאימות.
ממסוף Cloud
כדי ליצור נושא מ-Cloud Console:
- נכנסים למסוף Cloud לדף Pub/Sub Topics.
- לוחצים על יצירת נושא בחלק העליון של הדף. ייפתח חלון חדש של תיבת דו-שיח (ראו תמונה למטה)
- בשדה Topics ID (מזהה הנושא), מזינים את הערך
pullq
. - מבטלים את הבחירה בכל האפשרויות המסומנות ובוחרים באפשרות מפתח הצפנה בניהול Google.
- לוחצים על הלחצן יצירת נושא.
כך נראית תיבת הדו-שיח ליצירת נושא:
עכשיו, אחרי שיוצרים נושא, צריך ליצור מינוי אליו:
- נכנסים למסוף Cloud לדף 'מינויים ב-Pub/Sub'.
- לוחצים על יצירת מינוי בחלק העליון (ראו תמונה בהמשך).
- מזינים את הערך
worker
בשדה מזהה מינוי. - בוחרים את הערך
pullq
מתוך התפריט הנפתח Select a Cloud Pub/Sub topic, ומציינים את שם הנתיב שמוגדר במלואו. לדוגמה,projects/PROJECT_ID/topics/pullq
- בשדה סוג העברה, בוחרים באפשרות Pull.
- משאירים את כל שאר האפשרויות כפי שהן ולוחצים על הלחצן יצירה.
כך נראה מסך יצירת המינוי:
אפשר גם ליצור מינוי מהדף נושאים – קיצור הדרך הזה יכול לעזור בשיוך נושאים למינויים. למידע נוסף על יצירת מינויים, אפשר לעיין במסמכי התיעוד.
משורת הפקודה
משתמשי 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
בתיקיית המאגר של מודול 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.
מחיקת התור.yaml
אנחנו עוברים משימוש לחלוטין את 'תור המשימות', לכן צריך למחוק את 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
ובמספרי הגרסה של הספרייה, או בקטע 'העדכנית ביותר'. את העדכונים האחרונים שזמינים בשרתי App Engine. במודול 18 app.yaml
עדיין אין אחד מהקטעים האלה:
לפני:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
הוספת קטע libraries
ל-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
. בנוסף, אין יותר צורך להעתיק (שלפעמים נקרא ספק או קיבוץ עצמי) חבילות של צד שלישי שאינן מובנות. צריך לציין רק ספריות של צד שלישי שהאפליקציה משתמשת בהן ב-requirements.txt
.
הקטע handlers
ב-app.yaml
מיועד לציון רכיבי handler של קבצים סטטיים ושל אפליקציות (סקריפט). סביבת זמן הריצה של Python 3 מחייבת שמסגרות אינטרנט (frameworks) יבצעו ניתוב משלהן, לכן צריך לשנות את כל הגורמים המטפלים בסקריפטים ל-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
עבור Python 3, סיפקנו קובץ חלופי app3.yaml
בתיקיית המאגר של מודול 19. כדי להשתמש בו לפריסות, חשוב לצרף את שם הקובץ הזה לסוף הפקודה: 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 וגם 3, יכול להיות שאתם צריכים להשתמש ב-pip2
במקום ב-pip
.
6. שינוי קוד האפליקציה
הקטע הזה כולל עדכונים לקובץ הראשי של האפליקציה, main.py
, שמחליף את השימוש בתורי המשיכה בתור המשימות של App Engine ב-Cloud Pub/Sub. אין שינויים בתבנית האינטרנט, templates/index.html
. שתי האפליקציות צריכות לפעול באופן זהה ולהציג את אותם הנתונים.
ייבוא ואתחול של עדכונים
יש מספר עדכונים לייבוא ולאתחול:
- לצורך הייבוא, צריך להחליף את App Engine NDB ואת 'הבאים בתור' ב-Cloud NDB ו-Pub/Sub.
- שינוי השם של
pullq
מהשם שלQUEUE
לשם שלTOPIC
. - במשימות משיכה, העובד השכיר אותן למשך שעה, אבל ב-Pub/Sub, הזמן הקצוב לתפוגה נמדד לפי כל הודעה, לכן מוחקים את הקבוע
HOUR
. - ממשקי Cloud API מחייבים שימוש בלקוח API, לכן צריך ליזום אותם עבור Cloud NDB ו-Cloud Pub/Sub, וכך לספק לקוחות גם לנושאים וגם למינויים.
- ל-Pub/Sub נדרש מזהה הפרויקט ב-Cloud, לכן צריך לייבא ולקבל אותו מ-
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
לא משתנה. כדי לגשת למאגר הנתונים, צריך להשתמש באופן מפורש במנהל ההקשר של הלקוח ב-Cloud NDB API, ds_client.context()
. בקוד, המשמעות היא ששיחות Datastore ב-store_visit()
וב-fetch_visits()
צריכות להיות בתוך בלוקים with
של Python. העדכון הזה זהה למידע במודול 2.
השינוי הרלוונטי ביותר ב-Pub/Sub הוא החלפת משימת השליפה בתור 'הבאים בתור המשימות' בפרסום של הודעת 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 ואת 'תור המשימות' ב-Pub/Sub, אבל תהליך העבודה שלו לא משתנה.
- העברת קריאות ל-Datastore בבלוק
with
של המרכז לניהול ההקשר של Cloud NDB. - ניקוי תור המשימות כולל מחיקת כל המשימות מתור המשיכה. עם Pub/Sub, 'מזהי אישור' נאספים ב-
acks
ואז נמחקים או מקבלים אישור בסוף. - משימות משיכה דרך 'הבאים בתור' חתוכות באותו אופן שבו נשלפות הודעות Pub/Sub. בזמן המחיקה של משימות המשיכה עם האובייקטים של המשימה עצמם, הודעות 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
, אין צורך לבצע שינויים, לכן התהליך הזה כולל את כל העדכונים הנחוצים. מזל טוב, הגעת לאפליקציית Module 19 החדשה באמצעות Cloud Pub/Sub.
7. סיכום/ניקוי
פורסים את האפליקציה כדי לוודא שהיא פועלת כמצופה ובכל פלט משתקף. בנוסף, מריצים את ה-worker כדי לעבד את ספירת המבקרים. אחרי אימות האפליקציה, מומלץ לבצע את שלבי ניקוי האפליקציה ולשקול את השלבים הבאים.
פריסה ואימות של אפליקציה
חשוב לוודא שכבר יצרת את הנושא pullq
ואת המינוי worker
. אם סיימת את התהליך והאפליקציה לדוגמה מוכנה להפעלה, יש לפרוס את האפליקציה באמצעות gcloud app deploy
. הפלט אמור להיות זהה לאפליקציית מודול 18, אלא שהחלפתם בהצלחה את כל המנגנון הבסיסי להוספה לתור:
ממשק האינטרנט של האפליקציה מאמת עכשיו שהחלק הזה של האפליקציה פועל. אמנם החלק הזה של האפליקציה שולח בהצלחה שאילתות לגבי המבקרים המובילים והביקורים האחרונים, אך מציג אותם בפני המבקרים המובילים והביקורים האחרונים, אבל האפליקציה רושמת את הביקור הזה יחד עם יצירת משימת משיכה כדי להוסיף את המבקר הזה לספירה הכוללת. המשימה נמצאת עכשיו בתור וממתינה לעיבוד.
ניתן לבצע זאת באמצעות שירות לקצה העורפי של App Engine, משימת cron
, גלישה אל /log
או הנפקת בקשת HTTP בשורת הפקודה. הנה דוגמה אחת להפעלה ולביטול קריאה לקוד העובד באמצעות curl
(מחליפים את PROJECT_ID
):
$ curl https://PROJECT_ID.appspot.com/log DONE (with 1 task[s] logging 1 visitor[s])
לאחר מכן, הספירה המעודכנת תופיע בביקור הבא באתר. זהו!
הסרת המשאבים
כללי
אם סיימתם בינתיים, מומלץ להשבית את אפליקציית App Engine כדי להימנע מצבירת חיובים. עם זאת, אם אתם רוצים להתנסות בפיצ'רים נוספים או להתנסות בהם, בפלטפורמת App Engine יש מכסה בחינם, וכל עוד אתם לא חורגים ממכסת השימוש הזו, לא נחייב אתכם. הבקשה נועדה למחשוב, אבל ייתכן שיחולו חיובים גם על שירותים רלוונטיים של App Engine. למידע נוסף, יש לעיין בדף התמחור של האפליקציה. אם ההעברה הזו כוללת שירותי ענן אחרים, הם מחויבים בנפרד. בכל מקרה, אם רלוונטי, ראו "ספציפי ל-Codelab זה" שבהמשך.
גילוי נאות מלא, פריסה בפלטפורמת מחשוב ללא שרת (serverless) של Google Cloud, כמו App Engine, כרוכה בעלויות נמוכות של build ואחסון. ל-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
*שלך, לדוגמה, "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 (משימות ב-push) ל-Cloud Tasks
- מודולים 12-13: העברה מ-Memcache של App Engine ל-Cloud Memorystore
- מודולים 15-16: העברה מ-App Engine Blobstore ל-Cloud Storage
App Engine היא כבר לא הפלטפורמה היחידה ללא שרת (serverless) ב-Google Cloud. אם יש לכם אפליקציה קטנה של App Engine או אפליקציה שיש לה פונקציונליות מוגבלת ואתם רוצים להפוך אותה למיקרו-שירות (microservice) עצמאי, או שאתם רוצים לפצל אפליקציה מונוליתית למספר רכיבים לשימוש חוזר, כדאי לשקול לעבור ל-Cloud Functions. אם יצירת קונטיינרים הפכה לחלק מתהליך פיתוח האפליקציות שלכם, במיוחד אם היא מורכבת מצינור עיבוד נתונים של CI/CD (אינטגרציה רציפה (CI/CD)/פיתוח רציף (continuous delivery) או פריסה), מומלץ לעבור ל-Cloud Run. התרחישים האלה מתוארים במודולים הבאים:
- מעבר מ-App Engine ל-Cloud Functions: ראו מודול 11
- מעבר מ-App Engine ל-Cloud Run: אפשר לעיין במודול 4 ליצירת קונטיינרים לאפליקציה באמצעות Docker, או במודול 5 כדי לבצע אותו ללא קונטיינרים, ידע ב-Docker או
Dockerfile
המעבר לפלטפורמה אחרת ללא שרת הוא אופציונלי, ומומלץ לבדוק את האפשרויות הטובות ביותר לאפליקציות ולתרחישים לדוגמה לפני שמבצעים שינויים.
בלי קשר למודול ההעברה הרצוי, כל התוכן של תחנת המיגרציה ללא שרת (serverless) (codelabs, סרטונים, קוד מקור [אם הוא זמין]) יהיה זמין במאגר הקוד הפתוח שלו. README
של המאגר גם מספק הדרכה לגבי ההעברות שכדאי לשקול ו"הזמנה" רלוונטית של מודולי העברה.
8. מקורות מידע נוספים
בהמשך מפורטים מקורות מידע נוספים למפתחים שבודקים את מודול ההעברה הזה או מוצרים קשורים, וגם מוצרים קשורים. זה כולל מקומות שבהם אפשר לספק משוב על התוכן הזה, קישורים לקוד וקטעי תיעוד שונים שעשויים להועיל.
בעיות/משוב על Codelabs
אם נתקלתם בבעיות ב-Codelab הזה, צריך קודם לחפש את הבעיה לפני השליחה. קישורים לחיפוש וליצירת בעיות חדשות:
משאבים להעברה
בטבלה שלמטה מופיעים הקישורים לתיקיות המאגר של מודול 18 (START) ומודול 19 (FINISH).
Codelab | ֶPython 2 | ֶPython 3 |
(לא רלוונטי) | ||
יחידת לימוד 19 (Codelab זה) | (כמו ב-Python 2, למעט השתמשו ב-app3.yaml, אלא אם עדכנתם את app.yaml כפי שמתואר למעלה) |
הפניות אונליין
בהמשך מוצגים מקורות מידע שרלוונטיים למדריך הזה:
תור המשימות של App Engine
- סקירה כללית בנושא 'תור המשימות של App Engine'
- סקירה כללית על תורי המשימות של App Engine
- אפליקציה לדוגמה מלאה של תור המשימות של App Engine
- יצירת תורי משיכה בתור המשימות
- סרטון השקה של Google I/O 2011 pullQueue ( אפליקציות לדוגמה של Voicelator)
- קובץ עזר של
queue.yaml
queue.yaml
לעומת Cloud Tasks- שליפת תורי דואר למדריך להעברת נתונים (מיגרציה) ל-Pub/Sub
Cloud Pub/Sub
- דף המוצר של Cloud Pub/Sub
- שימוש בספריות לקוח של Pub/Sub
- דוגמאות של ספריות לקוח ב-Pub/Sub Python
- מסמכי תיעוד של ספריית הלקוח של Pub/Sub Python
- יצירה ניהול נושאי Pub/Sub
- הנחיות למתן שמות לנושאי Pub/Sub
- יצירה ניהול מינויים ב-Pub/Sub
- אפליקציה לדוגמה של App Engine (גמישה) (אפשר לפרוס גם בגרסה הרגילה, Python 3)
- מאגר של אפליקציה לדוגמה למעלה
- שליפת מינויים ב-Pub/Sub
- מינויים ב-Pub/Sub ל-Push
- אפליקציה לדוגמה של App Engine Pub/Sub לדחיפה (Python 3)
- מאגר אפליקציות לדוגמה ב-Pub/Sub ב-App Engine
- פרטי תמחור ב-Pub/Sub
- Cloud Tasks או Cloud Pub/Sub? (דחיפה לעומת משיכה)
App Engine NDB ו-Cloud NDB (Datastore)
- מסמכי NDB של App Engine
- מאגר NDB של App Engine
- מסמכי NDB של Google Cloud
- מאגר NDB ב-Google Cloud
- מידע על התמחור של Cloud Datastore
פלטפורמת App Engine
- מסמכי התיעוד של App Engine
- זמן ריצה של Python 2 App Engine (סביבה סטנדרטית)
- שימוש בספריות מובנות של App Engine ב-App Engine Python 2
- זמן ריצה של Python 3 App Engine (סביבה סטנדרטית)
- ההבדלים בין Python 2 לבין Python 3 זמני ריצה של App Engine (סביבה רגילה)
- מדריך להעברת אפליקציות מ-Python 2-3 App Engine (סביבה סטנדרטית)
- מידע על תמחור ומכסות של App Engine
- השקת פלטפורמת App Engine מדור שני (2018)
- השוואה ראשונה ל- פלטפורמות דור שני
- תמיכה לטווח ארוך בסביבות זמני ריצה מדור קודם
- דוגמאות להעברת מסמכים
- דוגמאות להעברה על ידי הקהילה
מידע אחר בענן
- Python ב-Google Cloud Platform
- ספריות הלקוח של Google Cloud Python
- "חינם תמיד" ב-Google Cloud שכבה
- Google Cloud SDK (כלי שורת הפקודה
gcloud
) - כל משאבי העזרה של Google Cloud
סרטונים
- תחנת העברה ללא שרת (serverless)
- קמפיינים ללא שרת (serverless)
- הרשמה למינוי Google Cloud Tech
- הרשמה ל-Google Developers
רישיון
היצירה הזו בשימוש ברישיון Creative Commons Attribution 2.0 גנרי.