העברת Python 2 App Engine Cloud NDB & אפליקציית Cloud Tasks ל-Python 3 ול-Cloud Datastore (מודול 9)

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

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

המטרה של ה-Codelab הזה היא לנייד את האפליקציה לדוגמה של מודול 8 ל-Python 3, וגם להעביר את הגישה של Datastore (Cloud Firestore במצב Datastore) משימוש ב-Cloud NDB לספריית הלקוח המקורית של Cloud Datastore ולשדרג לגרסה העדכנית של ספריית הלקוח של Cloud Tasks.

הוספנו את השימוש בתכונה 'תור המשימות' למשימות push במודול 7, ואז העברנו את השימוש הזה ל-Cloud Tasks במודול 8. כאן במודול 9, נמשיך אל Python 3 ו-Cloud Datastore. משתמשים שמשתמשים בתכונה 'תורי משימות' למשימות משיכה יועברו ל-Cloud Pub/Sub ויפנו למודולים 18-19 במקום זאת.

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

  • העברת האפליקציה לדוגמה של מודול 8 ל-Python 3
  • העברת הגישה של Datastore מ-Cloud NDB לספריות לקוח של Cloud Datastore
  • שדרוג לגרסה האחרונה של ספריית הלקוח ב-Cloud Tasks

למה תזדקק?

סקר

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

לקריאה בלבד לקרוא אותו ולבצע את התרגילים

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

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

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

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

2. רקע

מודול 7 מדגים איך להשתמש במשימות דחיפת תור המשימות של App Engine באפליקציות Python 2 Flask App Engine. במודול 8, מעבירים את האפליקציה מ'תור המשימות' ל-Cloud Tasks. כאן במודול 9, אתם ממשיכים בתהליך הניוד של האפליקציה ל-Python 3 ומעבירים את הגישה ב-Datastore משימוש ב-Cloud NDB לספריית הלקוח המקורית של Cloud Datastore.

מכיוון ש-Cloud NDB פועל גם ב-Python 2 וגם ב-3, הוא מספיק למשתמשי App Engine שמניידים את האפליקציות שלהם מ-Python 2 לגרסה 3. העברה נוספת של ספריות לקוח ל-Cloud Datastore היא אופציונלית לחלוטין, ויש סיבה אחת בלבד להתחשב בה: יש לכם אפליקציות שאינן של App Engine (ו/או אפליקציות Python 3 App Engine) שכבר משתמשות בספריית הלקוח של Cloud Datastore ואתם רוצים לאחד את ה-codebase כדי לגשת ל-Datastore באמצעות ספריית לקוח אחת בלבד. Cloud NDB נוצר במיוחד למפתחים של Python 2 App Engine ככלי להעברת Python 3, כך שאם אין לך עדיין קוד באמצעות ספריית הלקוח של Cloud Datastore, לא צריך לבצע את ההעברה הזו.

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

המדריך הזה כולל את השלבים הבאים:

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

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

בקטע הזה נסביר איך:

  1. הגדרת פרויקט ב-Cloud
  2. אחזור של אפליקציה בסיסית לדוגמה
  3. (מחדש) פריסה ואימות של אפליקציה בסיסית

השלבים האלה נועדו לוודא שאתם מתחילים לעבוד עם קוד ושהוא מוכן להעברה לשירותי Cloud.

1. הגדרת הפרויקט

אם השלמתם את Module 8 Codelab, השתמשו שוב באותו פרויקט (ובקוד). לחלופין, אפשר ליצור פרויקט חדש לגמרי או להשתמש שוב בפרויקט קיים אחר. צריך לוודא שלפרויקט יש חשבון פעיל לחיוב ואפליקציית App Engine מופעלת. אתם יכולים למצוא את מזהה הפרויקט שלכם למקרה הצורך במהלך ה-Codelab הזה, ולהשתמש בו בכל פעם שאתם נתקלים במשתנה PROJECT_ID.

2. אחזור של אפליקציה בסיסית לדוגמה

