۱. مرور کلی
مجموعه آزمایشگاههای کد Serverless Migration Station (آموزشهای عملی و خودآموز) و ویدیوهای مرتبط با آن ، با هدف کمک به توسعهدهندگان Google Cloud serverless برای مدرنسازی برنامههایشان، با راهنمایی آنها در طول یک یا چند مهاجرت، و در درجه اول دور شدن از سرویسهای قدیمی، ارائه میشوند. انجام این کار، برنامههای شما را قابل حملتر میکند و گزینهها و انعطافپذیری بیشتری به شما میدهد و شما را قادر میسازد تا با طیف وسیعتری از محصولات Cloud ادغام شده و به آنها دسترسی داشته باشید و به راحتی به نسخههای جدیدتر زبان ارتقا دهید. در حالی که در ابتدا بر روی اولین کاربران Cloud، در درجه اول توسعهدهندگان App Engine (محیط استاندارد)، تمرکز دارد، این مجموعه به اندازه کافی گسترده است که شامل سایر پلتفرمهای serverless مانند Cloud Functions و Cloud Run یا در صورت لزوم، هر جای دیگری نیز میشود.
این آزمایشگاه کد به شما آموزش میدهد که چگونه از App Engine Blobstore به Cloud Storage مهاجرت کنید. همچنین مهاجرتهای ضمنی از موارد زیر نیز وجود دارد:
- چارچوب وب
webapp2به Flask (که در ماژول 1 پوشش داده شده است) - اتصال NDB موتور برنامه به NDB ابری برای دسترسی به پایگاه داده (که در ماژول 2 پوشش داده شده است)
- پایتون ۲ به ۳ (برنامهی منتقلشده با پایتون ۲ و ۳ سازگار است)
برای اطلاعات گام به گام بیشتر، به هر یک از ماژولهای مهاجرت مرتبط مراجعه کنید.
یاد خواهید گرفت که چگونه
- استفاده از API/کتابخانهی App Engine Blobstore را اضافه کنید
- ذخیره آپلودهای کاربر در سرویس Blobstore
- برای مرحله بعدی مهاجرت به فضای ذخیرهسازی ابری آماده شوید
آنچه نیاز دارید
- یک پروژه پلتفرم ابری گوگل با یک حساب پرداخت فعال GCP
- مهارتهای پایه پایتون
- آشنایی کامل با دستورات رایج لینوکس
- دانش پایه در توسعه و استقرار برنامههای App Engine
- یک برنامهی ماژول ۱۵ که کار میکند: کدلب ماژول ۱۵ (توصیه میشود) را تکمیل کنید یا برنامهی ماژول ۱۵ را از مخزن کپی کنید
نظرسنجی
چگونه از این آموزش استفاده خواهید کرد؟
تجربه خود را با پایتون چگونه ارزیابی میکنید؟
تجربه خود را در استفاده از خدمات ابری گوگل چگونه ارزیابی میکنید؟
۲. پیشینه
این آزمایشگاه کد با برنامه نمونه از ماژول ۱۵ شروع میشود و نحوه مهاجرت از Blobstore (و NDB) به Cloud Storage (و Cloud NDB) را نشان میدهد. فرآیند مهاجرت شامل جایگزینی وابستگیها در سرویسهای همراه قدیمی App Engine است که به شما امکان میدهد برنامههای خود را در صورت تمایل به یک پلتفرم بدون سرور Cloud یا پلتفرم میزبانی دیگر منتقل کنید.
این مهاجرت در مقایسه با سایر مهاجرتهای این مجموعه به تلاش بیشتری نیاز دارد. Blobstore به چارچوب اصلی webapp وابستگی دارد و به همین دلیل است که برنامه نمونه به جای Flask از چارچوب webapp2 استفاده میکند. این آموزش شامل مهاجرت به Cloud Storage، Cloud NDB، Flask و Python 3 است.
این برنامه هنوز «بازدیدهای» کاربر نهایی را ثبت میکند و ده مورد آخر را نمایش میدهد، اما codelab قبلی (ماژول ۱۵) قابلیت جدیدی را برای تطبیق با استفاده از Blobstore اضافه کرده است: برنامه از کاربران نهایی میخواهد که یک مصنوع (یک فایل) مربوط به «بازدید» خود را آپلود کنند. کاربران میتوانند این کار را انجام دهند یا برای انصراف، «رد شدن» را انتخاب کنند. صرف نظر از تصمیم کاربر، صفحه بعد همان خروجی نسخههای قبلی این برنامه را ارائه میدهد و جدیدترین بازدیدها را نمایش میدهد. یک تغییر دیگر این است که بازدیدهایی با مصنوعات مربوطه، دارای یک لینک «مشاهده» برای نمایش مصنوع بازدید هستند. این codelab مهاجرتهای ذکر شده قبلی را پیادهسازی میکند و در عین حال عملکرد شرح داده شده را حفظ میکند.
۳. تنظیمات/پیشپردازش
قبل از اینکه به بخش اصلی آموزش برسیم، بیایید پروژه خود را راهاندازی کنیم، کد را دریافت کنیم، سپس برنامه پایه را مستقر کنیم تا بدانیم که با کد کار را شروع کردهایم.
۱. پروژه راهاندازی
اگر قبلاً برنامه ماژول ۱۵ را مستقر کردهاید، توصیه میکنیم از همان پروژه (و کد) دوباره استفاده کنید. همچنین میتوانید یک پروژه کاملاً جدید ایجاد کنید یا از یک پروژه موجود دیگر دوباره استفاده کنید. مطمئن شوید که پروژه دارای یک حساب صورتحساب فعال است و App Engine فعال است.
۲. نمونه برنامه پایه را دریافت کنید
یکی از پیشنیازهای این آزمایشگاه کد، داشتن یک برنامه نمونه ماژول ۱۵ است که کار کند. اگر آن را ندارید، میتوانید آن را از پوشه "START" ماژول ۱۵ (لینک زیر) دریافت کنید. این آزمایشگاه کد، شما را در هر مرحله راهنمایی میکند و در پایان، کدی مشابه آنچه در پوشه "FINISH" ماژول ۱۶ وجود دارد، ارائه میدهد.
- شروع: پوشه ماژول ۱۵ (پایتون ۲)
- پایان: پوشه ماژول ۱۶ (پایتون ۲)
- کل مخزن (برای کلون کردن یا دانلود فایل زیپ )
دایرکتوری فایلهای STARTING ماژول ۱۵ باید به شکل زیر باشد:
$ ls README.md app.yaml main-gcs.py main.py templates
فایل main-gcs.py یک نسخه جایگزین از main.py از ماژول ۱۵ است که امکان انتخاب یک باکت ذخیرهسازی ابری متفاوت از پیشفرض URL اختصاص داده شده به برنامه را بر اساس شناسه پروژه فراهم میکند: PROJECT_ID .appspot.com . این فایل هیچ نقشی در این codelab (ماژول ۱۶) ندارد، به جز اینکه در صورت تمایل میتوان تکنیکهای مهاجرت مشابه را روی آن فایل اعمال کرد.
۳. (دوباره) استقرار برنامه پایه
مراحل مقدماتی باقی مانده برای اجرا:
- با ابزار خط فرمان
gcloudدوباره آشنا شوید - برنامه نمونه را با استفاده از
gcloud app deployدوباره مستقر کنید - تأیید کنید که برنامه بدون مشکل در App Engine اجرا میشود.
وقتی این مراحل را با موفقیت انجام دادید و از کارکرد برنامه ماژول ۱۵ خود اطمینان حاصل کردید، صفحه اولیه با فرمی به کاربران خوشامد میگوید که از آنها میخواهد فایل مصنوع بازدید را به همراه یک گزینه، یعنی دکمه «رد شدن»، آپلود کنند تا از این فرآیند صرف نظر کنند:

به محض اینکه کاربران فایلی را آپلود کنند یا از آن صرف نظر کنند، برنامه صفحه آشنای «آخرین بازدیدها» را نمایش میدهد:

بازدیدهایی که شامل یک مصنوع (artifact) هستند، یک لینک «مشاهده» در سمت راست مهر زمانی بازدید برای نمایش (یا دانلود) مصنوع خواهند داشت. پس از تأیید عملکرد برنامه، آماده مهاجرت از سرویسهای قدیمی App Engine (webapp2، NDB، Blobstore) به جایگزینهای معاصر (Flask، Cloud NDB، Cloud Storage) خواهید بود.
۴. بهروزرسانی فایلهای پیکربندی
سه فایل پیکربندی برای نسخه بهروز شده برنامه ما اجرا میشوند. وظایف مورد نیاز عبارتند از:
- کتابخانههای شخص ثالث داخلی مورد نیاز را در
app.yamlبهروزرسانی کنید و همچنین در را برای مهاجرت به پایتون ۳ باز بگذارید. - یک
requirements.txtاضافه کنید که تمام کتابخانههای مورد نیاز که داخلی نیستند را مشخص میکند. -
appengine_config.pyرا اضافه کنید تا برنامه از کتابخانههای شخص ثالث داخلی و خارجی پشتیبانی کند.
برنامه.yaml
فایل app.yaml خود را با بهروزرسانی بخش libraries ویرایش کنید. jinja2 را حذف کرده و grpcio ، setuptools و ssl را اضافه کنید. آخرین نسخه موجود برای هر سه کتابخانه را انتخاب کنید. همچنین دستورالعمل runtime پایتون ۳ را اضافه کنید، اما به صورت کامنت. وقتی کارتان تمام شد، باید به این شکل باشد (اگر پایتون ۳.۹ را انتخاب کردهاید):
قبل از:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
بعد از:
#runtime: python39
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: grpcio
version: latest
- name: setuptools
version: latest
- name: ssl
version: latest
این تغییرات عمدتاً مربوط به کتابخانههای داخلی پایتون ۲ موجود در سرورهای App Engine است (بنابراین لازم نیست خودتان آنها را دسته بندی کنید). ما Jinja2 را حذف کردیم زیرا با Flask همراه است که قرار است آن را به reqs.txt اضافه کنیم. هر زمان که از کتابخانههای کلاینت Google Cloud، مانند کتابخانههای Cloud NDB و Cloud Storage، استفاده میشود، grpcio و setuptools مورد نیاز هستند. در نهایت، خود Cloud Storage به کتابخانه ssl نیاز دارد. دستورالعمل زمان اجرا که در بالا کامنت گذاری شده است، برای زمانی است که شما آماده انتقال این برنامه به پایتون ۳ هستید. ما این موضوع را در پایان این آموزش پوشش خواهیم داد.
الزامات.txt
یک فایل requirements.txt اضافه کنید که به چارچوب Flask و کتابخانههای کلاینت Cloud NDB و Cloud Storage نیاز دارد، که هیچکدام از آنها داخلی نیستند. فایل را با این محتوا ایجاد کنید:
flask
google-cloud-ndb
google-cloud-storage
موتور اجرای پایتون ۲ (Python 2 App Engine) نیاز به بستهبندی خودکار کتابخانههای شخص ثالث غیر داخلی دارد، بنابراین دستور زیر را برای نصب این کتابخانهها در پوشه lib اجرا کنید:
pip install -t lib -r requirements.txt
اگر هم پایتون ۲ و هم پایتون ۳ را روی دستگاه توسعه خود دارید، ممکن است مجبور شوید از دستور pip2 برای اطمینان از دریافت نسخههای پایتون ۲ این کتابخانهها استفاده کنید. پس از ارتقا به پایتون ۳، دیگر نیازی به بستهبندی خودکار ندارید.
appengine_config.py
یک فایل 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)
مراحلی که به تازگی انجام شدهاند باید مشابه یا یکسان با مراحل ذکر شده در بخش «نصب کتابخانهها برای برنامههای پایتون ۲» در مستندات App Engine باشند، و به طور خاصتر، محتویات appengine_config.py باید با آنچه در مرحله ۵ آمده است، مطابقت داشته باشد.
کار روی فایلهای پیکربندی تمام شد، پس بیایید به سراغ برنامه برویم.
۵. فایلهای برنامه را تغییر دهید
واردات
اولین مجموعه تغییرات برای main.py شامل تعویض تمام موارد جایگزین شده است. در اینجا مواردی که تغییر میکنند را مشاهده میکنید:
-
webapp2با Flask جایگزین شده است. - به جای استفاده از Jinja2 از
webapp2_extras، از Jinja2 که همراه با Flask ارائه میشود استفاده کنید. - موتور برنامه، Blobstore و NDB با Cloud NDB و Cloud Storage جایگزین شدهاند.
- هندلرهای Blobstore در
webappبا ترکیبی از ماژول کتابخانه استانداردio، ابزارهای Flask وwerkzeugجایگزین شدهاند. - به طور پیشفرض، Blobstore در یک مخزن ذخیرهسازی ابری که نام آن از URL برنامه شما (
PROJECT_ID.appspot.com) گرفته شده است، مینویسد. از آنجا که ما در حال انتقال به کتابخانه کلاینت ذخیرهسازی ابری هستیم،google.authبرای دریافت شناسه پروژه و مشخص کردن دقیقاً همان نام مخزن استفاده میشود. (از آنجایی که دیگر کدنویسی نشده است، میتوانید نام مخزن را تغییر دهید.)
قبل از:
import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers
تغییرات لیست بالا را با جایگزینی بخش import فعلی در main.py با قطعه کد زیر پیادهسازی کنید.
بعد از:
import io
from flask import (Flask, abort, redirect, render_template,
request, send_file, url_for)
from werkzeug.utils import secure_filename
import google.auth
from google.cloud import exceptions, ndb, storage
مقداردهی اولیه و پشتیبانی غیرضروری از Jinja2
بلوک کد بعدی که باید جایگزین شود، BaseHandler است که استفاده از Jinja2 را از webapp2_extras مشخص میکند. این مورد غیرضروری است زیرا Jinja2 همراه با Flask ارائه میشود و موتور قالببندی پیشفرض آن است، بنابراین آن را حذف کنید.
در سمت ماژول ۱۶، اشیاء را که در برنامه قدیمیتر نداشتیم، نمونهسازی میکنیم. این شامل مقداردهی اولیه برنامه Flask و ایجاد کلاینتهای API برای Cloud NDB و Cloud Storage میشود. در نهایت، نام باکت Cloud Storage را همانطور که در بخش importها در بالا توضیح داده شد، کنار هم قرار میدهیم. در اینجا قبل و بعد از پیادهسازی این بهروزرسانیها آمده است:
قبل از:
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))
بعد از:
app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID
بهروزرسانی دسترسی به پایگاه داده
Cloud NDB عمدتاً با App Engine NDB سازگار است. یکی از تفاوتهایی که قبلاً به آن پرداخته شد، نیاز به یک کلاینت API است. تفاوت دیگر این است که مورد دوم نیاز به کنترل دسترسی به Datastore توسط مدیر زمینه پایتون کلاینت API دارد. اساساً، این بدان معناست که تمام فراخوانیهای دسترسی به Datastore با استفاده از کتابخانه کلاینت Cloud NDB فقط میتوانند در پایتون with بلوکها انجام شوند.
این یک تغییر است؛ تغییر دیگر این است که Blobstore و اشیاء آن، مثلاً BlobKey ها، توسط Cloud Storage پشتیبانی نمیشوند، بنابراین file_blob به ndb.StringProperty تغییر دهید. در زیر کلاس مدل داده و توابع بهروز شده store_visit() و fetch_visits() که این تغییرات را منعکس میکنند، آمده است:
قبل از:
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)
بعد از:
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
file_blob = ndb.StringProperty()
def store_visit(remote_addr, user_agent, upload_key):
'create new Visit entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent),
file_blob=upload_key).put()
def fetch_visits(limit):
'get most recent visits'
with ds_client.context():
return Visit.query().order(-Visit.timestamp).fetch(limit)
در اینجا تصویری از تغییراتی که تاکنون ایجاد شده است را مشاهده میکنید:

بهروزرسانی هندلرها
کنترل کننده آپلود
هندلرها در webapp2 کلاس هستند در حالی که در Flask تابع هستند. به جای یک متد فعل HTTP، Flask از فعل برای تزئین تابع استفاده میکند. Blobstore و هندلرهای webapp آن با قابلیتهایی از Cloud Storage و همچنین Flask و ابزارهای آن جایگزین شدهاند:
قبل از:
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)
بعد از:
@app.route('/upload', methods=['POST'])
def upload():
'Upload blob (POST) handler'
fname = None
upload = request.files.get('file', None)
if upload:
fname = secure_filename(upload.filename)
blob = gcs_client.bucket(BUCKET).blob(fname)
blob.upload_from_file(upload, content_type=upload.content_type)
store_visit(request.remote_addr, request.user_agent, fname)
return redirect(url_for('root'), code=307)
چند نکته در مورد این بهروزرسانی:
- به جای
blob_id، مصنوعات فایل اکنون در صورت وجود با نام فایل (fname) و در غیر این صورتNone(هیچکدام) شناسایی میشوند (کاربر از آپلود فایل انصراف داده است). - کنترلکنندههای Blobstore فرآیند آپلود را از کاربران خود جدا میکردند، اما Cloud Storage این کار را نمیکند، بنابراین میتوانید کد تازه اضافه شده را که شیء blob فایل و مکان (bucket) و همچنین فراخوانی که آپلود واقعی را انجام میدهد (
upload_from_file()) را تنظیم میکند، مشاهده کنید. -
webapp2از یک جدول مسیریابی در پایین فایل برنامه استفاده میکند در حالی که مسیرهای Flask در هر handler تزئین شده یافت میشوند. - هر دو کنترلکننده با هدایت به home (
/) و حفظ درخواستPOSTبا کد بازگشتی HTTP 307، عملکرد خود را به پایان میرسانند.
دانلود هندلر
بهروزرسانی کنترلکنندهی دانلود از الگویی مشابه کنترلکنندهی آپلود پیروی میکند، فقط کد بسیار کمتری برای بررسی وجود دارد. قابلیتهای Blobstore و webapp را با معادلهای Cloud Storage و Flask جایگزین کنید:
قبل از:
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)
بعد از:
@app.route('/view/<path:fname>')
def view(fname):
'view uploaded blob (GET) handler'
blob = gcs_client.bucket(BUCKET).blob(fname)
try:
media = blob.download_as_bytes()
except exceptions.NotFound:
abort(404)
return send_file(io.BytesIO(media), mimetype=blob.content_type)
نکاتی در مورد این بهروزرسانی:
- باز هم، فلسک توابع هندلر را با مسیرشان تزئین میکند در حالی که
webappاین کار را در یک جدول مسیریابی در پایین انجام میدهد، بنابراین سینتکس تطبیق الگوی دومی('/view/([^/]+)?') را در مقابل سینتکس فلسک ('/view/<path:fname>') تشخیص دهید. - همانند کنترلکننده آپلود، در سمت ذخیرهسازی ابری برای عملکردهایی که توسط کنترلکنندههای Blobstore خلاصه شدهاند، کار بیشتری لازم است، یعنی شناسایی فایل (blob) مورد نظر و دانلود صریح فایل باینری در مقابل فراخوانی تکی متد
send_blob()کنترلکننده Blobstore. - در هر دو مورد، اگر مصنوع یافت نشود، خطای HTTP 404 به کاربر بازگردانده میشود.
متصدی اصلی
آخرین تغییرات در برنامه اصلی در هندلر اصلی (main handler) رخ میدهد. متدهای فعل HTTP webapp2 با یک تابع واحد که عملکرد آنها را ترکیب میکند، جایگزین میشوند. کلاس MainHandler را با تابع root() جایگزین کنید و جدول مسیریابی webapp2 را همانطور که در زیر نشان داده شده است، حذف کنید:
قبل از:
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)
بعد از:
@app.route('/', methods=['GET', 'POST'])
def root():
'main application (GET/POST) handler'
context = {}
if request.method == 'GET':
context['upload_url'] = url_for('upload')
else:
context['visits'] = fetch_visits(10)
return render_template('index.html', **context)
به جای اینکه متدهای get() و post() از هم جدا کنیم، اساساً یک عبارت if-else در root() هستند. همچنین، از آنجایی که root() یک تابع واحد است، فقط یک فراخوانی برای رندر کردن قالب برای GET و POST وجود دارد، در حالی که این کار در webapp2 واقعاً امکانپذیر نیست.
در اینجا یک نمایش تصویری از این مجموعه دوم و نهایی تغییرات در main.py آورده شده است:

(اختیاری) "بهبود" سازگاری با نسخههای قبلی
بنابراین راهکار ایجاد شده در بالا کاملاً کار میکند... اما فقط در صورتی که از ابتدا شروع کنید و فایلهایی که توسط Blobstore ایجاد شدهاند را نداشته باشید. از آنجا که ما برنامه را بهروزرسانی کردیم تا فایلها را به جای BlobKey با نام فایل شناسایی کند، برنامه ماژول ۱۶ تکمیل شده به همین صورت قادر به مشاهده فایلهای Blobstore نخواهد بود. به عبارت دیگر، ما در حین انجام این مهاجرت، یک تغییر ناسازگار با نسخههای قبلی ایجاد کردیم. اکنون یک نسخه جایگزین از main.py به نام main-migrate.py (موجود در مخزن) ارائه میدهیم که سعی در پر کردن این شکاف دارد.
اولین «افزونهای» که از فایلهای ایجاد شده در Blobstore پشتیبانی میکند، یک مدل داده است که دارای یک BlobKeyProperty (علاوه بر یک StringProperty برای فایلهای ایجاد شده در Cloud Storage) است:
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() # backwards-compatibility
file_gcs = ndb.StringProperty()
ویژگی file_blob برای شناسایی فایلهای ایجاد شده توسط Blobstore استفاده میشود در حالی که file_gcs برای فایلهای Cloud Storage است. اکنون هنگام ایجاد بازدیدهای جدید، به جای file_blob ، صریحاً مقداری را در file_gcs ذخیره کنید، بنابراین store_visit کمی متفاوت به نظر میرسد:
قبل از:
def store_visit(remote_addr, user_agent, upload_key):
'create new Visit entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent),
file_blob=upload_key).put()
بعد از:
def store_visit(remote_addr, user_agent, upload_key):
'create new Visit entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent),
file_gcs=upload_key).put()
هنگام دریافت آخرین بازدیدها، دادهها را قبل از ارسال به الگو، «عادیسازی» کنید:
قبل از:
@app.route('/', methods=['GET', 'POST'])
def root():
'main application (GET/POST) handler'
context = {}
if request.method == 'GET':
context['upload_url'] = url_for('upload')
else:
context['visits'] = fetch_visits(10)
return render_template('index.html', **context)
بعد از:
@app.route('/', methods=['GET', 'POST'])
def root():
'main application (GET/POST) handler'
context = {}
if request.method == 'GET':
context['upload_url'] = url_for('upload')
else:
context['visits'] = etl_visits(fetch_visits(10))
return render_template('index.html', **context)
در مرحله بعد، وجود file_blob یا file_gcs (یا هیچکدام) را تأیید کنید. اگر فایلی موجود است، فایل موجود را انتخاب کنید و از آن شناسه استفاده کنید ( BlobKey برای فایلهای ایجاد شده توسط Blobstore یا filename برای فایلهای ایجاد شده توسط Cloud Storage). وقتی میگوییم «فایلهای ایجاد شده توسط Cloud Storage»، منظورمان فایلهایی است که با استفاده از کتابخانه کلاینت Cloud Storage ایجاد شدهاند. Blobstore همچنین در Cloud Storage نیز مینویسد، اما در این مورد، این فایلها، فایلهای ایجاد شده توسط Blobstore خواهند بود.
حالا مهمتر از آن، تابع etl_visits() که برای نرمالسازی یا ETL (استخراج، تبدیل و بارگذاری) دادهها برای کاربر نهایی استفاده میشود چیست؟ چیزی شبیه به این است:
def etl_visits(visits):
return [{
'visitor': v.visitor,
'timestamp': v.timestamp,
'file_blob': v.file_gcs if hasattr(v, 'file_gcs') \
and v.file_gcs else v.file_blob
} for v in visits]
احتمالاً شبیه چیزی است که انتظار داشتید: کد تمام بازدیدها را طی میکند و برای هر بازدید، دادههای بازدیدکننده و برچسب زمانی را کلمه به کلمه دریافت میکند، سپس بررسی میکند که آیا file_gcs یا file_blob وجود دارند یا خیر، و اگر وجود دارند، یکی از آنها را انتخاب میکند (یا اگر هیچکدام وجود ندارند، None انتخاب میکند).
در اینجا یک مثال از تفاوتهای بین main.py و main-migrate.py آورده شده است:

