איך להשתמש ב-blobstore של App Engine (מודול 15)

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

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

ב-Codelab הזה (מודול 15) מוסבר איך להוסיף נתוני שימוש ב-App Engine blobstore לאפליקציה לדוגמה ממודול 0. אחר כך תוכלו להעביר את השימוש הזה ל-Cloud Storage, כפי שמוסבר במודול 16.

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

  • הוספת שימוש ב-App Engine Blobstore API/library
  • אחסון העלאות של משתמשים בשירות blobstore
  • הכנה לשלב הבא של המעבר ל-Cloud Storage

הדרישות

סקר

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

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

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

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

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

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

2. רקע

כדי לבצע מיגרציה מ-App Engine Blobstore API, מוסיפים את השימוש בו לאפליקציית App Engine הקיימת ndb ממודול 0. באפליקציה לדוגמה מוצגים עשרת הביקורים האחרונים של המשתמש. אנחנו משנים את האפליקציה כך שהיא תבקש ממשתמש הקצה להעלות ארטיפקט (קובץ) שמתאים ל'ביקור' שלו. אם המשתמש לא רוצה לעשות זאת, יש לו אפשרות 'דילוג'. לא משנה מה ההחלטה של המשתמש, הדף הבא מציג את אותה הפלט כמו האפליקציה ממודול 0 (והרבה מהמודולים האחרים בסדרה הזו). אחרי שמטמיעים את השילוב הזה של App Engine blobstore, אפשר להעביר אותו אל Cloud Storage בסדנת הקוד הבאה (מודול 16).

‫App Engine מספק גישה למערכות התבניות Django ו-Jinja2. דבר נוסף שמבדיל את הדוגמה הזו (מלבד הוספת גישה ל-Blobstore) הוא המעבר משימוש ב-Django במודול 0 לשימוש ב-Jinja2 במודול 15. שלב חשוב במודרניזציה של אפליקציות App Engine הוא העברה של מסגרות אינטרנט מ-webapp2 ל-Flask. האחרון משתמש ב-Jinja2 כמערכת ברירת המחדל ליצירת תבניות, ולכן אנחנו מתחילים לפעול בכיוון הזה על ידי הטמעה של Jinja2 תוך שמירה על webapp2 לגישה ל-Blobstore. מכיוון ש-Flask משתמש ב-Jinja2 כברירת מחדל, לא יהיה צורך לבצע שינויים בתבנית בהמשך, במודול 16.

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

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

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

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

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

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

הספרייה של קובצי ההתחלה של מודול 0 צריכה להיראות כך:

$ ls
README.md               index.html
app.yaml                main.py

3. (Re)Deploy baseline app

השלבים הנותרים שצריך לבצע עכשיו:

  1. כדאי להכיר מחדש את כלי שורת הפקודה gcloud
  2. פריסה מחדש של האפליקציה לדוגמה עם gcloud app deploy
  3. אישור שהאפליקציה פועלת ב-App Engine ללא בעיות

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

a7a9d2b80d706a2b.png

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

app.yaml

אין שינויים מהותיים בהגדרת האפליקציה, אבל כמו שציינו קודם, אנחנו עוברים מ-Django templating (ברירת מחדל) ל-Jinja2. כדי לעבור, המשתמשים צריכים לציין את הגרסה האחרונה של Jinja2 שזמינה בשרתי App Engine. כדי לעשות זאת, צריך להוסיף אותה לקטע של ספריות צד שלישי מובנות ב-app.yaml.

לפני:

runtime: python27
threadsafe: yes
api_version: 1

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

עורכים את קובץ app.yaml ומוסיפים קטע חדש של libraries כמו בדוגמה הבאה:

אחרי:

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: jinja2
  version: latest

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

5. שינוי קבצים של אפליקציות

ייבוא ותמיכה ב-Jinja2

השינויים הראשונים ב-main.py כוללים הוספה של שימוש ב-Blobstore API והחלפה של Django templating ב-Jinja2. אלה השינויים שיחולו:

  1. המטרה של מודול os היא ליצור שם נתיב של קובץ לתבנית Django. אנחנו עוברים ל-Jinja2, שבו הטיפול הזה מתבצע, ולכן אין יותר צורך בשימוש ב-os ובמנוע רינדור התבניות של Django, ‏ google.appengine.ext.webapp.template, ואנחנו מסירים אותם.
  2. מייבאים את Blobstore API: ‏ google.appengine.ext.blobstore
  3. מייבאים את ה-handlers של Blobstore שנמצאים ב-framework המקורי webapp – הם לא זמינים ב-webapp2: google.appengine.ext.webapp.blobstore_handlers
  4. ייבוא תמיכה ב-Jinja2 מחבילת webapp2_extras

