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

1. Panoramica

La serie di codelab Serverless Migration Station (tutorial pratici autogestiti) e i video correlati mirano ad aiutare gli sviluppatori di Google Cloud serverless a modernizzare le loro applicazioni guidandoli attraverso una o più migrazioni, principalmente l'abbandono dei servizi legacy. In questo modo, le tue app sono più portabili e hai più opzioni e flessibilità, il che ti consente di integrarle e accedere a una gamma più ampia di prodotti Cloud ed eseguire più facilmente l'upgrade alle versioni più recenti dei linguaggi. 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 altre, se applicabile.

Questo codelab ti insegna come eseguire la migrazione dall'archivio BLOB di App Engine a Cloud Storage. Esistono anche migrazioni implicite da:

Per ulteriori informazioni dettagliate, consulta i moduli di migrazione correlati.

Imparerai a utilizzare

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

Che cosa ti serve

Sondaggio

Come utilizzerai questo tutorial?

Leggerlo e basta Leggerlo e completare gli esercizi

Come valuteresti la tua esperienza con Python?

Principiante Intermedio Esperto

Come valuteresti la tua esperienza con l'utilizzo dei servizi Google Cloud?

Principiante Intermedio Esperto

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 in 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 lo desideri.

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

L'app registra ancora le "visite" degli utenti finali e visualizza le dieci più recenti, ma il codelab precedente (Modulo 15) ha aggiunto una nuova funzionalità per l'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 mostra lo stesso output delle versioni precedenti di questa app, visualizzando le visite più recenti. Un'ulteriore particolarità è che le visite con artefatti corrispondenti presentano un link "Visualizza" per visualizzare l'artefatto di una visita. Questo codelab implementa le migrazioni menzionate in precedenza, preservando al contempo la funzionalità descritta.

3. Configurazione/preparazione

Prima di passare alla parte principale del tutorial, configuriamo il progetto, recuperiamo il codice ed eseguiamo il deployment dell'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 lo stesso codice). In alternativa, puoi creare un nuovo progetto o riutilizzare un altro progetto esistente. Assicurati che il progetto abbia un account di fatturazione attivo e che App Engine sia abilitato.

2. Scarica 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 attraverso ogni passaggio, per concludere con un codice simile a quello presente nella cartella "FINISH" del Modulo 16.

La directory dei file START 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 dall'URL predefinito assegnato a un'app in base all'ID del progetto: PROJECT_ID.appspot.com. Questo file non ha alcun ruolo in questo codelab (Modulo 16), se non che è possibile applicare tecniche di migrazione simili a questo file, se lo si desidera.

3. (Riesegui il) deployment dell'app di base

I passaggi rimanenti della preparazione da eseguire ora:

  1. Acquisisci nuovamente 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

Dopo aver eseguito correttamente questi passaggi e aver confermato che l'app del Modulo 15 funziona, La pagina iniziale accoglie gli utenti con un modulo che richiede di caricare un file di artefatto della visita, insieme a un'opzione, un pulsante "Salta", per disattivare la funzionalità:

f5b5f9f19d8ae978.png

Una volta che gli utenti caricano un file o saltano il passaggio, l'app mostra la pagina familiare "Visite più recenti":

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, potrai eseguire la migrazione dai servizi legacy di App Engine (webapp2, NDB, Blobstore) alle alternative moderne (Flask, Cloud NDB, Cloud Storage).

4. Aggiorna i file di configurazione

Per la versione aggiornata della nostra app entrano in gioco tre file di configurazione. Le attività richieste sono:

  1. Aggiornare le librerie di terze parti integrate richieste in app.yaml e lasciare aperta la porta a una migrazione a Python 3
  2. Aggiungi un requirements.txt che specifichi tutte le librerie richieste che non sono integrate
  3. Aggiungi appengine_config.py in modo che l'app supporti sia le librerie di terze parti integrate sia quelle 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 l'istruzione 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

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

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 serve per quando è tutto pronto per eseguire il porting di questa app in 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 di Cloud NDB e Cloud Storage, nessuna delle quali è integrata. Crea il file con questi contenuti:

flask
google-cloud-ndb
google-cloud-storage

Il runtime Python 2 di App Engine richiede l'auto-bundling di 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 che 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 eseguire 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 questi contenuti:

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 dovrebbero essere simili o identici a quelli elencati nella sezione Installazione di librerie per app Python 2 della documentazione di App Engine e, più in particolare, i contenuti di appengine_config.py dovrebbero corrispondere a quelli del passaggio 5.

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

5. Modifica i file dell'applicazione

Importazioni

Il primo set 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. Blobstore e NDB di App Engine vengono sostituiti da Cloud NDB e Cloud Storage
  4. I gestori di 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 di 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 poiché non è più impostato come 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 l'attuale sezione di importazione in main.py con lo snippet di codice riportato di seguito.

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

Inizializzazione e supporto Jinja2 non necessario

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

Sul lato del Modulo 16, crea un'istanza 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, creiamo il nome del bucket Cloud Storage come descritto sopra nella sezione delle importazioni. Ecco i risultati 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))

AFTER:

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 a Datastore

Cloud NDB è per lo più compatibile con App Engine NDB. Una differenza già trattata è la necessità di un client API. Un'altra è che quest'ultimo richiede che l'accesso a Datastore sia controllato dal gestore del 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 essere eseguite solo all'interno di blocchi Python with.

Questa è una modifica; l'altra è che Blobstore e i suoi oggetti, ad esempio BlobKey, non sono supportati da Cloud Storage, quindi modifica file_blob in modo che sia 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)

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)

Ecco una rappresentazione grafica delle modifiche apportate finora:

a8f74ca392275822.png

Aggiornamento dei gestori

Gestore di caricamento

I gestori in webapp2 sono classi, mentre in Flask sono funzioni. Anziché un metodo con verbo HTTP, Flask utilizza il verbo per decorare la funzione. Blobstore e i relativi gestori webapp vengono sostituiti dalle 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)

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)

Alcune note su questo aggiornamento:

  • Anziché un blob_id, gli artefatti dei file sono ora identificati dal nome file (fname), se presente, e da None in caso contrario (l'utente ha disattivato il caricamento di un file).
  • I gestori di Blobstore hanno astratto il processo di caricamento dai suoi utenti, ma Cloud Storage non lo fa, 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 di Flask si trovano in ogni gestore decorato.
  • Entrambi i gestori concludono la loro funzionalità reindirizzando alla home page ( /) e conservando la richiesta POST con un codice di ritorno HTTP 307.

Gestore dei download

L'aggiornamento del gestore dei download segue un pattern simile a quello del gestore dei caricamenti, ma con molto meno codice da esaminare. Sostituisci la funzionalità Blobstore e webapp con gli equivalenti di 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)

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)

Note su questo aggiornamento:

  • Anche in questo caso, Flask decora le funzioni di gestione con la loro 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 dei caricamenti, sul lato Cloud Storage è necessario un po' di lavoro in più per le funzionalità astratte dai gestori Blobstore, ovvero l'identificazione del file (blob) in questione e il download esplicito del file binario rispetto alla singola chiamata al metodo send_blob() del gestore Blobstore.
  • In entrambi i casi, se un artefatto non viene trovato, all'utente viene restituito un errore HTTP 404.

Gestore principale

Le modifiche finali all'applicazione principale vengono apportate nel gestore principale. I metodi dei verbi HTTP webapp2 vengono sostituiti da una singola funzione che ne combina le 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)

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)

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

Ecco una rappresentazione grafica di questa seconda e ultima serie di modifiche a main.py:

5ec38818c32fec2.png

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

La soluzione creata sopra funziona perfettamente, ma solo se inizi 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 di Blobstore. In altre parole, abbiamo apportato una modifica incompatibile con le versioni precedenti eseguendo 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" per 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 di Cloud Storage. Ora, quando crei nuove visite, memorizza esplicitamente un valore in file_gcs anziché in file_blob, in modo che store_visit abbia 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()

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

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)

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)