אחת מהדרישות המוקדמות היא אפליקציית App Engine פעילה של Module 8: משלימים את Codelab ב-Module 8 (מומלץ) או מעתיקים את אפליקציית Module 8 מהמאגר. בין אם אתם משתמשים בזו שלכם או שלנו, קוד מודול 8 הוא המקום שבו נתחיל ("התחלה"). ה-Codelab הזה ינחה אותך לאורך ההעברה, ויסתיים בקוד שדומה למה שמופיע בתיקיית המאגר של מודול 9 ("FINISH").

התיקייה צריכה להיראות כמו בדוגמה הבאה, אולי עם התיקייה lib, בלי קשר לאפליקציית Module 7 שבה אתם משתמשים:

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

3. (מחדש) פריסה ואימות של אפליקציה בסיסית

מבצעים את השלבים הבאים כדי לפרוס את אפליקציית מודול 8:

  1. אם קיימת תיקייה כזו, מוחקים את התיקייה lib ומריצים את הפקודה pip install -t lib -r requirements.txt כדי לאכלס מחדש את lib. יכול להיות שתצטרכו להשתמש ב-pip2 במקום זאת, אם במחשב הפיתוח שלכם מותקנות גם Python 2 וגם גרסה 3.
  2. חשוב לוודא שהתקנתם ואתחלתם את כלי שורת הפקודה gcloud, ושבדקתם את השימוש בו.
  3. (אופציונלי) אם לא רוצים להזין את ה-PROJECT_ID עם כל פקודת gcloud שיוצרים, מגדירים את הפרויקט ב-Cloud לערך gcloud config set project PROJECT_ID.
  4. פריסת האפליקציה לדוגמה באמצעות gcloud app deploy
  5. מוודאים שהאפליקציה פועלת כמצופה ללא בעיות. אם השלמתם את ה-Codelab של מודול 8, האפליקציה מציגה את המבקרים המובילים יחד עם הביקורים האחרונים (איור בהמשך). למטה אפשר לראות אילו משימות ישנות יותר יימחקו.

4aa8a2cb5f527079.png

4. עדכון ההגדרות האישיות

requirements.txt

ה-requirements.txt החדש כמעט זהה לזה שבמודול 8, עם שינוי גדול אחד בלבד: מחליפים את google-cloud-ndb ב-google-cloud-datastore. מבצעים את השינוי כך שקובץ requirements.txt ייראה כך:

flask
google-cloud-datastore
google-cloud-tasks

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

app.yaml

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

עדכון נוסף הוא שסביבת זמן הריצה של Python 3 דורשת שימוש ב-frameworks של אינטרנט שעושות ניתוב משלהן. לכן צריך לשנות את כל רכיבי ה-handler של הסקריפטים ל-auto. עם זאת, צריך לשנות את כל המסלולים ל-auto, ולא מוצגים קבצים סטטיים מהאפליקציה לדוגמה, לכן לא רלוונטי שיהיו אף handlers. לכן צריך להסיר גם את הקטע handlers כולו.

הדבר היחיד שדרוש ב-app.yaml הוא להגדיר את סביבת זמן הריצה לגרסה נתמכת של Python 3, למשל 3.10. מבצעים את השינוי הזה כך שה-app.yaml החדש והמקוצר תהיה רק השורה היחידה הזו:

runtime: python310

מחיקת appengine_config.py ו-lib

סביבות זמן ריצה של App Engine מהדור הבא חידשו את השימוש בחבילות של צד שלישי:

  • ספריות מובנות הן ספריות שנבדקו על ידי Google וזמינות בשרתי App Engine, כנראה כי הן מכילות קוד C/C++ שהמפתחים לא מורשים לפרוס בענן – הן כבר לא זמינות בסביבות זמני הריצה של הדור השני.
  • אין יותר צורך להעתיק ספריות לא מובנות (שנקראות לפעמים 'ספק' או 'קיבוץ עצמי') בסביבות זמני הריצה של הדור השני. במקום זאת, הם צריכים להופיע ב-requirements.txt, שם מערכת ה-build מתקינה אותם באופן אוטומטי בזמן הפריסה.

