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

1. Panoramica

La serie di codelab Serverless Migration Station (tutorial pratici e self-service) e i video correlati mirano ad aiutare gli sviluppatori Google Cloud serverless a modernizzare le applicazioni guidandoli attraverso una o più migrazioni, principalmente abbandonando i servizi legacy. In questo modo le tue app saranno più portabili e avrai più opzioni e flessibilità, consentendoti di integrare e accedere a una gamma più ampia di prodotti Cloud e di eseguire più facilmente l'upgrade a release delle lingue più recenti. Pur concentrandosi inizialmente sui primi utenti di Cloud, principalmente sviluppatori di App Engine (ambiente standard), questa serie è sufficientemente ampia da includere altre piattaforme serverless come Cloud Functions e Cloud Run, o altrove, 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 informazioni più dettagliate, fai riferimento agli eventuali moduli di migrazione correlati.

Imparerai a utilizzare

  • Aggiungi utilizzo dell'API/libreria App Engine Blobstore
  • Archiviare i caricamenti degli utenti sul servizio Blobstore
  • Preparati per il passaggio successivo della migrazione a Cloud Storage

Che cosa ti serve

Sondaggio

Come utilizzerai questo tutorial?

Solo lettura Leggilo e completa gli esercizi

Come valuteresti la tua esperienza con Python?

Principiante Livello intermedio Eccellente

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

Principiante Livello intermedio Eccellente

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 comporta la sostituzione delle dipendenze nei servizi in bundle legacy di App Engine, che consentono di spostare le app su un'altra piattaforma serverless Cloud o un'altra piattaforma di hosting, se lo desideri.

Questa migrazione richiede un po' più di impegno rispetto alle altre migrazioni di questa serie. Il Blobstore ha dipendenze rispetto al framework originale dell'app web ed è per questo che 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 continua a registrare le "visite" degli utenti finali e mostra i dieci più recenti, ma il codelab precedente (Modulo 15) ha aggiunto nuove funzionalità per consentire 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" la disattivazione. Indipendentemente dalla decisione dell'utente, nella pagina successiva viene visualizzato lo stesso output delle versioni precedenti dell'app, visualizzando le visite più recenti. Un'altra novità è che le visite con gli artefatti corrispondenti presentano una "vista" link per visualizzare l'elemento di una visita. Questo codelab implementa le migrazioni menzionate in precedenza mantenendo la funzionalità descritta.

3. Configurazione/pre-lavoro

Prima di passare alla parte principale del tutorial, impostiamo il progetto, recuperiamo il codice ed eseguiamo il deployment dell'app di base in modo da sapere di aver iniziato con il 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. Ottieni app di esempio di riferimento

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

La directory dei file STARTing del modulo 15 dovrebbe essere simile alla seguente:

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

Il file main-gcs.py è una versione alternativa di main.py rispetto al Modulo 15 che consente di selezionare un bucket Cloud Storage diverso da quello predefinito dell'URL assegnato a un'app in base all'ID progetto: PROJECT_ID.appspot.com. Se lo desideri, questo file non ha alcun ruolo in questo codelab (Modulo 16) ad eccezione di tecniche di migrazione simili.

3. (Ri)Esegui il deployment dell'app di base

I passaggi preliminari rimanenti da eseguire ora:

  1. Acquisisci 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 verificato che l'app del Modulo 15 funzioni, La pagina iniziale accoglie gli utenti con un modulo che richiede il caricamento di un file dell'artefatto visita insieme a un'opzione, "salta" pulsante, per disattivare:

f5b5f9f19d8ae978.png

Quando gli utenti caricano o saltano un file, l'app mostra le "visite più recenti" che già conosci. pagina:

f5ac6b98ee8a34cb.png

Le visite contenenti un artefatto avranno una "visualizzazione" link a destra del timestamp della visita per visualizzare (o scaricare) l'elemento. Dopo aver verificato la funzionalità dell'app, puoi eseguire la migrazione dai servizi legacy di App Engine (webapp2, NDB, Blobstore) alle alternative contemporanee (Flask, Cloud NDB, Cloud Storage).

4. Aggiorna i file di configurazione

Per la versione aggiornata dell'app entrano in gioco tre file di configurazione. Le attività obbligatorie sono:

  1. Aggiorna le librerie di terze parti integrate necessarie in app.yaml e lascia la porta aperta per la migrazione a Python 3
  2. Aggiungi un valore 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 che non integrate

