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

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

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

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

इस बारे में सिलसिलेवार जानकारी पाने के लिए, माइग्रेशन से जुड़े किसी भी मॉड्यूल का इस्तेमाल करें.

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

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

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

सर्वे

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

इसे सिर्फ़ पढ़ें इसे पढ़ें और कसरतों को पूरा करें

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

शुरुआती इंटरमीडिएट कुशल

Google Cloud की सेवाएं इस्तेमाल करने का आपका अनुभव कैसा रहा?

शुरुआती इंटरमीडिएट कुशल

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

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

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

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

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

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

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

अगर आपने मॉड्यूल 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 का एक वैकल्पिक वर्शन है. इससे Cloud Storage बकेट को प्रोजेक्ट के आईडी के आधार पर, ऐप्लिकेशन को असाइन किए गए यूआरएल के डिफ़ॉल्ट बकेट से अलग चुनने की अनुमति मिलती है: PROJECT_ID.appspot.com. यह फ़ाइल इस (मॉड्यूल 16) कोडलैब में कोई भूमिका नहीं निभाती. इसके अलावा, अगर ज़रूरत हो, तो इस पर माइग्रेशन की ऐसी ही तकनीकों का इस्तेमाल किया जा सकता है.

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

कार्रवाई से पहले, इन चरणों को पूरा करें:

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

इन चरणों को पूरा करने के बाद, पुष्टि करें कि Module 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 चुना है):

पहले:

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

requirements.txt

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

पहले:

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

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

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

पहले:

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

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() फ़ंक्शन दिए गए हैं. इनमें इन बदलावों को दिखाया गया है:

पहले:

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)

यहां अब तक किए गए बदलावों को तस्वीरों के ज़रिए दिखाया गया है:

a8f74ca392275822.png

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

अपलोड हैंडलर

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

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

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

पहले:

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

मुख्य हैंडलर

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

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

5ec38818c32fec2.png

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

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

पहला "एक्सटेंशन" 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 कुछ अलग दिखता है:

पहले:

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 (या कोई भी नहीं) की मौजूदगी की पुष्टि करें. अगर कोई फ़ाइल उपलब्ध है, तो मौजूदा फ़ाइल को चुनें और उस आइडेंटिफ़ायर का इस्तेमाल करें (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 चलाएं और पुष्टि करें कि ऐप्लिकेशन, मॉड्यूल 15 ऐप्लिकेशन की तरह ही काम करता है. फ़ॉर्म स्क्रीन कुछ इस तरह दिखेगी:

f5b5f9f19d8ae978.png

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

f5ac6b98ee8a34cb.png

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

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

app.yaml में सबसे ऊपर, Python 3 runtime डायरेक्टिव के बारे में टिप्पणी करते समय, इस ऐप्लिकेशन को Python 3 में पोर्ट करने के लिए ज़रूरी सभी सुविधाएं मौजूद हैं. सोर्स कोड पहले से ही 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 Storage की तरह Cloud Build का अपना अलग कोटा होता है. उस इमेज का स्टोरेज, उसके कुछ हिस्से का इस्तेमाल करता है. हालांकि, हो सकता है कि आप किसी ऐसे क्षेत्र में हों जहां ऐसा कोई फ़्री टीयर उपलब्ध न हो. इसलिए, संभावित लागत को कम करने के लिए, अपने स्टोरेज के इस्तेमाल को ध्यान में रखें. 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" अगर आपका ऐप्लिकेशन अमेरिका में होस्ट किया जाता है.

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

इस कोडलैब के लिए खास

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

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

अगले चरण

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

  • मॉड्यूल 2: App Engine ndb से Cloud NDB पर माइग्रेट करें
  • मॉड्यूल 7-9: App Engine टास्क सूची से पुश टास्क को क्लाउड टास्क में माइग्रेट करें
  • मॉड्यूल 12-13: App Engine Memcache से Cloud Memorystore में माइग्रेट करना
  • मॉड्यूल 18-19: App Engine टास्क सूची (टास्क पुल करें) से Cloud Pub/Sub में माइग्रेट करें

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

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

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

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

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

कोडलैब (कोड बनाना सीखना) से जुड़ी समस्याएं/सुझाव/राय/शिकायत

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

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

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

Codelab

Python 2

Python 3

मॉड्यूल 15

कोड

लागू नहीं

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

कोड

(Python 2 की तरह)

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

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

App Engine Blobstore और Cloud Storage

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

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

Python

वीडियो

लाइसेंस

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