Esegui la migrazione dal BLOB di App Engine a Cloud Storage (modulo 16)

1. Panoramica

La serie di codelab Serverless Migration Station (esercitazioni pratiche e autonome) e i video correlati hanno lo scopo di aiutare gli sviluppatori serverless di Google Cloud a modernizzare le loro applicazioni guidandoli attraverso una o più migrazioni, principalmente abbandonando i servizi legacy. In questo modo, le tue app sono più portatili e hai più opzioni e flessibilità, il che ti consente di integrarti e accedere a una gamma più ampia di prodotti cloud e di eseguire più facilmente l'upgrade alle versioni più recenti del linguaggio. Sebbene inizialmente si concentri sui primi utenti di Cloud, principalmente gli sviluppatori di App Engine (ambiente standard), questa serie è abbastanza ampia da includere altre piattaforme serverless come Cloud Functions e Cloud Run o altrove, se applicabile.

Questo codelab ti insegna a eseguire la migrazione da App Engine Blobstore a Cloud Storage. Esistono anche migrazioni implicite da:

Per informazioni più dettagliate, consulta i moduli di migrazione correlati.

Imparerai a utilizzare

  • Aggiungi l'utilizzo dell'API/libreria Blobstore di App Engine
  • Memorizzare i caricamenti degli utenti nel servizio Blobstore
  • Preparati al passaggio successivo per la migrazione a Cloud Storage

Che cosa ti serve

Sondaggio

Come utilizzerai questo tutorial?

Leggilo e basta Leggilo e completa gli esercizi

Come valuteresti la tua esperienza con Python?

Principiante Intermedio Avanzato

Come valuti la tua esperienza di utilizzo dei servizi Google Cloud?

Principiante Intermedio Avanzato

2. Sfondo

Questo codelab inizia con l'app di esempio del modulo 15 e mostra come eseguire la migrazione da Blobstore (e NDB) a Cloud Storage (e Cloud NDB). Il processo di migrazione prevede la sostituzione delle dipendenze dai servizi bundle legacy di App Engine, che ti consentono di spostare le tue app su un'altra piattaforma serverless Cloud o su un'altra piattaforma di hosting, se vuoi.

Questa migrazione richiede un po' più di impegno rispetto alle altre migrazioni di questa serie. Blobstore ha dipendenze dal framework webapp originale, motivo per cui l'app di esempio utilizza il framework webapp2 anziché Flask. Questo tutorial include le migrazioni a Cloud Storage, Cloud NDB, Flask e Python 3.

L'app registra ancora le "visite" degli utenti finali e mostra le dieci più recenti, ma il codelab precedente (Modulo 15) ha aggiunto nuove funzionalità per adattarsi all'utilizzo di Blobstore: l'app chiede agli utenti finali di caricare un artefatto (un file) corrispondente alla loro "visita". Gli utenti possono farlo o selezionare "Salta" per disattivare l'opzione. Indipendentemente dalla decisione dell'utente, la pagina successiva restituisce lo stesso output delle versioni precedenti di questa app, mostrando le visite più recenti. Un'ulteriore particolarità è che le visite con artefatti corrispondenti includono un link "Visualizza" per mostrare l'artefatto di una visita. Questo codelab implementa le migrazioni menzionate in precedenza preservando la funzionalità descritta.

3. Configurazione/preparazione

Prima di passare alla parte principale del tutorial, configuriamo il progetto, recuperiamo il codice e poi implementiamo l'app di base per assicurarci di iniziare con un codice funzionante.

1. Configura il progetto

Se hai già eseguito il deployment dell'app del Modulo 15, ti consigliamo di riutilizzare lo stesso progetto (e codice). In alternativa, puoi creare un nuovo progetto o riutilizzarne uno esistente. Assicurati che il progetto abbia un account di fatturazione attivo e che App Engine sia abilitato.

2. Ottieni l'app di esempio di base

Uno dei prerequisiti di questo codelab è avere un'app di esempio del Modulo 15 funzionante. Se non ce l'hai, puoi scaricarla dalla cartella "START" del Modulo 15 (link di seguito). Questo codelab ti guida in ogni passaggio e si conclude con un codice simile a quello presente nella cartella "FINISH" del modulo 16.

