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

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

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

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

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

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

למה תזדקק?

סקר

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

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

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

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

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

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

2. רקע

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

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

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

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

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

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

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

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

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

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

3. (Re) פריסת אפליקציות בסיסיות

שאר השלבים לפני העבודה שצריך לבצע עכשיו:

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

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

a7a9d2b80d706a2b.png

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

app.yaml

אין שינויים מהותיים בתצורת האפליקציה, אבל כפי שציינו קודם, אנחנו עוברים מתבניות Django (ברירת המחדל) ל-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 כוללת את הוספת השימוש ב-Bblobstore API, והחלפת התבניות של Django ב-Jinja2. מה עומד להשתנות?

  1. מטרת המודול os היא ליצור שם נתיב של קובץ לתבנית Django. מכיוון שאנחנו עוברים ל-Jinja2 שבה אנחנו מטפלים בזה, אין יותר צורך בשימוש ב-os וגם בכלי לרינדור תבניות Django , google.appengine.ext.webapp.template, ולכן אנחנו מסירים אותם.
  2. ייבוא של Blobstore API: google.appengine.ext.blobstore
  3. אפשר לייבא את רכיבי ה-handler של Blobstore שנמצאים במסגרת 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

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

לפני העדכונים האלה, באפליקציית מודול 0 הייתה רק handler ראשי עם method 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)

אחרי ההטמעה של העדכונים האלה, יש עכשיו שלושה רכיבי handler: 1) handler של העלאה באמצעות method POST, 2) 'view blob' להוריד handler עם method GET, ו-3) את ה-handler הראשי באמצעות methods של 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 של ההעלאה לשלוח את הקובץ ל-Bblobstore.
  • בעוד UploadHandler.post בוצעה שיחה למספר blobstore_handlers.BlobstoreUploadHandler.get_uploads. זה הקסם האמיתי שמכניס את הקובץ ל-Bblobstore ומחזיר מזהה ייחודי וקבוע לקובץ הזה, ה-BlobKey שלו.
  • ב-ViewBlobHandler.get, קריאה אל blobstore_handlers.BlobstoreDownloadHandler.send עם BlobKey של קובץ כלשהו תגרום לאחזור הקובץ ולהעברתו לדפדפן של משתמש הקצה.

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

da2960525ac1b90d.png

עדכון תבנית HTML

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

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

לפני:

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

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

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

העדכונים שמתבצעים באפליקציה לדוגמה יורשים קבצים שהועלו לקטגוריה הזו, אבל למפתחים יש אפשרות לבחור מיקום ספציפי יותר. אפשר לגשת לקטגוריית ברירת המחדל באופן פרוגרמטי דרך 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')

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

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

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

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

256e1ea68241a501.png

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

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

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

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

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

f5ac6b98ee8a34cb.png

ברכות על השלמת השימוש ב-Codelab ב-App Engine לאפליקציה לדוגמה של מודול 0. הקוד אמור עכשיו להתאים למה שמופיע בתיקייה FINISH (מודול 15). main-gcs.py החלופי קיים גם בתיקייה הזו.

הסרת המשאבים

כללי

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

השלבים הבאים

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

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

משוב או בעיות ב-Codelab

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

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

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

Codelab

ֶPython 2

ֶPython 3

יחידת לימוד 0

קוד

לא רלוונטי

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

קוד

לא רלוונטי

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

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

App Engine

Google Cloud

Python

סרטונים

רישיון

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