בעקבות השינויים האלה בניהול חבילות של צד שלישי, אין צורך בקובץ appengine_config.py או בתיקייה lib, לכן צריך למחוק אותם. בסביבות זמני ריצה של הדור השני, App Engine מתקין באופן אוטומטי חבילות של צד שלישי שמפורטות ב-requirements.txt. סיכום:

  1. לא לכלול ספריות של צד שלישי באריזה עצמית או בהעתקה. צריך לרשום אותם ב-requirements.txt
  2. לא pip install בתוך תיקייה מסוג lib, כלומר אין תקופה של lib תיקייה
  3. אין רישום של ספריות מובְנות של צד שלישי (כלומר, לא בקטע libraries) ב-app.yaml; צריך לרשום אותם ב-requirements.txt
  4. אין ספריות של צד שלישי להפניה מהאפליקציה שלך. פירוש הדבר שאין קובץ appengine_config.py

הדרישה היחידה למפתחים היא להציג את כל הספריות הרצויות של צד שלישי ב-requirements.txt.

5. עדכון קובצי אפליקציה

יש רק קובץ אפליקציה אחד, main.py, כך שכל השינויים בקטע הזה ישפיעו רק על הקובץ הזה. לפניכם 'הבדלים' איור של השינויים הכוללים שצריך לבצע כדי לארגן מחדש את הקוד הקיים באפליקציה החדשה. אין לצפות מהקוראים לקרוא את הקוד שורה אחרי שורה, כי המטרה שלו היא לקבל סקירה כללית של מה שנחוץ בהגדרה מחדש (אבל אפשר לפתוח את הקוד בכרטיסייה חדשה או להוריד אותו ולהגדיל את התצוגה אם רוצים).

5d043768ba7be742.png

ייבוא ואתחול של עדכונים

קטע הייבוא ב-main.py למודול 8 משתמש ב-Cloud NDB וב-Cloud Tasks. היא אמורה להיראות כך:

לפני:

from datetime import datetime
import json
import logging
import time
from flask import Flask, render_template, request
import google.auth
from google.cloud import ndb, tasks

app = Flask(__name__)
ds_client = ndb.Client()
ts_client = tasks.CloudTasksClient()

הרישום ביומן פשוט יותר ומשופר בסביבות זמני ריצה של דור שני, כמו Python 3:

  • כדי ליהנות מחוויית רישום מקיפה ביומן, כדאי להשתמש ב-Cloud Logging
  • לרישום פשוט ביומן, צריך לשלוח אל stdout (או אל stderr) דרך print()
  • אין צורך להשתמש במודול logging של Python (לכן צריך להסיר אותו)

לכן, צריך למחוק את הייבוא של logging ולהחליף את הערך של google.cloud.ndb ב-google.cloud.datastore. באופן דומה, משנים את ds_client כדי להפנות ללקוח Datastore במקום ללקוח NDB. אחרי ביצוע השינויים, החלק העליון של האפליקציה החדשה נראה כך:

אחרי:

from datetime import datetime
import json
import time
from flask import Flask, render_template, request
import google.auth
from google.cloud import datastore, tasks

app = Flask(__name__)
ds_client = datastore.Client()
ts_client = tasks.CloudTasksClient()

העברה ל-Cloud Datastore

זה הזמן להחליף את השימוש בספריית הלקוח של NDB ב-Datastore. גם ל-App Engine NDB וגם ל-Cloud NDB נדרש מודל נתונים (מחלקה) האפליקציה הזו היא Visit. הפונקציה store_visit() פועלת באופן זהה בכל המודולים האחרים של העברה: היא רושמת ביקור על ידי יצירת רשומת Visit חדשה, ושמירת כתובת ה-IP של הלקוח שמבקרים בו וסוכן המשתמש (סוג הדפדפן).

לפני:

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 entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

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