Poi, 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 diciamo "file creati da Cloud Storage", intendiamo i file creati utilizzando la libreria client di Cloud Storage. Anche Blobstore scrive in Cloud Storage, ma in questo caso si tratta di file creati da Blobstore.

Ora, cosa più importante, cos'è questa funzione etl_visits() utilizzata per normalizzare o eseguire l'ETL (estrazione, trasformazione e caricamento) dei 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 è come ti aspettavi: il codice esegue un loop di tutte le visite e, per ogni visita, prende i dati del visitatore e del timestamp alla lettera, poi controlla se esiste file_gcs o file_blob e, se sì, 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 inizi 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 sia da Cloud Storage, dai un'occhiata a main-migrate.py come esempio di come gestire uno scenario simile per aiutarti a pianificare le migrazioni per le tue app. Quando si eseguono migrazioni complesse, è probabile che si verifichino 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 questo codelab con il deployment dell'app, la verifica del suo funzionamento come previsto e l'analisi dell'output generato. Dopo la convalida dell'app, esegui i passaggi di pulizia e valuta i passaggi successivi.

Esegui il deployment e verifica l'applicazione

Prima di rifare il deployment dell'app, assicurati di eseguire pip install -t lib -r requirements.txt per inserire le librerie di terze parti raggruppate autonomamente nella cartella lib. Se vuoi eseguire la soluzione compatibile con le versioni precedenti, rinomina prima main-migrate.py in 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 il seguente aspetto:

f5b5f9f19d8ae978.png

La pagina delle visite più recenti ha questo aspetto:

f5ac6b98ee8a34cb.png

Complimenti per aver completato questo codelab che sostituisce Blobstore di App Engine con Cloud Storage, NDB di App Engine con Cloud NDB e webapp2 con Flask. Il codice ora dovrebbe corrispondere a quello nella cartella FINISH (Module 16). Anche l'alternativa main-migrate.py è presente in quella cartella.

"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 su 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, ti consigliamo di disattivare l'app App Engine per evitare addebiti. Tuttavia, se vuoi eseguire altri test o esperimenti, la piattaforma App Engine ha una quota senza costi, quindi, se non superi questo livello di utilizzo, non ti verranno addebitati costi. Questo vale per il computing, ma potrebbero essere addebitati anche i 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 "Specifico per questo codelab" di seguito.

Per completezza, il deployment su una piattaforma di serverless computing di Google Cloud come App Engine comporta costi minimi di build e archiviazione. Cloud Build ha una propria quota senza costi, così come Cloud Storage. L'archiviazione di questa immagine utilizza parte di questa quota. Tuttavia, potresti vivere in una regione che non dispone di un livello senza costi, quindi tieni d'occhio l'utilizzo dello spazio di archiviazione per ridurre al minimo i potenziali costi. Le "cartelle" di 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 allo spazio di archiviazione riportati sopra dipendono dal tuo PROJECT_ID e dalla tua *LOC*azione, ad esempio "us" se la tua app è ospitata negli Stati Uniti.

Se invece non intendi continuare con questa applicazione o con altri codelab di migrazione correlati e vuoi eliminare tutto, 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 ciascun 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 incentrati sull'abbandono dei servizi in bundle legacy da considerare includono:

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

App Engine non è più l'unica piattaforma serverless di Google Cloud. Se hai un'app App Engine di piccole dimensioni o con funzionalità limitate e vuoi trasformarla in un microservizio autonomo oppure se 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 possibilità di eseguire 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 containerizzare la tua app con Docker o il Modulo 5 per farlo senza container, conoscenze di Docker o Dockerfile

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 qualsiasi modifica.

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

7. Risorse aggiuntive

Problemi/feedback relativi ai codelab

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

Risorse per la migrazione

I link alle cartelle del repository per il Modulo 15 (START) e il Modulo 16 (FINISH) sono disponibili nella tabella seguente. 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 per Python 2)

Risorse online

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

Blobstore di App Engine 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.