App Engine Blobstore से Cloud Storage में माइग्रेट करना (मॉड्यूल 16)

1. खास जानकारी

सर्वरलेस माइग्रेशन स्टेशन की कोडलैब सीरीज़ (अपने हिसाब से सीखने और प्रैक्टिकल करने वाले ट्यूटोरियल) और इससे जुड़े वीडियो का मकसद, Google Cloud सर्वरलेस डेवलपर की मदद करना है. इससे वे एक या उससे ज़्यादा माइग्रेशन करके, अपने ऐप्लिकेशन को बेहतर बना सकते हैं. इनमें मुख्य रूप से लेगसी सेवाओं से माइग्रेट करना शामिल है. ऐसा करने से, आपके ऐप्लिकेशन को एक जगह से दूसरी जगह ले जाना आसान हो जाता है. साथ ही, आपको ज़्यादा विकल्प और सुविधा मिलती है. इससे आपको Cloud प्रॉडक्ट की ज़्यादा रेंज के साथ इंटिग्रेट करने और उन्हें ऐक्सेस करने में मदद मिलती है. साथ ही, भाषा के नए वर्शन पर आसानी से अपग्रेड किया जा सकता है. शुरुआत में, इस सीरीज़ में मुख्य तौर पर App Engine (स्टैंडर्ड एनवायरमेंट) डेवलपर के लिए कॉन्टेंट शामिल किया गया था. हालांकि, अब इसमें अन्य सर्वरलेस प्लैटफ़ॉर्म के लिए भी कॉन्टेंट शामिल किया गया है. जैसे, Cloud Functions और Cloud Run. इसके अलावा, इसमें अन्य प्लैटफ़ॉर्म के लिए भी कॉन्टेंट शामिल किया गया है.

इस कोडलैब में, आपको App Engine Blobstore से Cloud Storage पर माइग्रेट करने का तरीका बताया गया है. इनके अलावा, यहां से भी माइग्रेट किया जा सकता है:

  • webapp2 वेब फ़्रेमवर्क से Flask (Module 1 में शामिल)
  • Datastore को ऐक्सेस करने के लिए, App Engine NDB से Cloud NDB पर माइग्रेट करना (Module 2 में शामिल है)
  • Python 2 से 3 (माइग्रेट किया गया ऐप्लिकेशन, Python 2 और 3, दोनों के साथ काम करता है)

ज़्यादा जानकारी के लिए, माइग्रेशन से जुड़े किसी भी मॉड्यूल को देखें.

आपको इनके बारे में जानकारी मिलेगी

  • App Engine Blobstore API/लाइब्रेरी के इस्तेमाल के बारे में जानकारी जोड़ें
  • इस कुकी का इस्तेमाल, उपयोगकर्ता की अपलोड की गई फ़ाइलों को Blobstore सेवा में सेव करने के लिए किया जाता है
  • Cloud Storage पर माइग्रेट करने के लिए, अगले चरण की तैयारी करना

आपको इन चीज़ों की ज़रूरत होगी

सर्वे

इस ट्यूटोरियल का इस्तेमाल कैसे किया जाएगा?

सिर्फ़ इसे पढ़ें इसे पढ़ें और एक्सरसाइज़ पूरी करें

Python के साथ अपने अनुभव को आप क्या रेटिंग देंगे?

शुरुआती सामान्य एडवांस

Google Cloud की सेवाओं को इस्तेमाल करने के अपने अनुभव को आप क्या रेटिंग देंगे?

शुरुआती सामान्य एडवांस

2. बैकग्राउंड

यह कोडलैब, मॉड्यूल 15 के सैंपल ऐप्लिकेशन से शुरू होता है. इसमें Blobstore (और NDB) से Cloud Storage (और Cloud NDB) पर माइग्रेट करने का तरीका बताया गया है. माइग्रेशन की प्रोसेस में, App Engine की लेगसी बंडल की गई सेवाओं पर निर्भरता को बदलना शामिल है. इससे, अपने ऐप्लिकेशन को किसी दूसरे Cloud सर्वरलेस प्लैटफ़ॉर्म या अन्य होस्टिंग प्लैटफ़ॉर्म पर ले जाया जा सकता है.

इस सीरीज़ में मौजूद अन्य माइग्रेशन की तुलना में, इस माइग्रेशन में थोड़ी ज़्यादा मेहनत करनी पड़ती है. Blobstore, ओरिजनल webapp फ़्रेमवर्क पर निर्भर करता है. इसलिए, सैंपल ऐप्लिकेशन में Flask के बजाय webapp2 फ़्रेमवर्क का इस्तेमाल किया जाता है. इस ट्यूटोरियल में, Cloud Storage, Cloud NDB, Flask, और Python 3 पर माइग्रेट करने के बारे में बताया गया है.