בלי סיווג הנתונים, הערך של store_visit() שערכתם אמור להיראות כך:

אחרי:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    entity = datastore.Entity(key=ds_client.key('Visit'))
    entity.update({
        'timestamp': datetime.now(),
        'visitor': '{}: {}'.format(remote_addr, user_agent),
    })
    ds_client.put(entity)

פונקציית המפתח היא fetch_visits(). כלומר, הפקודה לא רק מבצעת את השאילתה המקורית עבור ה-Visit האחרונים, אלא גם מאחזרת את חותמת הזמן של Visit האחרונים המוצגים ויוצרת את משימת הדחיפה שקוראת ל-/trim (כלומר trim()) כדי למחוק בבת אחת את ה-Visit הישנים. כאן הוא משתמש ב-Cloud NDB:

לפני:

def fetch_visits(limit):
    'get most recent visits & add task to delete older visits'
    with ds_client.context():
        data = Visit.query().order(-Visit.timestamp).fetch(limit)
    oldest = time.mktime(data[-1].timestamp.timetuple())
    oldest_str = time.ctime(oldest)
    logging.info('Delete entities older than %s' % oldest_str)
    task = {
        'app_engine_http_request': {
            'relative_uri': '/trim',
            'body': json.dumps({'oldest': oldest}).encode(),
            'headers': {
                'Content-Type': 'application/json',
            },
        }
    }
    ts_client.create_task(parent=QUEUE_PATH, task=task)
    return (v.to_dict() for v in data), oldest_str

השינויים העיקריים:

  1. להחליף את שאילתת Cloud NDB לערך המקביל ב-Cloud Datastore; סגנונות השאילתה שונים מעט.
  2. ב-Datastore לא נדרש שימוש במנהל הקשר ולכן לא ניתן לחלץ את הנתונים שלו (באמצעות to_dict()) כמו ב-Cloud NDB.
  3. החלפה של רישום השיחות ביומן ב-print()

לאחר השינויים האלה, fetch_visits() ייראה כך:

אחרי:

def fetch_visits(limit):
    'get most recent visits & add task to delete older visits'
    query = ds_client.query(kind='Visit')
    query.order = ['-timestamp']
    visits = list(query.fetch(limit=limit))
    oldest = time.mktime(visits[-1]['timestamp'].timetuple())
    oldest_str = time.ctime(oldest)
    print('Delete entities older than %s' % oldest_str)
    task = {
        'app_engine_http_request': {
            'relative_uri': '/trim',
            'body': json.dumps({'oldest': oldest}).encode(),
            'headers': {
                'Content-Type': 'application/json',
            },
        }
    }
    ts_client.create_task(parent=QUEUE_PATH, task=task)
    return visits, oldest_str

בדרך כלל זה כל מה שנחוץ. לצערנו, יש בעיה משמעותית אחת.

(כנראה) יצירת תור חדש (push)

במודול 7 הוספנו את השימוש ב-App Engine taskqueue לאפליקציית מודול 1 הקיימת. אחד היתרונות המרכזיים של שימוש במשימות דחיפה כתכונה מדור קודם של App Engine הוא "ברירת מחדל". 'הבאים בתור' נוצר באופן אוטומטי. כשהאפליקציה הזו הועברה ל-Cloud Tasks במודול 8, תור ברירת המחדל כבר היה שם, כך שעדיין לא היינו צריכים לדאוג לגבי זה באותו זמן. זה משתנה כאן במודול 9.

היבט קריטי אחד שחשוב להביא בחשבון הוא שאפליקציית App Engine החדשה כבר לא משתמשת בשירותי App Engine, ולכן כבר אי אפשר להניח ש-App Engine יוצר תור משימות באופן אוטומטי במוצר אחר (Cloud Tasks). כפי שכתוב, יצירת משימה ב-fetch_visits() (בתור שלא קיים) תיכשל. דרושה פונקציה חדשה כדי לבדוק אם קיים תור (ברירת מחדל), ואם לא, ליצור תור.