לפני:

import os
import webapp2
from google.appengine.ext import ndb
from google.appengine.ext.webapp import template

כדי להטמיע את השינויים שברשימה שלמעלה, צריך להחליף את קטע הייבוא הנוכחי ב-main.py בקטע הקוד שלמטה.

אחרי:

import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers

אחרי הייבוא, מוסיפים קוד boilerplate כדי לתמוך בשימוש ב-Jinja2 כמו שמוגדר במסמכי webapp2_extras. קטע הקוד הבא עוטף את המחלקה הרגילה של webapp2 לטיפול בבקשות בפונקציונליות של Jinja2, ולכן צריך להוסיף את בלוק הקוד הזה ל-main.py מיד אחרי הייבוא:

class BaseHandler(webapp2.RequestHandler):
    'Derived request handler mixing-in Jinja2 support'
    @webapp2.cached_property
    def jinja2(self):
        return jinja2.get_jinja2(app=self.app)

    def render_response(self, _template, **context):
        self.response.write(self.jinja2.render_template(_template, **context))

הוספת תמיכה ב-Blobstore

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

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

עדכון מודל הנתונים והטמעת השימוש בו

אנחנו מאחסנים יותר נתונים, ובאופן ספציפי, מעדכנים את מודל הנתונים כדי לאחסן את המזהה (שנקרא BlobKey) של הקובץ שהועלה ל-Blobstore, ומוסיפים הפניה כדי לשמור את המזהה ב-store_visit(). מכיוון שהנתונים הנוספים האלה מוחזרים יחד עם כל השאר בשאילתה, fetch_visits() נשאר ללא שינוי.

אלה השינויים שיתבצעו בעקבות העדכונים האלה, עם file_blob, ndb.BlobKeyProperty:

לפני:

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'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

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)
    file_blob = ndb.BlobKeyProperty()

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

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

לפניכם תמונה שממחישה את השינויים שבוצעו עד עכשיו:

2270783776759f7f.png

תמיכה בהעלאות של קבצים

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

  1. הבקשה של המטפל הראשי GET לא מאחזרת יותר את הביקורים האחרונים להצגה. במקום זאת, המשתמש מתבקש להעלות את הקובץ.
  2. כשמשתמש קצה שולח קובץ להעלאה או מדלג על התהליך הזה, POST מהטופס מעביר את השליטה אל UploadHandler החדש, שנגזר מ-google.appengine.ext.webapp.blobstore_handlers.BlobstoreUploadHandler.
  3. השיטה UploadHandler של POST מבצעת את ההעלאה, קוראת ל-store_visit() כדי לרשום את הביקור ומפעילה הפניה אוטומטית מסוג HTTP 307 כדי להחזיר את המשתמש אל '/', כאשר...
  4. השיטה POST של המטפל הראשי שולחת שאילתה לגבי הביקורים האחרונים (דרך fetch_visits()) ומציגה אותם. אם המשתמש בוחר באפשרות 'דילוג', לא מתבצעת העלאה של קובץ, אבל הביקור עדיין נרשם ואחריו מתבצעת אותה הפניה אוטומטית.
  5. התצוגה 'הביקורים האחרונים' כוללת שדה חדש שמוצג למשתמש. אם קובץ להעלאה זמין, מוצג קישור 'צפייה', אחרת מוצג 'ללא'. השינויים האלה מיושמים בתבנית ה-HTML, ובנוסף מתווסף טופס העלאה (מידע נוסף על כך יפורסם בקרוב).
  6. אם משתמש קצה לוחץ על הקישור 'הצגה' לביקור כלשהו עם סרטון שהועלה, נשלחת GET בקשה ל-ViewBlobHandler חדש, שנגזר מ-google.appengine.ext.webapp.blobstore_handlers.BlobstoreDownloadHandler. הקובץ מוצג אם הוא תמונה (בדפדפן אם הוא נתמך), או שמוצגת בקשה להורדה אם הוא לא תמונה, או שמוחזרת שגיאת HTTP 404 אם הקובץ לא נמצא.
  7. בנוסף לצמד החדש של מחלקות handler ולצמד חדש של נתיבים לשליחת תנועה אליהם, ה-handler הראשי צריך שיטת POST חדשה כדי לקבל את ההפניה האוטומטית 307 שמתוארת למעלה.

