Questa guida illustra come eseguire la migrazione dall'archivio BLOB di App Engine a Cloud Storage.
Cloud Storage è simile al BLOB di App Engine in quanto puoi utilizzare Cloud Storage per gestire oggetti di dati (BLOB), come file video o immagine e consentire agli utenti di caricare file di dati di grandi dimensioni. Mentre L'archivio BLOB di App Engine è accessibile solo tramite Servizi in bundle legacy di App Engine, Cloud Storage è una piattaforma Google Cloud autonoma prodotto a cui si accede tramite le librerie client di Cloud. Cloud Storage offre alla tua app una soluzione di archiviazione oggetti più moderna e ti consente di eseguire in un secondo momento la migrazione a Cloud Run o a un'altra piattaforma di hosting di app Google Cloud.
Per i progetti Google Cloud creati dopo novembre 2016, Blobstore utilizza dietro le quinte ai bucket Cloud Storage. Ciò significa che quando esegui la migrazione della tua app a Cloud Storage, tutte le autorizzazioni e gli oggetti esistenti nei bucket Cloud Storage esistenti rimangono invariati. Puoi anche iniziare ad accedere ai bucket esistenti utilizzando Librerie client di Cloud per Cloud Storage.
Differenze e analogie principali
Cloud Storage esclude le seguenti dipendenze e limitazioni di Blobstore:
- L'API Blobstore per Python 2 ha una dipendenza dall'app web.
- L'API Blobstore per Python 3 utilizza classi di utilità per utilizzare gli handler Blobstore.
- Per Blobstore, il numero massimo di file che possono essere caricati è 500. Non esiste un limite al numero di oggetti che puoi creare in un nel bucket Cloud Storage.
Cloud Storage non supporta:
- Classi di gestori Blobstore
- Oggetti Blobstore
Somiglianze con Cloud Storage e App Engine Blobstore:
- È in grado di leggere e scrivere oggetti di dati di grandi dimensioni in un ambiente di runtime, nonché di archiviare e pubblicare oggetti di dati statici di grandi dimensioni, come filmati, immagini o altri contenuti statici. Il limite di dimensione degli oggetti per Cloud Storage è 5 TiB.
- Ti consente di archiviare oggetti in un bucket Cloud Storage.
- Disporre di un Livello gratuito.
Prima di iniziare
- Devi esaminare e comprendere i prezzi e le quote di Cloud Storage:
- Cloud Storage è un servizio a pagamento e ha i propri prezzi per l'archiviazione dei dati in base alla classe di archiviazione dei dati e alla posizione dei bucket.
- Le quote di Cloud Storage presentano alcune differenze da quote e limiti dell'archivio BLOB di App Engine, il che potrebbe influire sulle quote delle richieste di App Engine.
- Avere un'app App Engine Python 2 o Python 3 esistente che utilizzi Archivio BLOB.
- Gli esempi in questa guida mostrano un'app che esegue la migrazione a
Cloud Storage
usando il framework Flask. Tieni presente che puoi utilizzare qualsiasi
framework web, inclusa la permanenza su
webapp2
, durante la migrazione a di archiviazione ideale in Cloud Storage.
Panoramica
In linea generale, la procedura di migrazione a Cloud Storage da App Engine Blobstore è costituita dai seguenti passaggi:
- Aggiornare i file di configurazione
- Aggiorna la tua app Python:
- Aggiorna il framework web
- Importa e inizializza Cloud Storage
- Aggiornamento gestori Blobstore
- (Facoltativo) Aggiorna il modello dei dati se utilizzi Cloud NDB NDB di App Engine
- Testare ed eseguire il deployment dell'app
Aggiornare i file di configurazione
Prima di modificare il codice dell'applicazione per passare da Blobstore a Cloud Storage, aggiorna i file di configurazione in modo da utilizzare libreria di Cloud Storage.
Aggiorna il file
app.yaml
. Segui le istruzioni relative alla tua versione di Python:Python 2
Per le app Python 2:
- Rimuovi la sezione
handlers
ed eventuali non necessarie dipendenze-applicazione web nella sezionelibraries
. - Se utilizzi le librerie client di Cloud, aggiungi le versioni più recenti delle librerie
grpcio
esetuptools
. - Aggiungi la libreria
ssl
poiché è richiesta da Cloud Storage.
Di seguito è riportato un file
app.yaml
di esempio con le modifiche apportate: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
Python 3
Per le app Python 3, elimina tutte le righe tranne l'elemento
runtime
. Ad esempio:runtime: python310 # or another support version
Il runtime Python 3 installa le librerie automaticamente, quindi devi specificare le librerie integrate nel runtime Python 2 precedente. Se la tua app Python 3 utilizza altri servizi legacy in bundle durante la migrazione a Cloud Storage, lascia invariato il file
app.yaml
.- Rimuovi la sezione
Aggiorna il file
requirements.txt
. Segui le istruzioni relative alla tua versione di Python:Python 2
Aggiungi le librerie client di Cloud per Cloud Storage al tuo elenco di di dipendenze nel file
requirements.txt
.google-cloud-storage
Poi esegui
pip install -t lib -r requirements.txt
per aggiornare l'elenco librerie disponibili per la tua app.Python 3
Aggiungi le librerie client di Cloud per Cloud Storage al tuo elenco delle dipendenze nel file
requirements.txt
.google-cloud-storage
App Engine installa automaticamente queste dipendenze durante il deployment dell'app nel runtime di Python 3, quindi elimina la cartella
lib
, se esistente.Per le app Python 2, se la tua app utilizza librerie integrate o copiate, devi specificare quei percorsi nel file
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)
Aggiorna l'app Python
Dopo aver modificato i file di configurazione, aggiorna l'app Python.
Aggiorna il framework web Python 2
Per le app Python 2 che utilizzano il framework webapp2
, è consigliabile eseguire la migrazione
dal framework webapp2
obsoleto. Consulta il
programma di supporto del runtime
per la data di ritiro del supporto di Python 2.
Puoi eseguire la migrazione a un altro framework web come
Flask,
Django o WSGI. Poiché Cloud Storage esclude le dipendenze su webapp2
e i gestori dell'archivio BLOB non sono supportati, puoi eliminare o sostituire altri
relative alle app web.
Se scegli di continuare a utilizzare webapp2
, tieni presente che gli esempi riportati in questa guida utilizzano Cloud Storage con Flask.
Se prevedi di utilizzare i servizi Google Cloud oltre a Cloud Storage o di accedere alle versioni più recenti del runtime, ti consigliamo di eseguire l'upgrade dell'app al runtime Python 3. Per ulteriori informazioni, consulta la panoramica della migrazione da Python 2 a Python 3.
Importa e inizializza Cloud Storage
Modifica i file dell'applicazione aggiornando le righe di importazione e inizializzazione:
Rimuovi le istruzioni di importazione di Blobstore, ad esempio la seguente:
import webapp2 from google.appengine.ext import blobstore from google.appengine.ext.webapp import blobstore_handlers
Aggiungi le istruzioni di importazione per Cloud Storage e Librerie di autenticazione, come le seguenti:
import io from flask import (Flask, abort, redirect, render_template, request, send_file, url_for) from google.cloud import storage import google.auth
La libreria di autenticazione Google è necessaria per ottenere lo stesso ID progetto che è stato usato in Blobstore per Cloud Storage. Importa altre librerie come Cloud NBD, se applicabile alla tua app.
Crea un nuovo client per Cloud Storage e specifica il bucket utilizzata in Blobstore. Ad esempio:
gcs_client = storage.Client() _, PROJECT_ID = google.auth.default() BUCKET = '%s.appspot.com' % PROJECT_ID
Per i progetti Google Cloud dopo novembre 2016, Blobstore scrive in un Il bucket Cloud Storage ha il nome dell'URL dell'app e segue la formato di
PROJECT_ID.appspot.com
. Utilizzi l'autenticazione Google per ottenere l'ID progetto per specificare il bucket Cloud Storage utilizzato per memorizzare i blob in Blobstore.
Aggiorna i gestori di Blobstore
Poiché Cloud Storage non supporta gli elaboratori di caricamento e download di Blobstore, devi utilizzare una combinazione di funzionalità di Cloud Storage, del modulo della libreria standard io
, del tuo framework web e delle utilità Python per caricare e scaricare oggetti (blob) in Cloud Storage.
Di seguito viene mostrato come aggiornare i gestori di Blobstore utilizzando Flask come framework web di esempio:
Sostituisci le classi del gestore di caricamento Blobstore con una funzione di caricamento in Fiaschetta. Segui le istruzioni per la tua versione di Python:
Python 2
I gestori di Blobstore in Python 2 sono classi
webapp2
come mostrato in seguente esempio di Blobstore: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 = webapp2.WSGIApplication([ ('/', MainHandler), ('/upload', UploadHandler), ('/view/([^/]+)?', ViewBlobHandler), ], debug=True)
Per utilizzare Cloud Storage:
- Sostituisci la classe di caricamento dell'app web con una funzione di caricamento Flask.
- Sostituisci il gestore del caricamento e il routing con un metodo
POST
Flask ornamentato con il routing.
Esempio di codice aggiornato:
@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)
Nell'esempio di codice aggiornato di Cloud Storage, l'app ora identifica gli artefatti dell'oggetto in base al nome dell'oggetto (
fname
) anzichéblob_id
. Il routing avviene anche nella parte inferiore del file dell'applicazione.Per ottenere l'oggetto caricato, il metodo
get_uploads()
di Blobstore viene sostituita con il metodorequest.files.get()
di Flask. In Flask, puoi utilizzare il metodosecure_filename()
per ottenere un nome senza caratteri di percorso, come/
, per il file e identificare l'oggetto utilizzandogcs_client.bucket(BUCKET).blob(fname)
per specificare il nome del bucket e quello dell'oggetto.Lo spazio di archiviazione
upload_from_file()
esegue come mostrato nell'esempio aggiornato.Python 3
La classe di gestore del caricamento in Blobstore per Python 3 è una classe di utilità e richiede l'utilizzo del dizionario
environ
WSGI come parametro di input, come mostrato nell'esempio di Blobstore seguente:class UploadHandler(blobstore.BlobstoreUploadHandler): 'Upload blob (POST) handler' def post(self): uploads = self.get_uploads(request.environ) if uploads: blob_id = uploads[0].key() store_visit(request.remote_addr, request.user_agent, blob_id) return redirect('/', code=307) ... @app.route('/upload', methods=['POST']) def upload(): """Upload handler called by blobstore when a blob is uploaded in the test.""" return UploadHandler().post()
Per usare Cloud Storage, sostituisci Metodo
get_uploads(request.environ)
con Flask Metodorequest.files.get()
.Esempio di codice aggiornato:
@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)
Nell'esempio di codice aggiornato di Cloud Storage, l'app ora identifica gli artefatti dell'oggetto in base al nome dell'oggetto (
fname
) anzichéblob_id
. Il routing avviene anche nella parte inferiore del file dell'applicazione.Per ottenere l'oggetto caricato, il metodo
get_uploads()
di Blobstore è sostituiti con il metodorequest.files.get()
di Flask. In Flask puoi: usa il metodosecure_filename()
per ottenere un nome senza percorso ad esempio/
, per il file e identifica l'oggetto utilizzandogcs_client.bucket(BUCKET).blob(fname)
per specificare il nome del bucket e dell'oggetto.Lo spazio di archiviazione Il metodo
upload_from_file()
viene eseguito eseguire il caricamento, come mostrato nell'esempio aggiornato.Sostituisci le classi gestore del download di Blobstore con una funzione di download in Fiaschetta. Segui le istruzioni per la tua versione di Python:
Python 2
Il seguente esempio di gestore dei download mostra l'utilizzo Classe
BlobstoreDownloadHandler
, che utilizza webapp2: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 = webapp2.WSGIApplication([ ('/', MainHandler), ('/upload', UploadHandler), ('/view/([^/]+)?', ViewBlobHandler), ], debug=True)
Per utilizzare Cloud Storage:
- Aggiorna il metodo
send_blob()
di Blobstore per utilizzare il metododownload_as_bytes()
di Cloud Storage. - Modifica il routing da webapp2 a Flask.
Esempio di codice aggiornato:
@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)
Nell'esempio di codice aggiornato di Cloud Storage, Flask decora la nella funzione Flask e identifica l'oggetto utilizzando
'/view/<path:fname>'
. Cloud Storage identificablob
con il nome dell'oggetto e del bucket e utilizza il parametrodownload_as_bytes()
per scaricare l'oggetto come byte, anziché come utilizzando il metodosend_blob
di Blobstore. Se l'elemento non viene trovato, l'app restituisce un errore HTTP404
.Python 3
Come il gestore del caricamento, la classe del gestore dei download in Blobstore Python 3 è una classe di utilità e richiede l'utilizzo Dizionario WSGI
environ
come parametro di input, come illustrato nel seguente esempio di Blobstore:class ViewBlobHandler(blobstore.BlobstoreDownloadHandler): 'view uploaded blob (GET) handler' def get(self, blob_key): if not blobstore.get(blob_key): return "Photo key not found", 404 else: headers = self.send_blob(request.environ, blob_key) # Prevent Flask from setting a default content-type. # GAE sets it to a guessed type if the header is not set. headers['Content-Type'] = None return '', headers ... @app.route('/view/<blob_key>') def view_photo(blob_key): """View photo given a key.""" return ViewBlobHandler().get(blob_key)
Per utilizzare Cloud Storage, sostituisci
send_blob(request.environ, blob_key)
di Blobstore con il metodoblob.download_as_bytes()
di Cloud Storage.Esempio di codice aggiornato:
@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)
Nel codice di esempio di Cloud Storage aggiornato,
blob_key
viene sostituito confname
e Flask identifica l'oggetto utilizzando l'URL'/view/<path:fname>'
. Il metodogcs_client.bucket(BUCKET).blob(fname)
viene utilizzato per individuare il nome del file e il nome del bucket. Il metododownload_as_bytes()
di Cloud Storage scarica come byte, invece di utilizzare il metodosend_blob()
da Archivio BLOB.- Aggiorna il metodo
Se la tua app utilizza un gestore principale, sostituisci la classe
MainHandler
con la funzioneroot()
in Flask. Segui le istruzioni per la tua versione di Python:Python 2
Di seguito è riportato un esempio di utilizzo della classe
MainHandler
di Blobstore: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)
Per utilizzare Cloud Storage:
- Rimuovi la classe
MainHandler(BaseHandler)
, poiché Flask gestisce il routing per te. - Semplificare il codice dell'archivio BLOB con Flask.
- Rimuovi il routing della web app alla fine.
Esempio di codice aggiornato:
@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)
Python 3
Se hai utilizzato Flask, non avrai una classe
MainHandler
, ma la funzione Flask root deve essere aggiornata se viene utilizzato Blobstore. L'esempio seguente utilizza la funzioneblobstore.create_upload_url('/upload')
:@app.route('/', methods=['GET', 'POST']) def root(): 'main application (GET/POST) handler' context = {} if request.method == 'GET': context['upload_url'] = blobstore.create_upload_url('/upload') else: context['visits'] = fetch_visits(10) return render_template('index.html', **context)
Per utilizzare Cloud Storage, sostituisci la funzione
blobstore.create_upload_url('/upload')
con il metodourl_for()
di Flask per ottenere l'URL della funzioneupload()
.Esempio di codice aggiornato:
@app.route('/', methods=['GET', 'POST']) def root(): 'main application (GET/POST) handler' context = {} if request.method == 'GET': context['upload_url'] = url_for('upload') # Updated to use url_for else: context['visits'] = fetch_visits(10) return render_template('index.html', **context)
- Rimuovi la classe
Test e deployment dell'app
Il server di sviluppo locale ti consente di verificare il funzionamento dell'app, ma non sarà in grado di testare Cloud Storage finché non eseguirai il deployment di una nuova versione perché tutte le richieste di Cloud Storage devono essere inviate tramite internet a un bucket Cloud Storage effettivo. Consulta la sezione Test e deployment dell'applicazione per scoprire come eseguire l'applicazione localmente. quindi esegui il deployment di una nuova versione per confermare l'app ha lo stesso aspetto di prima.
App che utilizzano App Engine NDB o Cloud NDB
Devi aggiornare il modello di dati di Datastore se la tua app utilizza NDB di App Engine o NDB di Cloud per includere proprietà correlate a Blobstore.
Aggiorna il modello dei dati
Poiché le proprietà BlobKey
di NDB non sono supportate da Cloud Storage, devi modificare le righe relative a Blobstore per utilizzare gli equivalenti integrati di NDB, dei framework web o di altre origini.
Per aggiornare il modello dei dati:
Trova le linee che utilizza
BlobKey
nel modello dei dati, come segue: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()
Sostituisci
ndb.BlobKeyProperty()
conndb.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.StringProperty() # Modified from ndb.BlobKeyProperty()
Se esegui anche l'upgrade da App Engine NDB a Cloud NDB durante la migrazione, consulta Guida alla migrazione di Cloud NDB per indicazioni su come eseguire il refactoring del codice NDB per utilizzare i gestori di contesto Python.
Compatibilità con le versioni precedenti per il modello di dati di Datastore
Nella sezione precedente, sostituendo ndb.BlobKeyProperty
con
ndb.StringProperty
ha reso l'app incompatibile con le versioni precedenti, ossia l'app
non sarà in grado di elaborare le voci meno recenti create da Blobstore. Se devi conservare i dati precedenti, anziché aggiornare il campo ndb.BlobKeyProperty
, crea un campo aggiuntivo per le nuove voci Cloud Storage e una funzione per normalizzare i dati.
A partire dagli esempi nelle sezioni precedenti, apporta le seguenti modifiche:
Crea due campi della proprietà separati quando definisci il modello dei dati. Utilizza la
file_blob
per identificare gli oggetti creati da Blobstore e lafile_gcs
per identificare gli oggetti creati in 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()
Trova le righe che fanno riferimento alle nuove visite, ad esempio:
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()
Modifica il codice in modo che per le voci recenti venga utilizzato
file_gcs
. Ad esempio: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() # change file_blob to file_gcs for new requests
Crea una nuova funzione per normalizzare i dati. L'esempio seguente mostra l'utilizzo di ETL (estrazione, trasformazione e caricamento) per eseguire un ciclo per tutte le visite e acquisisce i dati del visitatore e del timestamp per verificare se esistono
file_gcs
ofile_gcs
: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]
Trova la riga che fa riferimento alla funzione
fetch_visits()
:@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)
Inserisci
fetch_visits()
all'interno della funzioneetl_visits()
, ad esempio:@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)) # etl_visits wraps around fetch_visits return render_template('index.html', **context)
Esempi
- Per vedere un esempio di come eseguire la migrazione di un'app Python 2 a Cloud Storage, confronta l'esempio di codice Blobstore per Python 2 e l'esempio di codice Cloud Storage su GitHub.
- Per vedere un esempio di come eseguire la migrazione di un'app Python 3 a Cloud Storage, Confronta l'esempio di codice dell'archivio BLOB per Python 3 e l'esempio di codice di Cloud Storage in GitHub.
Passaggi successivi
- Per un tutorial pratico, consulta il codelab Esegui la migrazione da Blobstore di App Engine a Cloud Storage per Python.
- Scopri come archiviare e gestire file statici da Cloud Storage.
- Per ulteriori dettagli, consulta la documentazione di Cloud Storage.