צריך לקרוא לפונקציה _create_queue_if() ולהוסיף אותה לאפליקציה ממש מעל fetch_visits(), כי שם היא נקראת. גוף הפונקציה להוספה:

def _create_queue_if():
    'app-internal function creating default queue if it does not exist'
    try:
        ts_client.get_queue(name=QUEUE_PATH)
    except Exception as e:
        if 'does not exist' in str(e):
            ts_client.create_queue(parent=PATH_PREFIX,
                    queue={'name': QUEUE_PATH})
    return True

לפונקציה create_queue() של Cloud Tasks נדרש שם הנתיב המלא של התור, חוץ משם התור. כדי לשמור על פשטות, אפשר ליצור משתנה נוסף PATH_PREFIX שמייצג את QUEUE_PATH פחות שם התור (QUEUE_PATH.rsplit('/', 2)[0]). מוסיפים את ההגדרה שלו בחלק העליון של הדף כך שבלוק הקוד עם כל ההקצאות הקבועות ייראה כך:

_, PROJECT_ID = google.auth.default()
REGION_ID = 'REGION_ID'    # replace w/your own
QUEUE_NAME = 'default'     # replace w/your own
QUEUE_PATH = ts_client.queue_path(PROJECT_ID, REGION_ID, QUEUE_NAME)
PATH_PREFIX = QUEUE_PATH.rsplit('/', 2)[0]

עכשיו צריך לשנות את השורה האחרונה ב-fetch_visits() כך שתשתמש ב-_create_queue_if(). קודם יוצרים את התור אם צריך ואז יוצרים את המשימה לאחר מכן:

    if _create_queue_if():
        ts_client.create_task(parent=QUEUE_PATH, task=task)
    return visits, oldest_str

עכשיו הנתונים של _create_queue_if() ושל fetch_visits() צריכים להיראות כך באופן מצטבר:

def _create_queue_if():
    'app-internal function creating default queue if it does not exist'
    try:
        ts_client.get_queue(name=QUEUE_PATH)
    except Exception as e:
        if 'does not exist' in str(e):
            ts_client.create_queue(parent=PATH_PREFIX,
                    queue={'name': QUEUE_PATH})
    return True

def fetch_visits(limit):
    'get most recent visits & add task to delete older visits'
    query = ds_client.query(kind='Visit')
    query.order = ['-timestamp']
    visits = list(query.fetch(limit=limit))
    oldest = time.mktime(visits[-1]['timestamp'].timetuple())
    oldest_str = time.ctime(oldest)
    print('Delete entities older than %s' % oldest_str)
    task = {
        'app_engine_http_request': {
            'relative_uri': '/trim',
            'body': json.dumps({'oldest': oldest}).encode(),
            'headers': {
                'Content-Type': 'application/json',
            },
        }
    }
    if _create_queue_if():
        ts_client.create_task(parent=QUEUE_PATH, task=task)
    return visits, oldest_str

חוץ מזה שצריך להוסיף את הקוד הנוסף הזה, רוב הקוד של Cloud Tasks נשאר ללא שינוי ממודול 8. קטע הקוד האחרון שצריך לבחון הוא ה-handler של המשימה.

עדכון handler (התראות) במשימה

ב-handler של המשימות, trim(), שאילתות הקוד של Cloud NDB לביקורים ישנים יותר מהישן לחדש. היא משתמשת בשאילתה למפתחות בלבד כדי לזרז את התהליך – למה לאחזר את כל הנתונים אם צריך רק את מזהי הביקורים? אחרי שמקבלים את כל מזהי הביקורים, מוחקים את כולם בקבוצה באמצעות הפונקציה delete_multi() של Cloud NDB.

לפני:

@app.route('/trim', methods=['POST'])
def trim():
    '(push) task queue handler to delete oldest visits'
    oldest = float(request.get_json().get('oldest'))
    with ds_client.context():
        keys = Visit.query(
                Visit.timestamp < datetime.fromtimestamp(oldest)
        ).fetch(keys_only=True)
        nkeys = len(keys)
        if nkeys:
            logging.info('Deleting %d entities: %s' % (
                    nkeys, ', '.join(str(k.id()) for k in keys)))
            ndb.delete_multi(keys)
        else:
            logging.info(
                    'No entities older than: %s' % time.ctime(oldest))
    return ''   # need to return SOME string w/200

בדומה ל-fetch_visits(), רוב השינויים כוללים החלפת קוד Cloud NDB ל-Cloud Datastore, שינוי סגנונות של השאילתות, הסרת השימוש במנהל ההקשר ושינוי הקריאות לרישום ביומן ל-print().

אחרי:

@app.route('/trim', methods=['POST'])
def trim():
    '(push) task queue handler to delete oldest visits'
    oldest = float(request.get_json().get('oldest'))
    query = ds_client.query(kind='Visit')
    query.add_filter('timestamp', '<', datetime.fromtimestamp(oldest))
    query.keys_only()
    keys = list(visit.key for visit in query.fetch())
    nkeys = len(keys)
    if nkeys:
        print('Deleting %d entities: %s' % (
                nkeys, ', '.join(str(k.id) for k in keys)))
        ds_client.delete_multi(keys)
    else:
        print('No entities older than: %s' % time.ctime(oldest))
    return ''   # need to return SOME string w/200

אין שינויים ב-handler הראשי של האפליקציה root().

יציאה אל Python 3

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

עדכון ל-Cloud Tasks

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

עדכון של תבנית HTML

גם בקובץ תבנית ה-HTML, templates/index.html, אין צורך לבצע שינויים, לכן סיכום זה כולל את כל השינויים הנחוצים כדי להגיע לאפליקציית מודול 9.

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

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

אחרי שמשלימים את עדכוני הקוד, בעיקר את היציאה ל-Python 3, פורסים את האפליקציה באמצעות gcloud app deploy. הפלט אמור להיות זהה לאפליקציות שבאפליקציה ממודולים 7 ו-8, אלא שהעברת את הגישה למסד הנתונים לספריית הלקוח של Cloud Datastore וששדרגתם ל-Python 3:

אפליקציית ביקורים של מודול 7

השלב הזה מסתיים ב-Codelab. אנחנו מזמינים אתכם להשוות את הקוד שלכם לקוד שמופיע בתיקיית מודול 9. מעולה!

הסרת המשאבים

כללי

אם סיימתם בינתיים, מומלץ להשבית את אפליקציית 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 הזה. אפשר לקרוא מידע נוסף במסמכי התיעוד של כל מוצר:

השלבים הבאים

סיימנו את ההעברה שלנו ממשימות הדחיפה לתור המשימות של App Engine אל Cloud Tasks. גם ההעברה האופציונלית מ-Cloud NDB ל-Cloud Datastore מתבצעת בעצמה (ללא 'תור משימות' או Cloud Tasks) במודול 3. בנוסף למודול 3, קיימים מודולים אחרים של העברה שמתמקדים בהפסקת השירותים בחבילה מהדור הקודם של App Engine, כולל:

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 של המאגר גם מספק הדרכה לגבי ההעברות שכדאי לשקול ו"הזמנה" רלוונטית של מודולי העברה.

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

בעיות/משוב על Codelabs

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

משאבים להעברה

בטבלה שלמטה מופיעים הקישורים לתיקיות המאגר של מודול 8 (START) ומודול 9 (FINISH). אפשר לגשת אליהן גם דרך המאגר לכל העברות Codelab ב-App Engine, שאותו ניתן לשכפל או להוריד בקובץ ZIP.

Codelab

ֶPython 2

ֶPython 3

יחידת לימוד 8

קוד

(לא רלוונטי)

יחידת לימוד 9

(לא רלוונטי)

קוד

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

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

App Engine

NDB בענן

Cloud Datastore

Cloud Tasks

מידע אחר בענן

רישיון

היצירה הזו בשימוש ברישיון Creative Commons Attribution 2.0 גנרי.