app.yaml

Modifica il file app.yaml aggiornando la sezione libraries. Rimuovi jinja2 e aggiungi grpcio, setuptools e ssl. Scegli la versione più recente disponibile per tutte e tre le librerie. Aggiungi anche l'istruzione Python 3 runtime, ma con un commento. Al termine, l'aspetto dovrebbe essere simile a questo (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, quindi non è necessario raggrupparle autonomamente. Abbiamo rimosso Jinja2 perché include Flask, che aggiungeremo al file reqs.txt. Ogni volta che vengono utilizzate librerie client di Google Cloud, come quelle per Cloud NDB e Cloud Storage, sono necessari grpcio e setuptools. Infine, Cloud Storage richiede la libreria SSL. L'istruzione di runtime commentata in alto serve per quando è tutto pronto per la portabilità dell'app in Python 3. Questo argomento verrà trattato alla fine del tutorial.

requirements.txt

Aggiungi un file requirements.txt che richieda il framework Flask e le librerie client di Cloud NDB e Cloud Storage, nessuno dei quali è integrato. Crea il file con questi contenuti:

flask
google-cloud-ndb
google-cloud-storage

Il runtime Python 2 di App Engine richiede il raggruppamento autonomo delle librerie di terze parti non integrate, quindi esegui questo comando per installare queste librerie nella cartella lib:

pip install -t lib -r requirements.txt

Se hai sia Python 2 che 3 sulla tua macchina di sviluppo, potresti dover usare 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 creare autonomamente il bundle.

appengine_config.py

Aggiungi un file appengine_config.py che supporti le 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 le app Python 2 della documentazione su App Engine e, in particolare, i contenuti di appengine_config.py dovrebbero corrispondere a quelli del passaggio 5.

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

5. Modifica i file delle applicazioni

Importazioni

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

  1. webapp2 è stato sostituito da Flask
  2. Invece di utilizzare Jinja2 di webapp2_extras, usa Jinja2 fornito con Flask
  3. L'archivio BLOB e NDB di App Engine sono sostituiti da Cloud NDB e Cloud Storage
  4. I gestori Blobstore in webapp vengono sostituiti da una combinazione delle utilità io del modulo della libreria standard, Flask e werkzeug
  5. Per impostazione predefinita, l'archivio BLOB scrive in un bucket Cloud Storage denominato in base all'URL dell'app (PROJECT_ID.appspot.com). Poiché è in corso la portabilità alla libreria client di Cloud Storage, google.auth viene utilizzato per ottenere l'ID progetto in modo da specificare esattamente lo stesso nome di 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

Implementare le modifiche nell'elenco precedente 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'uso di Jinja2 da webapp2_extras. Questo non è necessario perché Jinja2 viene fornito con Flask ed è il suo motore di modelli predefinito, quindi rimuovilo.

Sul lato del Modulo 16, crea un'istanza degli oggetti che non erano presenti nell'app precedente. Ciò include l'inizializzazione dell'app Flask e la creazione di client API per Cloud NDB e Cloud Storage. Infine, abbiamo creato il nome del bucket Cloud Storage, come descritto sopra nella sezione Importazioni. Ecco le fasi 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 accesso a Datastore

Cloud NDB è per lo più compatibile con l'NDB di App Engine. Una differenza già contemplata è 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, questo significa che tutte le chiamate di accesso a Datastore che utilizzano la libreria client di Cloud NDB possono avvenire solo all'interno dei blocchi Python with.

Questa è una modifica: l'altra è che l'archivio BLOB e i suoi oggetti, ad esempio BlobKey non sono supportati da Cloud Storage, quindi modifica file_blob in ndb.StringProperty. Di seguito sono riportate la classe del modello dei 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 grafica delle modifiche apportate finora:

a8f74ca392275822.png

Aggiornamento dei gestori

Gestore caricamento

I gestori in webapp2 sono classi mentre svolgono funzioni in Flask. Invece di un metodo verbale HTTP, Flask utilizza il verbo per decorare la funzione. L'archivio BLOB e i relativi gestori webapp sono sostituiti dalla funzionalità di Cloud Storage, nonché da Flask e dalle sue 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é blob_id, gli elementi dei file sono ora identificati dal nome del file (fname), se presente, e da None in caso contrario (l'utente ha disattivato il caricamento di un file).
  • I gestori dell'archivio BLOB hanno astrae il processo di caricamento dagli utenti, ma Cloud Storage non lo fa. Di conseguenza, 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 aggregano la loro funzionalità reindirizzando alla home page ( /), preservando la richiesta POST con un codice restituito HTTP 307.