اگر از ابتدا و بدون فایلهای ایجاد شده توسط Blobstore شروع میکنید، main.py استفاده کنید، اما اگر در حال گذار هستید و میخواهید فایلهای ایجاد شده توسط Blobstore و Cloud Storage را پشتیبانی کنید، main-migrate.py به عنوان نمونهای از نحوه برخورد با سناریویی مانند کمک به شما در برنامهریزی مهاجرت برای برنامههای خود بررسی کنید. هنگام انجام مهاجرتهای پیچیده، احتمالاً موارد خاصی پیش میآید، بنابراین این مثال برای نشان دادن تمایل بیشتر برای مدرنسازی برنامههای واقعی با دادههای واقعی است.
۶. خلاصه/پاکسازی
این بخش، این آزمایشگاه کد را با استقرار برنامه، تأیید عملکرد آن طبق برنامه و در هر خروجی منعکسشده، به پایان میرساند. پس از اعتبارسنجی برنامه، مراحل پاکسازی را انجام داده و مراحل بعدی را در نظر بگیرید.
استقرار و تأیید برنامه
قبل از استقرار مجدد برنامه، حتماً pip install -t lib -r requirements.txt را اجرا کنید تا کتابخانههای شخص ثالثِ خود-بستهبندیشده در پوشه lib قرار گیرند. اگر میخواهید راهحل سازگار با نسخههای قبلی را اجرا کنید، ابتدا main-migrate.py را به main.py تغییر نام دهید. اکنون gcloud app deploy اجرا کنید و تأیید کنید که برنامه دقیقاً مانند برنامه ماژول ۱۵ کار میکند. صفحه فرم به این شکل خواهد بود:

صفحه آخرین بازدیدها به این شکل است:

تبریک میگویم که این کد را با جایگزینی App Engine Blobstore با Cloud Storage، App Engine NDB با Cloud NDB و webapp2 با Flask تکمیل کردید. اکنون کد شما باید با آنچه در پوشه FINISH (ماژول ۱۶) است مطابقت داشته باشد. فایل جایگزین main-migrate.py نیز در آن پوشه موجود است.
پایتون ۳ "مهاجرت"
دستورالعمل runtime پایتون ۳ که در بالای app.yaml کامنتگذاری شده است، تمام چیزی است که برای انتقال این برنامه به پایتون ۳ مورد نیاز است. خود کد منبع از قبل با پایتون ۳ سازگار است، بنابراین نیازی به تغییر در آن نیست. برای استقرار این برنامه به عنوان یک برنامه پایتون ۳، مراحل زیر را انجام دهید:
- دستور
runtimeپایتون ۳ را در بالایapp.yamlاز حالت کامنت خارج کنید. - تمام خطوط دیگر را در
app.yamlحذف کنید. - فایل
appengine_config.pyرا حذف کنید. (در زمان اجرای پایتون ۳ استفاده نشده است) - در صورت وجود، پوشه
libرا حذف کنید. (با پایتون ۳ در زمان اجرا غیر ضروری است)
تمیز کردن
عمومی
اگر فعلاً کارتان تمام است، توصیه میکنیم برنامه App Engine خود را غیرفعال کنید تا از پرداخت هزینه جلوگیری شود. با این حال، اگر میخواهید بیشتر آزمایش یا تجربه کنید، پلتفرم App Engine سهمیه رایگان دارد و بنابراین تا زمانی که از آن سطح استفاده تجاوز نکنید، نباید هزینهای از شما دریافت شود. این هزینه برای محاسبات است، اما ممکن است برای سرویسهای مربوطه 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" خواهد بود.
از طرف دیگر، اگر قصد ندارید با این برنامه یا سایر آزمایشگاههای کد مهاجرت مرتبط ادامه دهید و میخواهید همه چیز را به طور کامل حذف کنید، پروژه خود را ببندید .
مخصوص این آزمایشگاه کد
سرویسهای ذکر شده در زیر مختص این codelab هستند. برای اطلاعات بیشتر به مستندات هر محصول مراجعه کنید:
- سرویس App Engine Blobstore در بخش سهمیهها و محدودیتهای دادههای ذخیرهشده قرار میگیرد، بنابراین آن را به همراه صفحه قیمتگذاری سرویسهای قدیمی همراه آن بررسی کنید.
- فضای ذخیرهسازی ابری برای مناطق خاص، یک سطح رایگان دارد؛ همچنین برای اطلاعات بیشتر به صفحه قیمتگذاری عمومی آن مراجعه کنید.
- سرویس App Engine Datastore توسط Cloud Datastore (Cloud Firestore در حالت Datastore) ارائه میشود که یک نسخه رایگان نیز دارد؛ برای اطلاعات بیشتر به صفحه قیمتگذاری آن مراجعه کنید.
توجه داشته باشید که اگر از ماژول ۱۵ به ۱۶ مهاجرت کردهاید، همچنان دادهها را در Blobstore خواهید داشت، به همین دلیل اطلاعات قیمتگذاری آن را در بالا آوردهایم.
مراحل بعدی
فراتر از این آموزش، ماژولهای مهاجرت دیگری که بر دور شدن از سرویسهای همراه قدیمی تمرکز دارند، عبارتند از:
- ماژول 2 : مهاجرت از App Engine
ndbبه Cloud NDB - ماژولهای ۷-۹ : مهاجرت از وظایف صف وظایف موتور برنامه به وظایف ابری
- ماژولهای ۱۲-۱۳ : مهاجرت از App Engine Memcache به Cloud Memorystore
- ماژولهای ۱۸-۱۹ : مهاجرت از صف وظایف موتور برنامه (وظایف pull) به Cloud Pub/Sub
App Engine دیگر تنها پلتفرم بدون سرور در Google Cloud نیست. اگر یک برنامه کوچک App Engine یا برنامهای با قابلیتهای محدود دارید و میخواهید آن را به یک میکروسرویس مستقل تبدیل کنید، یا میخواهید یک برنامه یکپارچه را به چندین مؤلفه قابل استفاده مجدد تقسیم کنید، اینها دلایل خوبی برای در نظر گرفتن انتقال به Cloud Functions هستند. اگر کانتینرسازی به بخشی از گردش کار توسعه برنامه شما تبدیل شده است، به خصوص اگر شامل یک خط لوله CI/CD (ادغام مداوم/تحویل مداوم یا استقرار) باشد، مهاجرت به Cloud Run را در نظر بگیرید. این سناریوها توسط ماژولهای زیر پوشش داده میشوند:
- مهاجرت از موتور برنامه به توابع ابری: به ماژول 11 مراجعه کنید
- مهاجرت از App Engine به Cloud Run: برای کانتینرایز کردن برنامه خود با Docker به ماژول ۴ و برای انجام این کار بدون کانتینرها، دانش Docker یا
Dockerfileها به ماژول ۵ مراجعه کنید.
تغییر به یک پلتفرم بدون سرور دیگر اختیاری است و توصیه میکنیم قبل از ایجاد هرگونه تغییر، بهترین گزینهها را برای برنامهها و موارد استفاده خود در نظر بگیرید.
صرف نظر از اینکه کدام ماژول مهاجرت را در مرحله بعد در نظر بگیرید، تمام محتوای Serverless Migration Station (آزمایشگاههای کد، ویدیوها، کد منبع [در صورت وجود]) در مخزن متنباز آن قابل دسترسی است. README این مخزن همچنین راهنماییهایی در مورد اینکه کدام مهاجرتها را باید در نظر گرفت و هرگونه «ترتیب» مربوط به ماژولهای مهاجرت ارائه میدهد.
۷. منابع اضافی
مشکلات/بازخوردهای Codelab
اگر در این آزمایشگاه کد مشکلی پیدا کردید، لطفاً قبل از ثبت، ابتدا مشکل خود را جستجو کنید. لینکهای جستجو و ایجاد مشکلات جدید:
منابع مهاجرت
لینکهای پوشههای مخزن ماژول ۱۵ (START) و ماژول ۱۶ (FINISH) را میتوانید در جدول زیر پیدا کنید. همچنین میتوانید از مخزن تمام مهاجرتهای Codelab مربوط به App Engine که میتوانید آنها را کلون کنید یا یک فایل ZIP دانلود کنید، به آنها دسترسی داشته باشید.
کدلب | پایتون ۲ | پایتون ۳ |
ماژول ۱۵ | ناموجود | |
ماژول ۱۶ (این آزمایشگاه کد) | (همانند پایتون ۲) |
منابع آنلاین
در زیر منابع آنلاینی وجود دارد که ممکن است برای این آموزش مرتبط باشند:
موتور برنامه Blobstore و فضای ذخیرهسازی ابری
- سرویس اپ انجین بلاباستور
- مهاجرت به کتابخانه کلاینت ذخیرهسازی ابری
- صفحه اصلی فضای ذخیرهسازی ابری
- مستندات ذخیرهسازی ابری
پلتفرم موتور برنامه
- مستندات موتور برنامه
- موتور برنامه پایتون ۲ (محیط استاندارد) در زمان اجرا
- استفاده از کتابخانههای داخلی App Engine در Python 2 App Engine
- موتور برنامه پایتون ۳ (محیط استاندارد) در زمان اجرا
- تفاوتهای بین زمانهای اجرای موتور برنامه پایتون ۲ و ۳ (محیط استاندارد)
- راهنمای مهاجرت موتور برنامه پایتون ۲ به ۳ (محیط استاندارد)
- اطلاعات قیمتگذاری و سهمیهبندی موتور برنامه
- راهاندازی پلتفرم نسل دوم App Engine (۲۰۱۸)
- مقایسه پلتفرمهای نسل اول و دوم
- پشتیبانی بلندمدت از رانتایمهای قدیمی
- مخزن نمونههای مهاجرت مستندات
- مخزن نمونههای مهاجرت ارائه شده توسط جامعه
سایر اطلاعات ابری
- پایتون در پلتفرم ابری گوگل
- کتابخانههای کلاینت پایتون گوگل کلود
- سطح «همیشه رایگان» گوگل کلود
- کیت توسعه نرمافزار گوگل کلود (ابزار خط فرمان
gcloud) - تمام مستندات گوگل کلود
پایتون
- سیستمهای قالببندی جنگو و جینجا۲
- چارچوب وب
webapp2 - مستندات
webapp2 - پیوندهای
webapp2_extras - مستندات
webapp2_extrasدر Jinja2 - چارچوب وب فلاسک
ویدیوها
- ایستگاه مهاجرت بدون سرور
- سفرهای اکتشافی بدون سرور
- مشترک شدن در فناوری ابری گوگل
- مشترک شدن در توسعهدهندگان گوگل
مجوز
این اثر تحت مجوز عمومی Creative Commons Attribution 2.0 منتشر شده است.