ऐप्लिकेशन अब भी एंड-यूज़र की "विज़िट" रजिस्टर करता है और सबसे हाल की दस विज़िट दिखाता है. हालांकि, पिछले (मॉड्यूल 15) कोडलैब में Blobstore के इस्तेमाल के लिए नई सुविधा जोड़ी गई थी: ऐप्लिकेशन, एंड-यूज़र को उनकी "विज़िट" से जुड़ा कोई आर्टफ़ैक्ट (फ़ाइल) अपलोड करने के लिए कहता है. उपयोगकर्ता ऐसा कर सकते हैं या ऑप्ट-आउट करने के लिए "अभी नहीं" को चुन सकते हैं. उपयोगकर्ता के फ़ैसले से कोई फ़र्क़ नहीं पड़ता. अगला पेज, इस ऐप्लिकेशन के पिछले वर्शन की तरह ही आउटपुट रेंडर करता है. इसमें हाल ही की विज़िट दिखती हैं. एक और दिलचस्प बात यह है कि जिन विज़िट में कलाकृतियां शामिल होती हैं उनमें विज़िट की कलाकृति दिखाने के लिए, "देखें" लिंक होता है. इस कोडलैब में, पहले बताए गए माइग्रेशन को लागू किया गया है. साथ ही, इसमें बताई गई सुविधाओं को भी बनाए रखा गया है.

3. सेटअप/प्रीवर्क

ट्यूटोरियल के मुख्य हिस्से पर जाने से पहले, आइए हम अपना प्रोजेक्ट सेट अप करें, कोड पाएं, और फिर बेसलाइन ऐप्लिकेशन को डिप्लॉय करें, ताकि हमें पता चल सके कि हमने काम करने वाले कोड से शुरुआत की है.

1. प्रोजेक्ट सेट अप करना

अगर आपने Module 15 ऐप्लिकेशन पहले ही डिप्लॉय कर दिया है, तो हमारा सुझाव है कि आप उसी प्रोजेक्ट और कोड का फिर से इस्तेमाल करें. इसके अलावा, एक नया प्रोजेक्ट बनाया जा सकता है या किसी मौजूदा प्रोजेक्ट का फिर से इस्तेमाल किया जा सकता है. पक्का करें कि प्रोजेक्ट में, बिलिंग के लिए ऐक्टिव खाता हो और App Engine चालू हो.

2. बेसलाइन सैंपल ऐप्लिकेशन पाना

इस कोडलैब के लिए, यह ज़रूरी है कि आपके पास मॉड्यूल 15 का सैंपल ऐप्लिकेशन हो. अगर आपके पास यह ऐप्लिकेशन नहीं है, तो इसे मॉड्यूल 15 के "START" फ़ोल्डर से डाउनलोड किया जा सकता है. इसका लिंक यहां दिया गया है. इस कोडलैब में, आपको हर चरण के बारे में बताया गया है. साथ ही, इसमें ऐसा कोड भी दिया गया है जो मॉड्यूल 16 के "FINISH" फ़ोल्डर में मौजूद कोड जैसा है.

मॉड्यूल 15 की STARTing फ़ाइलों की डायरेक्ट्री ऐसी दिखनी चाहिए:

$ ls
README.md       app.yaml        main-gcs.py     main.py         templates

main-gcs.py फ़ाइल, मॉड्यूल 15 में मौजूद main.py का दूसरा वर्शन है. इससे, प्रोजेक्ट के आईडी PROJECT_ID.appspot.com के आधार पर, ऐप्लिकेशन के असाइन किए गए यूआरएल के डिफ़ॉल्ट Cloud Storage बकेट से अलग बकेट को चुना जा सकता है. इस फ़ाइल का इस (मॉड्यूल 16) कोडलैब में कोई रोल नहीं है. हालांकि, अगर चाहें, तो माइग्रेशन की इसी तरह की तकनीकों को उस फ़ाइल पर लागू किया जा सकता है.

3. बेसलाइन ऐप्लिकेशन को (फिर से) डिप्लॉय करना

अब आपको ये काम करने हैं:

  1. gcloud कमांड-लाइन टूल के बारे में फिर से जानें
  2. gcloud app deploy की मदद से, सैंपल ऐप्लिकेशन को फिर से डिप्लॉय करना
  3. पुष्टि करें कि ऐप्लिकेशन, App Engine पर बिना किसी समस्या के काम करता है

