פריסת אפליקציית אינטרנט של Python Flask בסביבה גמישה של App Engine

סיכום

בשיעור הזה תלמדו איך לפרוס אפליקציית אינטרנט של Python Flask בסביבה הגמישה של App Engine. אפליקציית הדוגמה מאפשרת למשתמש להעלות תמונה של פנים של אדם ולגלות מה הסיכוי שהאדם שמח. האפליקציה משתמשת ב-Google Cloud APIs ל-Vision, ל-Storage ול-Datastore.

מידע על App Engine

קל ליצור אפליקציות של Google App Engine, קל לתחזק אותן וקל להרחיב אותן ככל שהתנועה וצרכי אחסון הנתונים משתנים. ב-App Engine, אין שרתים לתחזוקה. פשוט מעלים את האפליקציה והיא מוכנה לשימוש.

אפליקציות של App Engine עוברות שינוי גודל באופן אוטומטי על סמך התנועה הנכנסת. איזון עומסים, מיקרו-שירותים, הרשאות, מסדי נתונים של SQL ו-NoSQL, פיצול תעבורה, רישום ביומן, חיפוש, ניהול גרסאות, פריסה והחזרה מפריסה וסריקת אבטחה – כל אלה נתמכים באופן מקורי וניתנים להתאמה אישית.

הסביבה הגמישה של App Engine תומכת בכל שפות התכנות הבאות: C#‎,‏ Go,‏ Java,‏ Node.js,‏ PHP,‏ Python ו-Ruby. ‫App Engine Flexible מריץ את האפליקציה שלכם בתוך קונטיינרים של Docker שפועלים במכונות וירטואליות של Google Compute Engine. הסביבה הרגילה של App Engine היא אפשרות חלופית לשפות מסוימות, כולל Python. סביבה רגילה של App Engine מריצה את האפליקציה בסביבת ארגז חול מגבילה יותר. מידע נוסף זמין במאמר בחירת סביבת App Engine.

מה תלמדו

  • איך פורסים אפליקציית אינטרנט פשוטה בסביבה גמישה של App Engine
  • איך ניגשים לספריות הלקוח של Google Cloud עבור Vision,‏ Storage ו-Datastore
  • איך משתמשים ב-Google Cloud Console וב-Google Cloud SDK כדי לנהל משאבים שונים בענן
  • איך משתמשים ב-Cloud Shell

מה צריך להכין

  • היכרות עם Python
  • היכרות עם כלים לעריכת טקסט של Linux, כמו Vim, ‏ Emacs או Nano

יצירת פרויקט

אם עדיין אין לכם חשבון Google (Gmail או Google Apps), אתם צריכים ליצור חשבון. נכנסים ל-Google Cloud Platform Console‏ (console.cloud.google.com) ויוצרים פרויקט חדש:

חשוב לזכור את מזהה הפרויקט, שהוא שם ייחודי בכל הפרויקטים ב-Google Cloud (השם שמופיע למעלה כבר תפוס ולא יתאים לכם, מצטערים!). בהמשך ה-codelab הזה נתייחס אליו בתור PROJECT_ID.

חיוב

בשלב הבא, תצטרכו להפעיל את החיוב ב-Cloud Console כדי להשתמש במשאבים של Google Cloud.

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

משתמשים חדשים ב-Google Cloud Platform זכאים לתקופת ניסיון בחינם בשווי 300$.

אפשר להפעיל את Google Cloud מרחוק מהמחשב הנייד, אבל ב-codelab הזה נשתמש ב-Google Cloud Shell, סביבת שורת פקודה שפועלת ב-Cloud. המכונה הווירטואלית הזו מבוססת על Debian, וטעונים בה כל הכלים הדרושים למפתחים (gcloud, ‏ python, ‏ virtualenv,‏ pip ועוד). היא מציעה ספריית בית בעלת אחסון מתמיד בגודל 5GB, והיא פועלת ב-Google Cloud, מה שמשפר מאוד את ביצועי הרשת והאימות. כלומר, כל מה שצריך בשביל ה-codelab הזה הוא דפדפן (כן, הוא עובד ב-Chromebook).

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