La directory dei file di INIZIO del modulo 15 dovrebbe avere il seguente aspetto:

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

Il file main-gcs.py è una versione alternativa di main.py del modulo 15 che consente di selezionare un bucket Cloud Storage diverso da quello predefinito di un URL assegnato a un'app in base all'ID progetto: PROJECT_ID.appspot.com. Questo file non svolge alcun ruolo in questo codelab (Modulo 16), se non per il fatto che è possibile applicare tecniche di migrazione simili a questo file, se necessario.

3. (Esegui di nuovo il deployment dell'app di base

I passaggi preliminari rimanenti da eseguire ora:

  1. Acquisisci di nuovo familiarità con lo strumento a riga di comando gcloud
  2. Esegui di nuovo il deployment dell'app di esempio con gcloud app deploy
  3. Verifica che l'app venga eseguita su App Engine senza problemi

Una volta eseguiti correttamente questi passaggi e verificato che l'app del modulo 15 funzioni. La pagina iniziale accoglie gli utenti con un modulo che richiede il caricamento di un file di artefatto della visita insieme a un'opzione, un pulsante "Salta", per disattivare la funzionalità:

f5b5f9f19d8ae978.png

Una volta caricato un file o saltato il passaggio, l'app visualizza la pagina "Visite più recenti" che conosciamo:

f5ac6b98ee8a34cb.png

Le visite che includono un artefatto avranno un link "Visualizza" a destra del timestamp della visita per visualizzare (o scaricare) l'artefatto. Una volta confermata la funzionalità dell'app, puoi eseguire la migrazione dai servizi legacy di App Engine (webapp2, NDB, Blobstore) ad alternative contemporanee (Flask, Cloud NDB, Cloud Storage).

4. Aggiorna i file di configurazione

Per la versione aggiornata della nostra app vengono utilizzati tre file di configurazione. Le attività richieste sono:

  1. Aggiorna le librerie di terze parti integrate richieste in app.yaml e lascia la porta aperta a una migrazione a Python 3
  2. Aggiungi un requirements.txt che specifica tutte le librerie richieste non integrate
  3. Aggiungi appengine_config.py in modo che l'app supporti librerie di terze parti sia integrate che non integrate

app.yaml

Modifica il file app.yaml aggiornando la sezione libraries. Rimuovi jinja2 e aggiungi grpcio, setuptools e ssl. Scegli l'ultima versione disponibile per tutte e tre le librerie. Aggiungi anche la direttiva Python 3 runtime, ma commentata. Al termine, dovrebbe avere l'aspetto seguente (se hai selezionato Python 3.9):

PRIMA:

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: jinja2
  version: latest

DOPO:

#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

Le modifiche riguardano principalmente le librerie integrate di Python 2 disponibili sui server App Engine (in modo da non doverle raggruppare autonomamente). Abbiamo rimosso Jinja2 perché è incluso in Flask, che aggiungeremo a reqs.txt. Ogni volta che vengono utilizzate le librerie client di Google Cloud, come quelle per Cloud NDB e Cloud Storage, sono necessari grpcio e setuptools. Infine, Cloud Storage stesso richiede la libreria SSL. La direttiva di runtime commentata in alto è per quando sarà il momento di eseguire il porting di questa app a Python 3. Tratteremo questo argomento alla fine di questo tutorial.

requirements.txt

Aggiungi un file requirements.txt, che richiede il framework Flask e le librerie client Cloud NDB e Cloud Storage, nessuna delle quali è integrata. Crea il file con questo contenuto:

flask
google-cloud-ndb
google-cloud-storage

Il runtime Python 2 di App Engine richiede l'autobundling delle librerie di terze parti non integrate, quindi esegui il comando seguente per installare queste librerie nella cartella lib:

pip install -t lib -r requirements.txt

Se sulla tua macchina di sviluppo sono presenti sia Python 2 sia Python 3, potresti dover utilizzare il comando pip2 per assicurarti di ottenere le versioni Python 2 di queste librerie. Una volta eseguito l'upgrade a Python 3, non è più necessario il self-bundling.

appengine_config.py

Aggiungi un file appengine_config.py che supporti librerie di terze parti integrate e non integrate. Crea il file con questo contenuto:

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)