इन चरणों को पूरा करने के बाद, पुष्टि करें कि मॉड्यूल 15 का ऐप्लिकेशन काम कर रहा है. शुरुआती पेज पर, उपयोगकर्ताओं को एक फ़ॉर्म दिखता है. इसमें उन्हें विज़िट आर्टफ़ैक्ट फ़ाइल अपलोड करने के लिए कहा जाता है. साथ ही, उन्हें ऑप्ट आउट करने का विकल्प मिलता है. इसके लिए, उन्हें "छोड़ें" बटन पर क्लिक करना होता है:

f5b5f9f19d8ae978.png

जब उपयोगकर्ता कोई फ़ाइल अपलोड करते हैं या इस चरण को छोड़ देते हैं, तो ऐप्लिकेशन "हाल ही की विज़िट" वाला पेज रेंडर करता है:

f5ac6b98ee8a34cb.png

जिस विज़िट में कोई आर्टफ़ैक्ट मौजूद होगा उसमें विज़िट के टाइमस्टैंप के दाईं ओर, आर्टफ़ैक्ट को दिखाने (या डाउनलोड करने) के लिए "देखें" लिंक होगा. ऐप्लिकेशन के काम करने की पुष्टि करने के बाद, App Engine की लेगसी सेवाओं (webapp2, NDB, Blobstore) से आधुनिक विकल्पों (Flask, Cloud NDB, Cloud Storage) पर माइग्रेट किया जा सकता है.

4. कॉन्फ़िगरेशन फ़ाइलें अपडेट करना

हमारे ऐप्लिकेशन के अपडेट किए गए वर्शन के लिए, तीन कॉन्फ़िगरेशन फ़ाइलें काम करती हैं. ये काम ज़रूरी हैं:

  1. app.yaml में तीसरे पक्ष की ज़रूरी लाइब्रेरी अपडेट करें. साथ ही, Python 3 पर माइग्रेट करने का विकल्प भी उपलब्ध कराएं
  2. एक requirements.txt जोड़ें, जिसमें उन सभी ज़रूरी लाइब्रेरी के बारे में बताया गया हो जो पहले से मौजूद नहीं हैं
  3. appengine_config.py जोड़ें, ताकि ऐप्लिकेशन में बिल्ट-इन और तीसरे पक्ष की नॉन-बिल्ट-इन लाइब्रेरी, दोनों इस्तेमाल की जा सकें

app.yaml

libraries सेक्शन को अपडेट करके, अपनी app.yaml फ़ाइल में बदलाव करें. jinja2 को हटाएं और grpcio, setuptools, और ssl को जोड़ें. तीनों लाइब्रेरी के लिए उपलब्ध सबसे नया वर्शन चुनें. साथ ही, Python 3 runtime डायरेक्टिव को भी जोड़ें, लेकिन उस पर टिप्पणी की गई हो. जब यह प्रोसेस पूरी हो जाए, तो यह ऐसा दिखना चाहिए (अगर आपने Python 3.9 चुना है):

BEFORE:

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: jinja2
  version: latest

AFTER:

#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 सर्वर पर उपलब्ध Python 2 की बिल्ट-इन लाइब्रेरी से जुड़े हैं. इसलिए, आपको इन्हें खुद से बंडल करने की ज़रूरत नहीं है. हमने Jinja2 को हटा दिया है, क्योंकि यह Flask के साथ आता है. हम इसे reqs.txt में जोड़ने वाले हैं. जब भी Cloud NDB और Cloud Storage जैसी Google Cloud क्लाइंट लाइब्रेरी का इस्तेमाल किया जाता है, तब grpcio और setuptools की ज़रूरत होती है. आखिर में, Cloud Storage को ssl लाइब्रेरी की ज़रूरत होती है. सबसे ऊपर मौजूद, टिप्पणी के तौर पर लिखा गया रनटाइम डायरेक्टिव तब इस्तेमाल किया जाता है, जब आपको इस ऐप्लिकेशन को Python 3 पर पोर्ट करना हो. हम इस विषय के बारे में इस ट्यूटोरियल के आखिर में बात करेंगे.

requirements.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