אחרי שמתחברים ל-Cloud Shell, אמור להופיע אימות שכבר בוצע ושהפרויקט כבר הוגדר לפי PROJECT_ID:

gcloud auth list
Credentialed accounts:
- <myaccount>@<mydomain>.com (active)
gcloud config list project
[core]
Project = <PROJECT_ID>

אם מסיבה כלשהי הפרויקט לא מוגדר, פשוט מריצים את הפקודה הבאה:

gcloud config set project <PROJECT_ID>

מחפשים את PROJECT_ID? כדאי לבדוק באיזה מזהה פרויקט השתמשתם בשלבי ההגדרה, או לחפש אותו בלוח הבקרה של המסוף:

ב-Cloud Shell, בשורת הפקודה, מריצים את הפקודה הבאה כדי לשכפל את מאגר Github:

git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

עוברים לספרייה python-docs-samples/codelabs/flex_and_vision:

cd python-docs-samples/codelabs/flex_and_vision

כדי שנוכל להתחיל להשתמש בממשקי ה-API של Vision,‏ Storage ו-Datastore, צריך להפעיל אותם באמצעות הפקודות הבאות:

gcloud services enable vision.googleapis.com
gcloud services enable storage-component.googleapis.com
gcloud services enable datastore.googleapis.com

כדי לשלוח בקשות לממשקי Vision,‏ Storage ו-Datastore API, תצטרכו פרטי כניסה לחשבון שירות. אפשר ליצור פרטי כניסה של חשבון שירות מהפרויקט באמצעות הכלי gcloud.

מגדירים משתנה סביבה ל-PROJECT_ID, ומחליפים את [YOUR_PROJECT_ID] במזהה הפרויקט שלכם:

export PROJECT_ID=[YOUR_PROJECT_ID]

יוצרים חשבון שירות כדי לגשת ל-Google Cloud APIs כשבודקים באופן מקומי:

gcloud iam service-accounts create codelab \
  --display-name "My Codelab Service Account"

נותנים לחשבון השירות החדש שנוצר את ההרשאות המתאימות:

gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member serviceAccount:codelab@${PROJECT_ID}.iam.gserviceaccount.com \
--role roles/owner

אחרי שיוצרים חשבון שירות, יוצרים מפתח לחשבון השירות:

gcloud iam service-accounts keys create ~/key.json \
--iam-account codelab@${PROJECT_ID}.iam.gserviceaccount.com

הפקודה הזו יוצרת מפתח של חשבון שירות שמאוחסן בקובץ JSON בשם key.json בספריית הבית.

משתמשים בנתיב המוחלט של המפתח שנוצר כדי להגדיר משתנה סביבה למפתח של חשבון השירות ב-Cloud Shell:

export GOOGLE_APPLICATION_CREDENTIALS="/home/${USER}/key.json"

מידע נוסף על אימות Vision API

הפעלת הסביבה הווירטואלית והתקנת תלות

יוצרים סביבת Python 3 מבודדת בשם env באמצעות virtualenv:

virtualenv -p python3 env

מזינים את virtualenv החדש שנוצר בשם env:

source env/bin/activate

משתמשים ב-pip כדי להתקין תלות עבור הפרויקט מקובץ requirements.txt:

pip install -r requirements.txt

קובץ requirements.txt הוא רשימה של תלות בחבילות שנדרשות לפרויקט. הפקודה שלמעלה הורידה את כל התלויות של החבילות שצוינו אל virtualenv.

יצירת אפליקציית App Engine

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

gcloud app create

יצירת קטגוריית אחסון

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

export CLOUD_STORAGE_BUCKET=${PROJECT_ID}

האפליקציה שלנו משתמשת בקטגוריה של Cloud Storage, ותצטרכו ליצור אותה מ-Cloud Shell באמצעות כלי שנקרא gsutil. מריצים את הפקודה הבאה, שיוצרת קטגוריה עם אותו שם כמו PROJECT_ID.

gsutil mb gs://${PROJECT_ID}

הפעלת האפליקציה

python main.py

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