Gestore dei download

L'aggiornamento del gestore dei download segue uno schema simile a quello del gestore del caricamento, ma c'è molto meno codice da esaminare. Sostituisci l'archivio BLOB e la funzionalità 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)

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:

  • Ancora una volta, Flask decora le funzioni dei gestori con la rispettiva route, mentre webapp la esegue in una tabella di routing nella parte inferiore, quindi riconosce la sintassi di corrispondenza dei pattern di quest'ultima ('/view/([^/]+)?') rispetto a quella di Flask ('/view/<path:fname>').
  • Come per il gestore di caricamento, è richiesto un po' più di lavoro da parte di Cloud Storage per la funzionalità astratta dai gestori dell'archivio BLOB, ovvero l'identificazione del file (blob) in questione e il download esplicito della singola chiamata al metodo send_blob() del gestore binario o dell'archivio BLOB.
  • In entrambi i casi, se non viene trovato un artefatto, all'utente viene restituito un errore HTTP 404.

Gestore principale

Le modifiche finali all'applicazione principale avvengono nel gestore principale. I metodi verbo HTTP webapp2 sono sostituiti da un'unica funzione che ne combina la 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é separare i metodi get() e post(), si tratta essenzialmente di un'istruzione if-else in root(). Inoltre, poiché root() è una singola funzione, esiste una sola chiamata per eseguire il rendering del modello sia per GET sia per POST, mentre in webapp2 non è possibile.

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

Quindi la soluzione creata sopra funziona perfettamente... ma solo se stai iniziando da zero e non hai file creati da Blobstore. Poiché abbiamo aggiornato l'app per identificare i file per nome invece che per BlobKey, l'app del modulo 16 completata così com'è non sarà in grado di visualizzare i file dell'archivio BLOB. In altre parole, durante questa migrazione abbiamo apportato una modifica incompatibile con le versioni precedenti. Ora presentiamo una versione alternativa di main.py denominata main-migrate.py (trovata nel repository) che tenta di colmare questo divario.

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

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 un po' 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()

Durante il recupero delle 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)

Ora conferma l'esistenza di file_blob o file_gcs (o nessuno dei due). Se è disponibile un file, scegli quello esistente e utilizza questo identificatore (BlobKey per i file creati dall'archivio BLOB o il nome file per i file creati da Cloud Storage). Quando diciamo "File creati in Cloud Storage", intendiamo i file creati utilizzando la libreria client di Cloud Storage. Anche l'archivio BLOB scrive in Cloud Storage, ma in questo caso si tratta di file creati da Blobstore.

Ora, cosa ancora più importante, qual è la funzione etl_visits() utilizzata per normalizzare o ETL (estrarre, trasformare e caricare) 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 sembra quello che ti aspettavi: il codice si ripete in tutte le visite e, per ogni visita, esamina i dati del visitatore e del timestamp, dopodiché verifica se file_gcs o file_blob esistono e, in tal caso, ne sceglie una (o None se nessuno dei due esiste).

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 file di supporto creati sia da Blobstore sia Cloud Storage, dai un'occhiata a main-migrate.py come esempio di come gestire uno scenario come 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à per la modernizzazione delle app reali con dati reali.

6. Riepilogo/Pulizia

In questa sezione si conclude questo codelab eseguendo il deployment dell'app e verificando che funzioni come previsto e in qualsiasi output riportato. Dopo la convalida dell'app, esegui tutti i passaggi di pulizia e considera 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-in bundle 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 il seguente aspetto:

f5b5f9f19d8ae978.png

La pagina delle visite più recenti ha il seguente aspetto:

f5ac6b98ee8a34cb.png

Complimenti per aver completato questo codelab per la sostituzione dell'archivio BLOB di App Engine con Cloud Storage, dell'NDB di App Engine con Cloud NDB e di webapp2 con Flask. Il codice dovrebbe corrispondere al contenuto della cartella FINISH (Modulo 16). In questa cartella è presente anche l'alternativa main-migrate.py.