अगर आपकी डेवलपमेंट मशीन पर Python 2 और 3, दोनों मौजूद हैं, तो आपको pip2 कमांड का इस्तेमाल करना पड़ सकता है. इससे यह पक्का किया जा सकेगा कि आपको इन लाइब्रेरी के Python 2 वर्शन मिलें. Python 3 पर अपग्रेड करने के बाद, आपको खुद से बंडल करने की ज़रूरत नहीं होती.

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 के दस्तावेज़ों में मौजूद Python 2 ऐप्लिकेशन के लिए लाइब्रेरी इंस्टॉल करना सेक्शन में दिए गए चरणों से मिलते-जुलते होने चाहिए. खास तौर पर, appengine_config.py का कॉन्टेंट, वहाँ दिए गए पाँचवें चरण के कॉन्टेंट से मेल खाना चाहिए.

कॉन्फ़िगरेशन फ़ाइलों पर काम पूरा हो गया है. इसलिए, अब ऐप्लिकेशन पर चलते हैं.

5. ऐप्लिकेशन की फ़ाइलों में बदलाव करना

आयात

main.py के लिए किए गए बदलावों के पहले सेट में, बदली जा रही सभी चीज़ों को स्वैप करना शामिल है. यहां बताया गया है कि क्या-क्या बदलाव किए जा रहे हैं:

  1. webapp2 की जगह Flask का इस्तेमाल किया जाता है
  2. webapp2_extras से Jinja2 का इस्तेमाल करने के बजाय, Flask के साथ आने वाले Jinja2 का इस्तेमाल करें
  3. App Engine Blobstore और NDB की जगह Cloud NDB और Cloud Storage का इस्तेमाल किया जाता है
  4. webapp में मौजूद Blobstore हैंडलर को io स्टैंडर्ड लाइब्रेरी मॉड्यूल, Flask, और werkzeug यूटिलिटी के कॉम्बिनेशन से बदल दिया गया है
  5. डिफ़ॉल्ट रूप से, Blobstore आपके ऐप्लिकेशन के यूआरएल (PROJECT_ID.appspot.com) के नाम वाली Cloud Storage बकेट में लिखता है. हम Cloud Storage क्लाइंट लाइब्रेरी पर पोर्ट कर रहे हैं. इसलिए, google.auth का इस्तेमाल प्रोजेक्ट आईडी पाने के लिए किया जाता है, ताकि बकेट का नाम बिलकुल वैसा ही हो. (बकेट का नाम बदला जा सकता है, क्योंकि अब यह हार्डकोड नहीं किया गया है.)

BEFORE:

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

ऊपर दी गई सूची में किए गए बदलावों को लागू करने के लिए, main.py में मौजूद मौजूदा इंपोर्ट सेक्शन को नीचे दिए गए कोड स्निपेट से बदलें.

AFTER:

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 है. यह webapp2_extras से Jinja2 के इस्तेमाल के बारे में बताता है. इसकी ज़रूरत नहीं है, क्योंकि Jinja2, Flask के साथ आता है और यह इसका डिफ़ॉल्ट टेंप्लेटिंग इंजन है. इसलिए, इसे हटा दें.

Module 16 में, उन ऑब्जेक्ट को इंस्टैंशिएट करें जो हमारे पुराने ऐप्लिकेशन में नहीं थे. इनमें Flask ऐप्लिकेशन को शुरू करना और Cloud NDB और Cloud Storage के लिए एपीआई क्लाइंट बनाना शामिल है. आखिर में, हम Cloud Storage बकेट का नाम एक साथ रखते हैं. इसके बारे में ऊपर इंपोर्ट सेक्शन में बताया गया है. इन अपडेट को लागू करने से पहले और बाद में, यहां दिए गए उदाहरण देखें:

BEFORE:

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))

AFTER:

app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID

Datastore के ऐक्सेस को अपडेट करना

Cloud NDB, App Engine NDB के साथ काम करता है. एपीआई क्लाइंट की ज़रूरत के बारे में पहले ही बताया जा चुका है. दूसरा अंतर यह है कि बाद वाले तरीके में, Datastore के ऐक्सेस को एपीआई क्लाइंट के Python कॉन्टेक्स्ट मैनेजर से कंट्रोल किया जाता है. इसका मतलब है कि Cloud NDB क्लाइंट लाइब्रेरी का इस्तेमाल करके, Datastore को ऐक्सेस करने के सभी कॉल सिर्फ़ Python with ब्लॉक में किए जा सकते हैं.