I passaggi appena completati devono essere simili o identici a quelli elencati nella sezione Installazione di librerie per app Python 2 della documentazione di App Engine e, più nello specifico, i contenuti di appengine_config.py devono corrispondere a quelli del passaggio 5.

Il lavoro sui file di configurazione è terminato, quindi passiamo all'applicazione.

5. Modificare i file dell'applicazione

Importazioni

Il primo insieme di modifiche per main.py include la sostituzione di tutti gli elementi da sostituire. Ecco cosa cambierà:

  1. webapp2 viene sostituito da Flask
  2. Anziché utilizzare Jinja2 da webapp2_extras, utilizza Jinja2 fornito con Flask
  3. App Engine Blobstore e NDB vengono sostituiti da Cloud NDB e Cloud Storage
  4. I gestori Blobstore in webapp vengono sostituiti da una combinazione del modulo della libreria standard io, Flask e delle utilità werkzeug
  5. Per impostazione predefinita, Blobstore scrive in un bucket Cloud Storage denominato in base all'URL dell'app (PROJECT_ID.appspot.com). Poiché stiamo eseguendo il porting alla libreria client Cloud Storage, google.auth viene utilizzato per ottenere l'ID progetto per specificare esattamente lo stesso nome del bucket. Puoi modificare il nome del bucket perché non è più hardcoded.

PRIMA:

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

Implementa le modifiche nell'elenco riportato sopra sostituendo la sezione di importazione corrente in main.py con lo snippet di codice riportato di seguito.

DOPO:

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

Inizializzazione e supporto Jinja2 non necessario

Il blocco di codice successivo da sostituire è BaseHandler, che specifica l'utilizzo di Jinja2 da webapp2_extras. Questo passaggio è superfluo perché Jinja2 è incluso in Flask ed è il motore di modelli predefinito, quindi rimuovilo.

Sul lato del modulo 16, crea istanze degli oggetti che non avevamo nell'app precedente. Ciò include l'inizializzazione dell'app Flask e la creazione di client API per Cloud NDB e Cloud Storage. Infine, abbiamo assemblato il nome del bucket Cloud Storage come descritto sopra nella sezione delle importazioni. Ecco la situazione prima e dopo l'implementazione di questi aggiornamenti:

PRIMA:

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

DOPO:

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

Aggiorna l'accesso al datastore

Cloud NDB è per lo più compatibile con App Engine NDB. Una differenza già trattata è la necessità di un client API. Un altro è che quest'ultimo richiede che l'accesso a Datastore sia controllato dal gestore di contesto Python del client API. In sostanza, ciò significa che tutte le chiamate di accesso a Datastore che utilizzano la libreria client Cloud NDB possono verificarsi solo all'interno dei blocchi Python with.

Questa è una modifica; l'altra è che Blobstore e i relativi oggetti, ad esempio BlobKey, non sono supportati da Cloud Storage, quindi modifica file_blob in modo che sia un ndb.StringProperty. Di seguito sono riportate la classe del modello di dati e le funzioni store_visit() e fetch_visits() aggiornate che riflettono queste modifiche:

PRIMA:

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)

DOPO:

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)

Ecco una rappresentazione illustrata delle modifiche apportate finora:

a8f74ca392275822.png

Aggiornamento degli handler

Gestore caricamento

I gestori in webapp2 sono classi, mentre in Flask sono funzioni. Anziché un metodo HTTP verb, Flask utilizza il verbo per decorare la funzione. Blobstore e i relativi gestori webapp vengono sostituiti dalla funzionalità di Cloud Storage, nonché da Flask e dalle relative utilità:

PRIMA:

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)

DOPO:

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