"Migrazione" Python 3

L'istruzione Python 3 runtime commentato nella parte superiore di app.yaml è tutto ciò che serve per portare questa app in Python 3. Il codice sorgente stesso è già compatibile con Python 3, quindi non sono necessarie modifiche. Per eseguire il deployment come app Python 3, esegui questi passaggi:

  1. Rimuovi il commento dall'istruzione 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 di Python 3)
  4. Elimina la cartella lib, se esistente. (non necessario con il runtime Python 3)

Esegui la pulizia

Generale

Se per il momento hai finito, ti consigliamo di disabilitare l'app App Engine per evitare di incorrere in fatturazione. Tuttavia, se desideri eseguire altri test o sperimentarli, la piattaforma App Engine ha una quota senza costi, pertanto, se non superi il livello di utilizzo, non ti verrà addebitato alcun costo. Questo riguarda il computing, ma potrebbero essere addebitati costi anche per i servizi App Engine pertinenti, quindi consulta la pagina dei prezzi per ulteriori informazioni. Se la migrazione coinvolge altri servizi Cloud, questi vengono fatturati separatamente. In entrambi i casi, se applicabile, consulta la sezione "Specifici di questo codelab" di seguito.

Per garantire la piena divulgazione, il deployment su una piattaforma di serverless computing di Google Cloud come App Engine comporta costi minori di build e archiviazione. Cloud Build e Cloud Storage hanno una quota senza costi specifica. Lo spazio di archiviazione dell'immagine esaurisce una parte della quota. Tuttavia, potresti risiedere in una regione che non ha un livello senza costi, quindi tieni presente l'utilizzo dello spazio di archiviazione per ridurre al minimo i costi potenziali. "cartelle" specifiche di Cloud Storage da 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 dalla tua 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 completamente, chiudi il progetto.

Specifico di questo codelab

I servizi elencati di seguito sono esclusivi per questo codelab. Per ulteriori informazioni, fai riferimento alla documentazione di ciascun prodotto:

Tieni presente che se hai eseguito la migrazione dal modulo 15 al 16, continuerai ad avere dati in Blobstore e, per questo motivo, includiamo le informazioni sui prezzi riportate sopra.

Passaggi successivi

Oltre a questo tutorial, altri moduli di migrazione che si concentrano sull'abbandono dei servizi in bundle legacy da prendere in considerazione includono:

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

App Engine non è più l'unica piattaforma serverless in Google Cloud. Se hai un'app App Engine di piccole dimensioni o con funzionalità limitate e vuoi convertirla in un microservizio autonomo oppure vuoi suddividere un'app monolitica in più componenti riutilizzabili, questi sono ottimi motivi per passare a Cloud Functions. Se la containerizzazione è diventata parte del flusso di lavoro per lo sviluppo delle applicazioni, in particolare se è costituita da una pipeline CI/CD (integrazione continua/distribuzione continua o deployment), valuta la possibilità di eseguire la migrazione a Cloud Run. Questi scenari sono trattati nei seguenti moduli:

  • Eseguire 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 oppure il Modulo 5 per eseguire questa operazione senza container, conoscenze di Docker o Dockerfile

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

Indipendentemente dal modulo di migrazione successivo, sarà possibile accedere a tutti i contenuti di Serverless Migration Station (codelab, video, codice sorgente [se disponibile]) nel relativo repository open source. L'elemento README del repository fornisce anche indicazioni sulle migrazioni da prendere in considerazione e su eventuali "ordine" pertinenti dei Moduli di migrazione.

7. Risorse aggiuntive

Problemi/feedback del codelab

Se riscontri problemi con questo codelab, cercali prima di procedere con l'invio. Link per eseguire ricerche e creare nuovi problemi:

Risorse di migrazione

I link alle cartelle repository per il modulo 15 (START) e il modulo 16 (FINISH) sono disponibili nella tabella seguente. Sono inoltre accessibili dal repository per tutte le migrazioni del codelab di App Engine che puoi clonare o scaricare un file ZIP.

Codelab

Python 2

Python 3

Modulo 15

codice

N/A

Modulo 16 (questo codelab)

codice

(come Python 2)

Risorse online

Di seguito sono riportate alcune risorse online che potrebbero essere pertinenti per questa esercitazione:

Blobstore e Cloud Storage di App Engine

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.