לפני העדכונים האלה, באפליקציה Module 0 היה רק handler ראשי עם שיטה GET ונתיב אחד:

לפני:

class MainHandler(webapp2.RequestHandler):
    'main application (GET) handler'
    def get(self):
        store_visit(self.request.remote_addr, self.request.user_agent)
        visits = fetch_visits(10)
        tmpl = os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(tmpl, {'visits': visits}))

app = webapp2.WSGIApplication([
    ('/', MainHandler),
], debug=True)

אחרי הטמעת העדכונים האלה, יש עכשיו שלושה handlers: ‏ 1) upload handler עם שיטת POST, ‏ 2) download handler של 'view blob' עם שיטת GET, ‏ 3) handler ראשי עם שיטות GET ו-POST. מבצעים את השינויים האלה כדי ששאר האפליקציה ייראו כמו בדוגמה שלמטה.

אחרי:

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    'Upload blob (POST) handler'
    def post(self):
        uploads = self.get_uploads()
        blob_id = uploads[0].key() if uploads else None
        store_visit(self.request.remote_addr, self.request.user_agent, blob_id)
        self.redirect('/', code=307)

class ViewBlobHandler(blobstore_handlers.BlobstoreDownloadHandler):
    'view uploaded blob (GET) handler'
    def get(self, blob_key):
        self.send_blob(blob_key) if blobstore.get(blob_key) else self.error(404)

class MainHandler(BaseHandler):
    'main application (GET/POST) handler'
    def get(self):
        self.render_response('index.html',
                upload_url=blobstore.create_upload_url('/upload'))

    def post(self):
        visits = fetch_visits(10)
        self.render_response('index.html', visits=visits)

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    ('/upload', UploadHandler),
    ('/view/([^/]+)?', ViewBlobHandler),
], debug=True)

יש כמה קריאות חשובות בקוד שזה עתה הוספנו:

  • ב-MainHandler.get, יש שיחה אל blobstore.create_upload_url. הקריאה הזו יוצרת את כתובת ה-URL שאליה הטופס POST נשלח, ומפעילה את ה-handler להעלאה כדי לשלוח את הקובץ ל-Blobstore.
  • ב-UploadHandler.post, יש שיחה אל blobstore_handlers.BlobstoreUploadHandler.get_uploads. זה הקסם האמיתי שמעביר את הקובץ ל-Blobstore ומחזיר מזהה ייחודי וקבוע לקובץ הזה, שהוא BlobKey.
  • ב-ViewBlobHandler.get, קריאה ל-blobstore_handlers.BlobstoreDownloadHandler.send עם BlobKey של קובץ גורמת לאחזור הקובץ ולהעברתו לדפדפן של משתמש הקצה

הקריאות האלה מייצגות את רוב הגישה לתכונות שנוספו לאפליקציה. הנה ייצוג גרפי של השינויים השני והאחרון ב-main.py:

da2960525ac1b90d.png

עדכון תבנית HTML

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

  1. נדרש טופס להעלאת קבצים עם 3 רכיבי קלט: קובץ וצמד לחצני שליחה להעלאת קובץ ודילוג, בהתאמה.
  2. עדכון הפלט של הביקורים האחרונים על ידי הוספת קישור 'צפייה' לביקורים עם העלאת קובץ תואמת, או 'none' אחרת.

לפני:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>