Alcune note relative a questo aggiornamento:

  • Anziché un blob_id, gli artefatti dei file vengono ora identificati dal nome file (fname), se presente, e None in caso contrario (l'utente ha disattivato il caricamento di un file).
  • I gestori Blobstore hanno estratto il processo di caricamento dai suoi utenti, ma Cloud Storage no, quindi puoi vedere il codice appena aggiunto che imposta l'oggetto blob e la posizione (bucket) del file, nonché la chiamata che esegue il caricamento effettivo. (upload_from_file()).
  • webapp2 utilizza una tabella di routing nella parte inferiore del file dell'applicazione, mentre le route Flask si trovano in ogni gestore decorato.
  • Entrambi i gestori completano la loro funzionalità reindirizzando alla home page ( / ) mantenendo la richiesta POST con un codice restituito HTTP 307.

Gestore dei download

L'aggiornamento del gestore di download segue un pattern simile a quello del gestore di caricamento, ma c'è molto meno codice da esaminare. Sostituisci la funzionalità Blobstore e webapp con gli equivalenti Cloud Storage e Flask:

PRIMA:

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)

DOPO:

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

Note su questo aggiornamento:

  • Anche in questo caso, Flask decora le funzioni di gestione con la relativa route, mentre webapp lo fa in una tabella di routing in basso, quindi riconosci la sintassi di corrispondenza dei pattern di quest'ultimo (('/view/([^/]+)?') rispetto a quella di Flask ('/view/<path:fname>').
  • Come per il gestore di caricamento, è necessario un po' più di lavoro sul lato Cloud Storage per la funzionalità astratta dai gestori Blobstore, ovvero identificare il file (blob) in questione e scaricare esplicitamente il binario rispetto alla singola chiamata al metodo send_blob() del gestore Blobstore.
  • In entrambi i casi, all'utente viene restituito un errore HTTP 404 se non viene trovato un artefatto.

Main handler

Le modifiche finali all'applicazione principale vengono apportate nel gestore principale. I metodi dei verbi HTTP webapp2 vengono sostituiti da una singola funzione che combina la loro funzionalità. Sostituisci la classe MainHandler con la funzione root() e rimuovi la tabella di routing webapp2 come mostrato di seguito:

PRIMA:

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)

DOPO:

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

Anziché metodi get() e post() separati, si tratta essenzialmente di un'istruzione if-else in root(). Inoltre, poiché root() è una singola funzione, esiste una sola chiamata per il rendering del modello sia per GET che per POST, mentre non è possibile in webapp2.

Di seguito è riportata una rappresentazione illustrata di questo secondo e ultimo insieme di modifiche a main.py:

5ec38818c32fec2.png

(Facoltativo) "Miglioramento" della compatibilità con le versioni precedenti

Quindi la soluzione creata sopra funziona perfettamente, ma solo se parti da zero e non hai file creati da Blobstore. Poiché abbiamo aggiornato l'app per identificare i file in base al nome file anziché a BlobKey, l'app del Modulo 16 completata così com'è non sarà in grado di visualizzare i file Blobstore. In altre parole, abbiamo apportato una modifica non compatibile con le versioni precedenti durante questa migrazione. Ora presentiamo una versione alternativa di main.py chiamata main-migrate.py (disponibile nel repository) che tenta di colmare questa lacuna.

La prima "estensione" a supportare i file creati da Blobstore è un modello di dati che ha un BlobKeyProperty (oltre a un StringProperty per i file creati da 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()

La proprietà file_blob verrà utilizzata per identificare i file creati da Blobstore, mentre file_gcs per i file Cloud Storage. Ora, quando crei nuove visite, memorizza esplicitamente un valore in file_gcs anziché in file_blob, quindi store_visit ha un aspetto leggermente diverso:

PRIMA:

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

DOPO:

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

Quando recuperi le visite più recenti, "normalizza" i dati prima di inviarli al modello:

PRIMA:

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

DOPO:

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

Successivamente, conferma l'esistenza di file_blob o file_gcs (o di nessuno dei due). Se è disponibile un file, scegli quello esistente e utilizza l'identificatore (BlobKey per i file creati da Blobstore o il nome file per i file creati da Cloud Storage). Quando parliamo di "file creati da Cloud Storage", ci riferiamo ai file creati utilizzando la libreria client di Cloud Storage. Blobstore scrive anche in Cloud Storage, ma in questo caso si tratta di file creati da Blobstore.

Ancora più importante, che cos'è questa funzione etl_visits() utilizzata per normalizzare o ETL (estrazione, trasformazione e caricamento) i dati per l'utente finale? Ha questo aspetto:

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]