यह एक बदलाव है.दूसरा बदलाव यह है कि Blobstore और इसके ऑब्जेक्ट, जैसे कि BlobKey, Cloud Storage के साथ काम नहीं करते. इसलिए, file_blob को बदलकर ndb.StringProperty कर दें. यहां डेटा मॉडल क्लास और अपडेट किए गए store_visit() और fetch_visits() फ़ंक्शन दिए गए हैं. इनमें ये बदलाव दिखते हैं:

BEFORE:

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)

AFTER:

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)

अब तक किए गए बदलावों को यहां इमेज में दिखाया गया है:

a8f74ca392275822.png

हैंडलर अपडेट करना

अपलोड हैंडलर

webapp2 में हैंडलर क्लास होते हैं, जबकि Flask में ये फ़ंक्शन होते हैं. एचटीटीपी वर्ब मेथड के बजाय, Flask फ़ंक्शन को डेकोरेट करने के लिए वर्ब का इस्तेमाल करता है. Blobstore और इसके webapp हैंडलर को Cloud Storage के साथ-साथ Flask और इसकी सुविधाओं से बदल दिया गया है:

BEFORE:

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)

AFTER:

@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 ऑब्जेक्ट और जगह (बकेट) को सेट करता है. साथ ही, यह कोड उस कॉल को भी सेट करता है जो फ़ाइल को अपलोड करता है. (upload_from_file()).
  • webapp2, ऐप्लिकेशन फ़ाइल के सबसे नीचे राउटिंग टेबल का इस्तेमाल करता है. वहीं, Flask राउट हर डेकोरेटेड हैंडलर में मिलते हैं.
  • दोनों हैंडलर, एचटीटीपी 307 रिटर्न कोड के साथ POST अनुरोध को सेव करते हुए, होम पेज ( / ) पर रीडायरेक्ट करके अपनी फ़ंक्शनैलिटी को रैप-अप करते हैं.

डाउनलोड हैंडलर

डाउनलोड हैंडलर को अपडेट करने का तरीका, अपलोड हैंडलर को अपडेट करने के तरीके जैसा ही होता है. हालांकि, इसमें देखने के लिए बहुत कम कोड होता है. Blobstore और webapp फ़ंक्शन को Cloud Storage और Flask के बराबर फ़ंक्शन से बदलें:

BEFORE:

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)

AFTER:

@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)

इस अपडेट के बारे में जानकारी:

  • Flask, हैंडलर फ़ंक्शन को उनके रूट से सजाता है, जबकि webapp इसे सबसे नीचे मौजूद राउटिंग टेबल में करता है. इसलिए, बाद वाले के पैटर्न मैचिंग सिंटैक्स ('/view/([^/]+)?') बनाम Flask के ('/view/<path:fname>') को पहचानें.
  • अपलोड हैंडलर की तरह, Cloud Storage को भी कुछ और काम करना पड़ता है. यह काम, Blobstore हैंडलर की मदद से किया जाता है. जैसे, सवाल में मौजूद फ़ाइल (ब्लॉब) की पहचान करना और Blobstore हैंडलर के सिंगल send_blob() तरीके के कॉल के मुकाबले, बाइनरी को साफ़ तौर पर डाउनलोड करना.
  • दोनों ही मामलों में, अगर कोई आर्टफ़ैक्ट नहीं मिलता है, तो उपयोगकर्ता को एचटीटीपी 404 गड़बड़ी का मैसेज दिखता है.

मुख्य हैंडलर

मुख्य ऐप्लिकेशन में फ़ाइनल बदलाव, मुख्य हैंडलर में होते हैं. webapp2 एचटीटीपी वर्ब के तरीकों को एक ही फ़ंक्शन से बदल दिया गया है. इस फ़ंक्शन में, उन तरीकों की सुविधाओं को शामिल किया गया है. MainHandler क्लास को root() फ़ंक्शन से बदलें और webapp2 राउटिंग टेबल को हटाएं. इसके लिए, यहां दिया गया तरीका अपनाएं:

BEFORE:

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)

AFTER:

@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() तरीके नहीं हैं. ये असल में root() में if-else स्टेटमेंट हैं. इसके अलावा, root() एक ही फ़ंक्शन है. इसलिए, GET और POST, दोनों के लिए टेंप्लेट को रेंडर करने के लिए सिर्फ़ एक कॉल किया जाता है. हालांकि, webapp2 में ऐसा करना मुमकिन नहीं है.

main.py में हुए बदलावों के दूसरे और आखिरी सेट को यहां इमेज में दिखाया गया है:

5ec38818c32fec2.png

(ज़रूरी नहीं) पिछले वर्शन के साथ काम करने की सुविधा को "बेहतर बनाना"