תיפתח כרטיסייה בדפדפן ותתבצע התחברות לשרת שהפעלתם. אתם אמורים לראות משהו כזה:

Screen Shot 2017-02-23 at 7.22.50 PM.png

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

אחרי העלאת תמונה, אתם אמורים לראות משהו כזה:

Screen Shot 2017-02-23 at 7.32.08 PM.png

פריסת קוד לדוגמה

הפריסה של הדוגמה היא כזו:

templates/
  homepage.html   /* HTML template that uses Jinja2 */
app.yaml          /* App Engine application configuration file */
main.py           /* Python Flask web application */
requirements.txt  /* List of dependencies for the project */

main.py

קובץ ה-Python הזה הוא אפליקציית אינטרנט של Flask. האפליקציה מאפשרת למשתמשים לשלוח תמונות (רצוי של פנים), שנשמרות ב-Cloud Storage ומנותחות באמצעות התכונה לזיהוי פנים של Cloud Vision API. מידע מרכזי על כל תמונה מאוחסן ב-Datastore, מסד הנתונים NoSQL של Google Cloud Platform, ומתבצעת אליו גישה בכל פעם שמשתמש מבקר באתר.

האפליקציה הזו משתמשת בספריות הלקוח של Google Cloud Platform עבור Storage,‏ Datastore ו-Vision. ספריות הלקוח האלה מאפשרות לגשת בקלות ל-Cloud APIs משפות התכנות האהובות עליכם.

בואו נסתכל על כמה קטעי קוד חשובים.

בקטע Imports (ייבוא) בחלק העליון, אנחנו מייבאים את החבילות השונות שדרושות לקוד שלנו. כך מייבאים את ספריות הלקוח של Google Cloud ל-Datastore, ל-Storage ול-Vision:

from google.cloud import datastore
from google.cloud import storage
from google.cloud import vision

זה הקוד שמופעל כשמשתמש מבקר בכתובת ה-URL הבסיסית של האתר. אנחנו יוצרים אובייקט לקוח Datastore, שמשמש לגישה לספריית הלקוח Datastore. לאחר מכן אנחנו מריצים שאילתה ב-Datastore לגבי ישויות מסוג Faces. לבסוף, אנחנו מעבדים את תבנית ה-HTML שלנו, ומעבירים את image_entities שחולצו מ-Datastore כמשתנה.

@app.route('/')
def homepage():
    # Create a Cloud Datastore client.
    datastore_client = datastore.Client()

    # Use the Cloud Datastore client to fetch information from Datastore about
    # each photo.
    query = datastore_client.query(kind='Faces')
    image_entities = list(query.fetch())

    # Return a Jinja2 HTML template and pass in image_entities as a parameter.
    return render_template('homepage.html', image_entities=image_entities)

בואו נראה איך ישויות נשמרות ב-Datastore. ‫Datastore הוא פתרון מסד נתונים NoSQL של Google Cloud. הנתונים מאוחסנים באובייקטים שנקראים ישויות. לכל ישות מוקצה מפתח ייחודי, שאפשר ליצור באמצעות סוג ומחרוזת של שם מפתח. סוג הוא מאגר ארגוני של סוג הישות. לדוגמה, יכול להיות שנרצה להגדיר סוגים לתמונות, לאנשים ולבעלי חיים.

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

    # Create a Cloud Datastore client.
    datastore_client = datastore.Client()

    # Fetch the current date / time.
    current_datetime = datetime.now()

    # The kind for the new entity.
    kind = 'Faces'

    # The name/ID for the new entity.
    name = blob.name

    # Create the Cloud Datastore key for the new entity.
    key = datastore_client.key(kind, name)

    # Construct the new entity using the key. Set dictionary values for entity
    # keys blob_name, storage_public_url, timestamp, and joy.
    entity = datastore.Entity(key)
    entity['blob_name'] = blob.name
    entity['image_public_url'] = blob.public_url
    entity['timestamp'] = current_datetime
    entity['joy'] = face_joy

    # Save the new entity to Datastore.
    datastore_client.put(entity)