Probabilmente l'aspetto è quello che ti aspettavi: il codice scorre tutte le visite e, per ciascuna, prende i dati del visitatore e del timestamp letteralmente, poi controlla se esistono file_gcs o file_blob e, in caso affermativo, ne sceglie uno (o None se non esiste nessuno dei due).

Ecco un'illustrazione delle differenze tra main.py e main-migrate.py:

718b05b2adadb2e1.png

Se parti da zero senza file creati da Blobstore, utilizza main.py, ma se stai eseguendo la transizione e vuoi supportare i file creati sia da Blobstore che da Cloud Storage, consulta main-migrate.py come esempio di come gestire scenari simili per pianificare le migrazioni per le tue app. Quando si eseguono migrazioni complesse, è probabile che si presentino casi speciali, quindi questo esempio ha lo scopo di mostrare una maggiore affinità con la modernizzazione di app reali con dati reali.

6. Riepilogo/Pulizia

Questa sezione conclude il codelab eseguendo il deployment dell'app, verificando che funzioni come previsto e in qualsiasi output riflesso. Dopo la convalida dell'app, esegui i passaggi di pulizia e valuta i passaggi successivi.

Esegui il deployment e verifica l'applicazione

Prima di eseguire nuovamente il deployment dell'app, assicurati di eseguire pip install -t lib -r requirements.txt per inserire le librerie di terze parti auto-raggruppate nella cartella lib. Se vuoi eseguire la soluzione compatibile con le versioni precedenti, rinomina prima main-migrate.py come main.py. Ora esegui gcloud app deploy e verifica che l'app funzioni in modo identico all'app del modulo 15. La schermata del modulo ha questo aspetto:

f5b5f9f19d8ae978.png

La pagina delle visite più recenti ha questo aspetto:

f5ac6b98ee8a34cb.png

Congratulazioni per aver completato questo codelab sostituendo App Engine Blobstore con Cloud Storage, App Engine NDB con Cloud NDB e webapp2 con Flask. Il codice ora dovrebbe corrispondere a quello della cartella FINISH (Modulo 16). Nella cartella è presente anche l'alternativa main-migrate.py.

"Migrazione" a Python 3

La direttiva Python 3 runtime commentata nella parte superiore di app.yaml è tutto ciò che serve per eseguire il porting di questa app a Python 3. Il codice sorgente è già compatibile con Python 3, quindi non sono necessarie modifiche. Per eseguire il deployment come app Python 3, segui questi passaggi:

  1. Rimuovi il commento dalla direttiva Python 3 runtime nella parte superiore di app.yaml.
  2. Elimina tutte le altre righe in app.yaml.
  3. Elimina il file appengine_config.py. (non utilizzato nel runtime Python 3)
  4. Elimina la cartella lib, se esiste. (non necessario con il runtime Python 3)

Esegui la pulizia

Generale

Se hai finito per il momento, ti consigliamo di disattivare l'app App Engine per evitare addebiti. Tuttavia, se vuoi fare altri test o esperimenti, la piattaforma App Engine ha una quota senza costi e, finché non superi questo livello di utilizzo, non ti verranno addebitati costi. Questo vale per il calcolo, ma potrebbero essere addebitati anche costi per i servizi App Engine pertinenti, quindi consulta la pagina dei prezzi per ulteriori informazioni. Se questa migrazione coinvolge altri servizi cloud, questi vengono fatturati separatamente. In entrambi i casi, se applicabile, consulta la sezione "Specifiche per questo codelab" di seguito.