इसलिए, ऊपर दिया गया समाधान पूरी तरह से काम करता है... लेकिन सिर्फ़ तब, जब आपने अभी तक कोई फ़ाइल नहीं बनाई है और आपके पास Blobstore से बनाई गई कोई फ़ाइल नहीं है. हमने ऐप्लिकेशन को अपडेट किया है. अब यह BlobKey के बजाय, फ़ाइल नाम के हिसाब से फ़ाइलों की पहचान करेगा. इसलिए, मॉड्यूल 16 का पूरा हो चुका ऐप्लिकेशन, Blobstore फ़ाइलें नहीं देख पाएगा. दूसरे शब्दों में कहें, तो हमने इस माइग्रेशन को पूरा करने के लिए, पिछले वर्शन के साथ काम न करने वाला बदलाव किया है. अब हम main.py का एक वैकल्पिक वर्शन पेश कर रहे हैं, जिसे main-migrate.py कहा जाता है. यह repo में मौजूद है. यह इस अंतर को कम करने की कोशिश करता है.

Blobstore में बनाई गई फ़ाइलों के साथ काम करने वाला पहला "एक्सटेंशन" एक डेटा मॉडल है. इसमें BlobKeyProperty होता है. साथ ही, Cloud Storage में बनाई गई फ़ाइलों के लिए StringProperty भी होता है:

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 थोड़ा अलग दिखे:

BEFORE:

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()

AFTER:

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()

हाल ही की विज़िट का डेटा फ़ेच करते समय, टेंप्लेट को भेजने से पहले डेटा को "सामान्य करें":

BEFORE:

@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)

AFTER:

@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 (या दोनों में से कोई भी नहीं) मौजूद है या नहीं. अगर कोई फ़ाइल उपलब्ध है, तो मौजूदा फ़ाइल चुनें और उस आइडेंटिफ़ायर का इस्तेमाल करें (Blobstore से बनाई गई फ़ाइलों के लिए BlobKey या Cloud Storage से बनाई गई फ़ाइलों के लिए फ़ाइल का नाम). "Cloud Storage से बनाई गई फ़ाइलों" का मतलब, Cloud Storage क्लाइंट लाइब्रेरी का इस्तेमाल करके बनाई गई फ़ाइलों से है. Blobstore, Cloud Storage में भी लिखता है. हालांकि, इस मामले में वे Blobstore से बनाई गई फ़ाइलें होंगी.

अब सबसे अहम बात यह है कि यह etl_visits() फ़ंक्शन क्या है, जिसका इस्तेमाल असली उपयोगकर्ता के लिए डेटा को सामान्य बनाने या ईटीएल (डेटा निकालना, बदलना, और लोड करना) के लिए किया जाता है? यह इस तरह दिखता है:

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 के बीच के अंतर को दिखाया गया है:

718b05b2adadb2e1.png

अगर आपको Blobstore से बनाई गई फ़ाइलों के बिना नए सिरे से शुरुआत करनी है, तो main.py का इस्तेमाल करें. हालांकि, अगर आपको ट्रांज़िशन करना है और Blobstore और Cloud Storage, दोनों से बनाई गई फ़ाइलों का इस्तेमाल करना है, तो main-migrate.py देखें. इसमें बताया गया है कि इस तरह के मामलों को कैसे हैंडल किया जाता है. इससे आपको अपने ऐप्लिकेशन के लिए माइग्रेशन की योजना बनाने में मदद मिलेगी. जटिल माइग्रेशन करते समय, कुछ खास मामले सामने आ सकते हैं. इसलिए, इस उदाहरण का मकसद यह दिखाना है कि असली डेटा के साथ असली ऐप्लिकेशन को मॉडर्न बनाने के लिए, ज़्यादा से ज़्यादा काम किया जा सकता है.

6. खास जानकारी/सफ़ाई

इस सेक्शन में, ऐप्लिकेशन को डिप्लॉय करके इस कोडलैब को पूरा किया गया है. साथ ही, यह पुष्टि की गई है कि ऐप्लिकेशन ठीक से काम कर रहा है और आउटपुट में कोई गड़बड़ी नहीं है. ऐप्लिकेशन की पुष्टि होने के बाद, क्लीन-अप से जुड़े सभी चरण पूरे करें और आगे की कार्रवाई करें.

ऐप्लिकेशन डिप्लॉय करना और उसकी पुष्टि करना