אפשר לגשת לספריות הלקוח של Storage ו-Vision באופן פרוגרמטי, בדומה ל-Datastore. אפשר לפתוח את הקובץ main.py בעצמכם באמצעות vim,‏ emacs או nano כדי לעיין בכל קוד הדוגמה.

מידע נוסף על Flask זמין בכתובת http://flask.pocoo.org/.

מידע נוסף על ספריות לקוח זמין בכתובת https://googlecloudplatform.github.io/google-cloud-python/.

homepage.html

מסגרת האינטרנט Flask משתמשת ב-Jinja2 כמנוע תבניות. כך אנחנו יכולים להעביר משתנים וביטויים מ-main.py אל homepage.html, ולקבל ערכים במקום המשתנים והביטויים האלה אחרי שהדף מעובד.

מידע נוסף על Jinja2 זמין בכתובת http://jinja.pocoo.org/docs/2.9/templates/.

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

homepage.html

<h1>Google Cloud Platform - Face Detection Sample</h1>

<p>This Python Flask application demonstrates App Engine Flexible, Google Cloud
Storage, Datastore, and the Cloud Vision API.</p>

<br>

<html>
  <body>
    <form action="upload_photo" method="POST" enctype="multipart/form-data">
      Upload File: <input type="file" name="file"><br>
      <input type="submit" name="submit" value="Submit">
    </form>
    
  </body>
</html>

‫App Engine Flexible משתמש בקובץ שנקרא app.yaml כדי לתאר את הגדרות הפריסה של אפליקציה. אם הקובץ הזה לא קיים, App Engine ינסה לנחש את הגדרות הפריסה. עם זאת, כדאי לספק את הקובץ הזה.

לאחר מכן, תשנו את app.yaml באמצעות עורך שתבחרו, כמו vim, ‏nano או emacs. נשתמש בעורך nano:

nano app.yaml

app.yaml

runtime: python
env: flex
entrypoint: gunicorn -b :$PORT main:app

runtime_config:
    python_version: 3

env_variables:
    CLOUD_STORAGE_BUCKET: <your-cloud-storage-bucket>

זו ההגדרה הבסיסית שנדרשת כדי לפרוס אפליקציית Python 3 App Engine Flex. כאן אפשר לקרוא מידע נוסף על הגדרת App Engine.

אחרי שפותחים את app.yaml, מחליפים את < your-cloud-storage-bucket > בשם של הקטגוריה ב-Cloud Storage. (אם שכחתם את השם של הקטגוריה שלכם ב-Cloud Storage, אפשר להעתיק את מזהה הפרויקט ב-GCP מ-Qwiklabs, שהוא זהה). בקטע env_variables מוגדרים משתני סביבה שישמשו בקובץ main.py אחרי שהאפליקציה תופעל.

עכשיו אפשר לסגור ולשמור את הקובץ ב-nano באמצעות (Ctrl + x), ותוצג ההודעה הבאה:

Screen Shot 2017-02-17 at 4.47.12 PM.png

כותבים את האות y ואז מקישים על המקש ENTER פעם נוספת כדי לאשר את שם הקובץ בהנחיה הבאה:

Screen Shot 2017-02-24 at 4.18.23 PM.png

פורסים את האפליקציה ב-App Engine באמצעות gcloud:

gcloud app deploy

אחרי פריסת האפליקציה, אפשר להיכנס אליה על ידי פתיחת כתובת ה-URL https://< PROJECT_ID >.appspot.com בדפדפן האינטרנט.

סיכום

בשלב הזה, מגדירים אפליקציית אינטרנט ב-Python ומפרסים אותה בסביבה הגמישה של App Engine.

למדתם איך לכתוב ולפרוס את אפליקציית האינטרנט הראשונה שלכם ב-App Engine Flexible.

הסרת המשאבים

כדי להימנע מחיובים בחשבון Google Cloud Platform על המשאבים שבהם השתמשתם במדריך למתחילים הזה:

  • עוברים אל Cloud Platform Console.
  • בוחרים את הפרויקט שרוצים לסגור ולוחצים על 'מחיקה' בחלק העליון. הפעולה הזו מתזמנת את הפרויקט למחיקה.

מידע נוסף

רישיון

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