Per una divulgazione completa, il deployment su una piattaforma di calcolo serverless di Google Cloud come App Engine comporta costi di build e archiviazione minimi. Cloud Build ha una propria quota senza costi, così come Cloud Storage. L'archiviazione di questa immagine utilizza parte della quota. Tuttavia, potresti vivere in una regione che non dispone di un livello senza costi, quindi tieni sotto controllo l'utilizzo dello spazio di archiviazione per ridurre al minimo i potenziali costi. Le "cartelle" Cloud Storage specifiche che devi esaminare includono:

  • 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
  • I link di archiviazione riportati sopra dipendono dalla tua PROJECT_ID e dalla tua *LOC*, ad esempio "us" se la tua app è ospitata negli Stati Uniti.

D'altra parte, se non intendi continuare con questa applicazione o con altri codelab di migrazione correlati e vuoi eliminare tutto completamente, chiudi il progetto.

Specifico per questo codelab

I servizi elencati di seguito sono univoci per questo codelab. Per saperne di più, consulta la documentazione di ogni prodotto:

Tieni presente che se hai eseguito la migrazione dal modulo 15 al 16, avrai ancora dati in Blobstore, motivo per cui includiamo le informazioni sui prezzi riportate sopra.

Passaggi successivi

Oltre a questo tutorial, altri moduli di migrazione che si concentrano sul passaggio dai servizi in bundle legacy da prendere in considerazione includono:

  • Modulo 2: esegui la migrazione da App Engine ndb a Cloud NDB
  • Moduli 7-9: esegui la migrazione delle attività push di App Engine Task Queue a Cloud Tasks
  • Moduli 12-13: esegui la migrazione da Memcache App Engine a Cloud Memorystore
  • Moduli 18-19: esegui la migrazione dalla coda di attività App Engine (attività pull) a Cloud Pub/Sub

App Engine non è più l'unica piattaforma serverless in Google Cloud. Se hai una piccola app App Engine o una con funzionalità limitate e vuoi trasformarla in un microservizio autonomo oppure vuoi suddividere un'app monolitica in più componenti riutilizzabili, questi sono buoni motivi per prendere in considerazione il passaggio a Cloud Functions. Se la containerizzazione è diventata parte del flusso di lavoro di sviluppo delle applicazioni, in particolare se consiste in una pipeline CI/CD (integrazione continua/distribuzione continua o deployment continuo), valuta la migrazione a Cloud Run. Questi scenari sono trattati nei seguenti moduli:

  • Esegui la migrazione da App Engine a Cloud Functions: consulta il modulo 11
  • Esegui la migrazione da App Engine a Cloud Run: consulta il modulo 4 per inserire la tua app in un container con Docker o il modulo 5 per farlo senza container, conoscenze di Docker o Dockerfiles

Il passaggio a un'altra piattaforma serverless è facoltativo e ti consigliamo di valutare le opzioni migliori per le tue app e i tuoi casi d'uso prima di apportare modifiche.

Indipendentemente dal modulo di migrazione che prenderai in considerazione, tutti i contenuti di Serverless Migration Station (codelab, video, codice sorgente [se disponibile]) sono accessibili nel relativo repository open source. Il repository README fornisce anche indicazioni sulle migrazioni da prendere in considerazione e sull'eventuale "ordine" dei moduli di migrazione pertinenti.

7. Risorse aggiuntive

Problemi/feedback relativi ai codelab

Se riscontri problemi con questo codelab, cerca prima il tuo problema prima di presentare una segnalazione. Link per cercare e creare nuovi problemi:

Risorse per la migrazione

I link alle cartelle del repository per il Modulo 15 (INIZIO) e il Modulo 16 (FINE) sono disponibili nella tabella riportata di seguito. Puoi accedervi anche dal repository per tutte le migrazioni dei codelab di App Engine, che puoi clonare o scaricare come file ZIP.

Codelab

Python 2

Python 3

Modulo 15

code

N/A

Modulo 16 (questo codelab)

code

(come Python 2)

Risorse online

Di seguito sono riportate risorse online che potrebbero essere pertinenti per questo tutorial:

App Engine Blobstore e Cloud Storage

Piattaforma App Engine

Altre informazioni sul cloud

Python

Video

Licenza

Questo lavoro è concesso in licenza ai sensi di una licenza Creative Commons Attribution 2.0 Generic.