अपने ऐप्लिकेशन को फिर से डिप्लॉय करने से पहले, pip install -t lib -r requirements.txt को ज़रूर चलाएं, ताकि lib फ़ोल्डर में तीसरे पक्ष की वे लाइब्रेरी मिल सकें जो खुद बंडल की गई हैं. अगर आपको पुराने वर्शन के साथ काम करने वाला समाधान चलाना है, तो पहले main-migrate.py का नाम बदलकर main.py करें. अब gcloud app deploy चलाएं और पुष्टि करें कि यह ऐप्लिकेशन, Module 15 ऐप्लिकेशन की तरह ही काम करता है. फ़ॉर्म की स्क्रीन ऐसी दिखती है:

f5b5f9f19d8ae978.png

हाल ही की विज़िट वाला पेज ऐसा दिखता है:

f5ac6b98ee8a34cb.png

App Engine Blobstore को Cloud Storage से, App Engine NDB को Cloud NDB से, और webapp2 को Flask से बदलने वाले इस कोडलैब को पूरा करने के लिए बधाई. आपका कोड अब FINISH (Module 16) फ़ोल्डर में मौजूद कोड से मेल खाना चाहिए. उस फ़ोल्डर में, विकल्प main-migrate.py भी मौजूद है.

Python 3 "माइग्रेशन"

इस ऐप्लिकेशन को Python 3 में पोर्ट करने के लिए, app.yaml के सबसे ऊपर मौजूद Python 3 runtime डायरेक्टिव को अनकमेंट करना होगा. सोर्स कोड पहले से ही Python 3 के साथ काम करता है. इसलिए, इसमें कोई बदलाव करने की ज़रूरत नहीं है. इसे Python 3 ऐप्लिकेशन के तौर पर डिप्लॉय करने के लिए, यह तरीका अपनाएं:

  1. app.yaml के सबसे ऊपर मौजूद, Python 3 runtime डायरेक्टिव से टिप्पणी हटाएं.
  2. app.yaml में मौजूद अन्य सभी लाइनें मिटाएं.
  3. appengine_config.py फ़ाइल मिटाएं. (Python 3 रनटाइम में इस्तेमाल नहीं किया जाता)
  4. अगर lib फ़ोल्डर मौजूद है, तो उसे मिटाएं. (Python 3 रनटाइम के साथ इसकी ज़रूरत नहीं है)

व्यवस्थित करें

सामान्य

अगर आपको अभी और काम नहीं करना है, तो हमारा सुझाव है कि आप अपने App Engine ऐप्लिकेशन को बंद कर दें, ताकि आपसे शुल्क न लिया जाए. हालांकि, अगर आपको कुछ और टेस्ट या एक्सपेरिमेंट करने हैं, तो App Engine प्लैटफ़ॉर्म पर मुफ़्त कोटा उपलब्ध है. इसलिए, जब तक आप इस्तेमाल की उस सीमा से ज़्यादा नहीं होते हैं, तब तक आपसे कोई शुल्क नहीं लिया जाएगा. यह शुल्क कंप्यूट के लिए है. हालांकि, App Engine की सेवाओं के लिए भी शुल्क लिया जा सकता है. इसलिए, ज़्यादा जानकारी के लिए कीमत वाला पेज देखें. अगर इस माइग्रेशन में अन्य क्लाउड सेवाएं शामिल हैं, तो उनके लिए अलग से बिल भेजा जाता है. अगर लागू हो, तो दोनों ही मामलों में, नीचे दिया गया "इस कोडलैब के लिए खास जानकारी" सेक्शन देखें.

पूरी जानकारी के लिए बता दें कि App Engine जैसे Google Cloud के सर्वरलेस कंप्यूट प्लैटफ़ॉर्म पर डिप्लॉय करने से, बिल्ड और स्टोरेज के लिए मामूली शुल्क लगता है. 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" दिखेगा.

दूसरी ओर, अगर आपको इस ऐप्लिकेशन या माइग्रेशन से जुड़े अन्य कोडलैब का इस्तेमाल नहीं करना है और आपको सब कुछ पूरी तरह से मिटाना है, तो अपना प्रोजेक्ट बंद करें.

इस कोडलैब के लिए खास तौर पर

यहां दी गई सेवाएं, इस कोड सीखने की लैब के लिए खास तौर पर बनाई गई हैं. ज़्यादा जानकारी के लिए, हर प्रॉडक्ट का दस्तावेज़ देखें:

ध्यान दें कि अगर आपने मॉड्यूल 15 से 16 पर माइग्रेट किया है, तो आपके पास अब भी Blobstore में डेटा होगा. इसलिए, हमने ऊपर इसकी कीमत की जानकारी शामिल की है.