<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
    <li>{{ visit.timestamp.ctime }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>

</body>
</html>

מבצעים את השינויים ברשימה שלמעלה כדי ליצור את התבנית המעודכנת:

אחרי:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>

<h1>VisitMe example</h1>
{% if upload_url %}

<h3>Welcome... upload a file? (optional)</h3>
<form action="{{ upload_url }}" method="POST" enctype="multipart/form-data">
    <input type="file" name="file"><p></p>
    <input type="submit"> <input type="submit" value="Skip">
</form>

{% else %}

<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
<li>{{ visit.timestamp.ctime() }}
    <i><code>
    {% if visit.file_blob %}
        (<a href="/view/{{ visit.file_blob }}" target="_blank">view</a>)
    {% else %}
        (none)
    {% endif %}
    </code></i>
    from {{ visit.visitor }}
</li>
{% endfor %}
</ul>

{% endif %}

</body>
</html>

בתמונה הזו מוצגים העדכונים הנדרשים ב-index.html:

8583e975f25aa9e7.png

שינוי אחרון הוא ש-Jinja2 מעדיף שהתבניות שלו יהיו בתיקייה templates, לכן צריך ליצור את התיקייה הזו ולהעביר את index.html לתוכה. בשלב הזה סיימתם את כל השינויים הנדרשים כדי להוסיף את השימוש ב-Blobstore לאפליקציית הדוגמה של מודול 0.

(אופציונלי) 'שיפור' של Cloud Storage

בסופו של דבר, האחסון ב-Blobstore התפתח ל-Cloud Storage. המשמעות היא שהעלאות ל-Blobstore גלויות במסוף Cloud, ובמיוחד בדפדפן Cloud Storage. השאלה היא איפה. התשובה היא קטגוריית Cloud Storage שמוגדרת כברירת מחדל באפליקציית App Engine. השם שלו הוא השם של הדומיין המלא של אפליקציית App Engine, ‏ PROJECT_ID.appspot.com. זה מאוד נוח כי כל מזהי הפרויקטים הם ייחודיים, נכון?

העדכונים שבוצעו באפליקציית הדוגמה גורמים להעלאת הקבצים ל-bucket הזה, אבל למפתחים יש אפשרות לבחור מיקום ספציפי יותר. אפשר לגשת אל דלי ברירת המחדל באופן פרוגרמטי באמצעות google.appengine.api.app_identity.get_default_gcs_bucket_name(), ולכן צריך לייבא מחדש אם רוצים לגשת לערך הזה, למשל כדי להשתמש בו כקידומת לארגון קבצים שהועלו. לדוגמה, מיון לפי סוג קובץ:

f61f7a23a1518705.png

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

ROOT_BUCKET = app_identity.get_default_gcs_bucket_name()
IMAGE_BUCKET = '%s/%s' % (ROOT_BUCKET, 'images')

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

נניח שכל זה כבר נעשה. איך אפשר לעדכן את האפליקציה שלנו כך שתתמוך בציון המיקום לאחסון הקבצים שהועלו? כדי לציין את המיקום הרצוי ב-Cloud Storage להעלאה, צריך לשנות את הקריאה ל-blobstore.create_upload_url ב-MainHandler.get ולהוסיף את הפרמטר gs_bucket_name כך:

blobstore.create_upload_url('/upload', gs_bucket_name=IMAGE_BUCKET))

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

256e1ea68241a501.png

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

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

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

מבצעים פריסה מחדש של האפליקציה עם gcloud app deploy, ומוודאים שהאפליקציה פועלת כמו שמתואר, עם חוויית משתמש שונה מזו של אפליקציית מודול 0. עכשיו יש באפליקציה שני מסכים שונים. הראשון הוא ההנחיה למילוי הטופס להעלאת קובץ הביקור:

f5b5f9f19d8ae978.pngמשם, משתמשי הקצה יכולים להעלות קובץ וללחוץ על 'שליחה', או ללחוץ על 'דילוג' כדי לא להעלות כלום. בכל מקרה, התוצאה היא המסך של הביקור האחרון, שעכשיו מופיעים בו קישורים ל'צפייה' או 'ללא' בין חותמות הזמן של הביקור לבין פרטי המבקר:

f5ac6b98ee8a34cb.png

סיימתם את ה-codelab הזה, והוספתם שימוש ב-Blobstore של App Engine לאפליקציית הדוגמה Module 0. הקוד שלכם צריך להיות זהה לקוד שבתיקייה FINISH (Module 15). הקובץ החלופי main-gcs.py נמצא גם הוא בתיקייה הזו.

הסרת המשאבים

כללי

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

השלבים הבאים

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

מעבר למודול 16 יש עוד הרבה אפשרויות להעברה, כמו Cloud NDB ו-Cloud Datastore, ‏ Cloud Tasks או Cloud Memorystore. יש גם העברות בין מוצרים אל Cloud Run ו-Cloud Functions. מאגר ההעברה כולל את כל דוגמאות הקוד, קישורים לכל סדנאות ה-codelab והסרטונים שזמינים, וגם הנחיות לגבי ההעברות שכדאי לבצע וסדר ההעברות הרלוונטי.

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

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

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

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

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

Codelab

Python 2

Python 3

יחידת לימוד 0

קוד

לא רלוונטי

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

קוד

לא רלוונטי

משאבים באינטרנט

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

App Engine

Google Cloud

Python

סרטונים

רישיון

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