अगले चरण

इस ट्यूटोरियल के अलावा, माइग्रेशन के अन्य मॉड्यूल भी उपलब्ध हैं. इनमें लेगसी बंडल की गई सेवाओं से माइग्रेट करने पर फ़ोकस किया गया है. इनमें ये शामिल हैं:

App Engine अब Google Cloud में सर्वरलेस प्लैटफ़ॉर्म नहीं है. अगर आपके पास कोई छोटा App Engine ऐप्लिकेशन है या ऐसा ऐप्लिकेशन है जिसमें सीमित सुविधाएं हैं और आपको उसे स्टैंडअलोन माइक्रोसेवा में बदलना है या आपको किसी मोनोलिथिक ऐप्लिकेशन को फिर से इस्तेमाल किए जा सकने वाले कई कॉम्पोनेंट में बांटना है, तो Cloud Functions पर माइग्रेट करने के लिए ये अच्छी वजहें हैं. अगर कंटेनर बनाने की प्रोसेस, ऐप्लिकेशन डेवलपमेंट वर्कफ़्लो का हिस्सा बन गई है, तो Cloud Run पर माइग्रेट करें. खास तौर पर, अगर इसमें सीआई/सीडी (लगातार इंटिग्रेशन/लगातार डिलीवरी या डिप्लॉयमेंट) पाइपलाइन शामिल है. इन स्थितियों के बारे में यहां दिए गए मॉड्यूल में बताया गया है:

  • App Engine से Cloud Functions पर माइग्रेट करना: मॉड्यूल 11 देखें
  • App Engine से Cloud Run पर माइग्रेट करना: Docker की मदद से अपने ऐप्लिकेशन को कंटेनर में बदलने के लिए, मॉड्यूल 4 देखें. इसके अलावा, कंटेनर, Docker की जानकारी या Dockerfile के बिना ऐसा करने के लिए, मॉड्यूल 5 देखें

किसी दूसरे सर्वरलेस प्लैटफ़ॉर्म पर स्विच करना ज़रूरी नहीं है. हमारा सुझाव है कि कोई भी बदलाव करने से पहले, अपने ऐप्लिकेशन और इस्तेमाल के उदाहरणों के लिए सबसे सही विकल्पों पर विचार करें.

अगले माइग्रेशन मॉड्यूल के तौर पर किसी भी मॉड्यूल को चुना जा सकता है. हालांकि, Serverless Migration Station का पूरा कॉन्टेंट (कोड लैब, वीडियो, सोर्स कोड [अगर उपलब्ध हो]) इसके ओपन सोर्स रेपो में ऐक्सेस किया जा सकता है. रेपो के README में यह भी बताया गया है कि किन माइग्रेशन पर विचार करना चाहिए. साथ ही, माइग्रेशन मॉड्यूल के "क्रम" के बारे में भी बताया गया है.

7. अन्य संसाधन

कोडलैब से जुड़ी समस्याएं/सुझाव/राय

अगर आपको इस कोडलैब में कोई समस्या मिलती है, तो कृपया शिकायत दर्ज करने से पहले अपनी समस्या खोजें. नई समस्याएं खोजने और बनाने के लिए लिंक:

माइग्रेशन के लिए उपलब्ध संसाधन

मॉड्यूल 15 (START) और मॉड्यूल 16 (FINISH) के लिए, रेपो फ़ोल्डर के लिंक यहां दिए गए टेबल में देखे जा सकते हैं. इन्हें App Engine के सभी कोडलैब माइग्रेशन के लिए उपलब्ध repo से भी ऐक्सेस किया जा सकता है. इसे क्लोन किया जा सकता है या इसकी ZIP फ़ाइल डाउनलोड की जा सकती है.

कोडलैब

Python 2

Python 3

मॉड्यूल 15

code

लागू नहीं

मॉड्यूल 16 (यह कोडलैब)

code

(Python 2 की तरह ही)

ऑनलाइन संसाधन

यहां कुछ ऑनलाइन संसाधन दिए गए हैं, जो इस ट्यूटोरियल के लिए काम के हो सकते हैं:

App Engine Blobstore और Cloud Storage

App Engine प्लैटफ़ॉर्म

क्लाउड से जुड़ी अन्य जानकारी

Python

वीडियो

लाइसेंस

इस काम के लिए, Creative Commons एट्रिब्यूशन 2.0 जेनेरिक लाइसेंस के तहत लाइसेंस मिला है.