Modulo 2: Migrazione da App Engine ndb a Cloud NDB

1. Panoramica

Questa serie di codelab (tutorial pratici e autogestiti) ha lo scopo di aiutare gli sviluppatori di Google App Engine (standard) a modernizzare le loro app guidandoli attraverso una serie di migrazioni. Il passaggio più significativo è l'abbandono dei servizi di runtime originali in bundle, perché i runtime di nuova generazione sono più flessibili e offrono agli utenti una maggiore varietà di opzioni di servizio. Il passaggio al runtime di nuova generazione consente di integrarsi più facilmente con i prodotti Google Cloud, utilizzare una gamma più ampia di servizi supportati e supportare le versioni attuali dei linguaggi.

Questo tutorial ti insegna a eseguire la migrazione dalla libreria client ndb (Next Database) integrata di App Engine alla libreria client Cloud NDB.

Imparerai come

  • Utilizza la libreria ndb di App Engine (se non la conosci)
  • Migrazione da ndb a Cloud NDB
  • Esegui la migrazione della tua app a Python 3

Che cosa ti serve

Sondaggio

Come utilizzerai questo codelab?

Solo leggere Leggere e completare gli esercizi

2. Sfondo

Nel modulo 1, abbiamo eseguito la migrazione dei framework web da webapp2 integrato di App Engine a Flask. In questo codelab, continuiamo ad allontanarci dai servizi integrati di App Engine passando dalla libreria ndb di App Engine a Cloud NDB di Google.

Una volta completata la migrazione, potrai:

  1. Esegui la migrazione a Python 3 e al runtime App Engine di nuova generazione
  2. Migrazione a Cloud Datastore (libreria client per app non App Engine)
  3. Containerizza la tua app Python 2 (o 3) ed esegui la migrazione a Cloud Run
  4. Aggiungi l'utilizzo delle code di attività di App Engine (push), quindi esegui la migrazione a Cloud Tasks

Ma non ci siamo ancora. Completa questo codelab prima di prendere in considerazione i passaggi successivi. La migrazione descritta in questo tutorial prevede i seguenti passaggi principali:

  1. Configurazione/preparazione
  2. Aggiungi la libreria Cloud NDB
  3. Aggiorna i file dell'applicazione

3. Configurazione/preparazione

Prima di iniziare la 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 completato il codelab del modulo 1, 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 è avere un'app di esempio del Modulo 1 funzionante. Utilizza la tua soluzione se hai completato il tutorial. Puoi completarlo ora (link sopra) oppure, se vuoi saltarlo, copia il repository del modulo 1 (link sotto).

Che tu utilizzi il tuo o il nostro, il codice del Modulo 1 è il punto di partenza. Questo codelab del modulo 2 ti guida in ogni passaggio e, al termine, dovrebbe assomigliare al codice nel punto FINISH (inclusa una porta "bonus" facoltativa da Python 2 a 3):

La cartella del codice del Modulo 1 STARTing deve contenere i seguenti elementi:

$ ls
README.md               appengine_config.py     requirements.txt
app.yaml                main.py                 templates

Se hai completato il tutorial del modulo 1, avrai anche una cartella lib con Flask e le relative dipendenze. Se non hai una cartella lib, creala con il comando pip install -t lib -r requirements.txt in modo da poter eseguire il deployment di questa app di base nel passaggio successivo. Se hai installato sia Python 2 che Python 3, ti consigliamo di utilizzare pip2 anziché pip per evitare confusione con Python 3.

3. (Esegui di nuovo il deployment dell')app del modulo 1

I passaggi preliminari rimanenti da eseguire ora:

  1. Acquisisci di nuovo familiarità con lo strumento a riga di comando gcloud (se necessario).
  2. (Esegui di nuovo il deployment del codice del modulo 1 in App Engine (se necessario))

Una volta eseguiti correttamente questi passaggi e verificato che sia operativo, andremo avanti in questo tutorial, a partire dai file di configurazione.

4. Aggiorna i file di configurazione (aggiungi la libreria Cloud NDB)

Molti servizi integrati originali di App Engine si sono trasformati in prodotti autonomi e Datastore è uno di questi. Oggi le app non App Engine possono utilizzare Cloud Datastore. Per gli utenti di ndb da molto tempo, il team di Google Cloud ha creato la libreria client Cloud NDB per comunicare con Cloud Datastore. È disponibile sia per Python 2 che per Python 3.

Aggiorniamo i file di conferma per sostituire App Engine ndb con Cloud NDB, quindi modifichiamo la nostra applicazione.

1. Aggiorna requirements.txt

Nel Modulo 1, l'unica dipendenza esterna della nostra app era Flask. Ora aggiungiamo Cloud NDB. Ecco l'aspetto del file requirements.txt alla fine del modulo 1:

  • PRIMA:
Flask==1.1.2

La migrazione da App Engine ndb richiede la libreria Cloud NDB (google-cloud-ndb), quindi aggiungi il relativo pacchetto a requirements.txt.

  • DOPO:
Flask==1.1.2
google-cloud-ndb==1.7.1

Al momento della stesura di questo codelab, l'ultima versione consigliata è la 1.7.1, ma requirements.txt nel repository potrebbe avere una versione più recente. Ti consigliamo di utilizzare le versioni più recenti di ogni libreria, ma se non funzionano, puoi eseguire il rollback a una release precedente.

Elimina la cartella lib, se ne hai una e non l'hai appena creata. Ora (re)installa le librerie aggiornate con il comando pip install -t lib -r requirements.txt, utilizzando pip2 anziché pip, se necessario.

2. Aggiorna app.yaml

L'aggiunta di librerie client Google Cloud come google-cloud-ndb ha alcuni requisiti, tutti incentrati sull'inclusione di librerie "integrate", pacchetti di terze parti già disponibili sui server Google. Non li elenchi in requirements.txt né li copi con pip install. Gli unici requisiti:

  1. Specifica le librerie integrate in app.yaml
  2. Indica le librerie di terze parti copiate con cui potrebbero lavorare (in lib).

Ecco l'inizio di app.yaml del modulo 1:

  • PRIMA:
runtime: python27
threadsafe: yes
api_version: 1

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

Ora aggiungi le seguenti righe a app.yaml per fare riferimento a una coppia di pacchetti in bundle di terze parti: grpcio e setuptools in una nuova sezione libraries:

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

Perché utilizzare queste librerie integrate? gRPC è un framework RPC aperto utilizzato da tutte le librerie client di Google Cloud, inclusa google-cloud-ndb. La libreria grpcio è l'adattatore gRPC Python ed è quindi obbligatoria. Il motivo dell'inclusione di setuptools verrà spiegato a breve.

  • DOPO:

Con le modifiche riportate sopra, il codice aggiornato di app.yaml ora dovrebbe avere il seguente aspetto:

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

3. Aggiorna appengine_config.py

Lo strumento pkg_resources, parte della libreria setuptools, viene utilizzato per consentire alle librerie di terze parti integrate di accedere a quelle raggruppate. Aggiorna appengine_config.py per utilizzare pkg_resources in modo da indirizzare gli utenti alle librerie in bundle in lib. Al termine della modifica, l'intero file dovrebbe avere il seguente aspetto:

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)

5. Aggiorna i file dell'applicazione

Ora che le formalità relative al file di configurazione sono state completate, puoi eseguire la migrazione da ndb a Cloud NDB. Per completare la migrazione, aggiorna le librerie importate e aggiungi l'utilizzo della gestione del contesto in main.py.

1. Importazioni

Esegui il seguente scambio di importazioni in main.py:

  • PRIMA
from google.appengine.ext import ndb
  • DOPO:
from google.cloud import ndb

Il passaggio da una libreria App Engine a una libreria Google Cloud a volte è sottile come in questo caso. Per i servizi integrati che sono diventati prodotti Google Cloud completi, importerai gli attributi da google.cloud anziché da google.appengine.

2. Accesso a Datastore

Per poter utilizzare la libreria Cloud NDB, la tua app deve utilizzare i gestori di contesto Python. Il loro scopo è quello di "controllare" l'accesso alle risorse in modo che debbano essere acquisite prima di poter essere utilizzate. I gestori del contesto si basano sulla tecnica di controllo dell'informatica nota come Resource Allocation Is Initialization (o RAII). I gestori di contesto vengono utilizzati con i file Python (che devono essere aperti prima di poter essere accessibili) e la concorrenza, i "spin lock" devono essere acquisiti prima che il codice in una "sezione critica" possa essere eseguito.

Allo stesso modo, Cloud NDB richiede l'acquisizione del contesto di un client per comunicare con Datastore prima che possano essere eseguiti comandi Datastore. Innanzitutto, crea un client (ndb.Client()) aggiungendo ds_client = ndb.Client() in main.py subito dopo l'inizializzazione di Flask:

app = Flask(__name__)
ds_client = ndb.Client()

Il comando Pythonwith viene utilizzato esclusivamente per ottenere il contesto di un oggetto. Racchiudi tutti i blocchi di codice che accedono a Datastore con istruzioni with.

Di seguito sono riportate le stesse funzioni del modulo 1 per scrivere una nuova entità in Datastore e leggere per visualizzare le entità aggiunte più di recente:

  • PRIMA:

Ecco il codice originale senza gestione del contesto:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    return (v.to_dict() for v in Visit.query().order(
            -Visit.timestamp).fetch(limit))
  • DOPO:

Ora aggiungi with ds_client.context(): e sposta il codice di accesso a Datastore nel blocco with:

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    with ds_client.context():
        return (v.to_dict() for v in Visit.query().order(
                -Visit.timestamp).fetch(limit))

L'applicazione principale del conducente rimane identica a quella del Modulo 1, poiché qui non è presente codice ndb (né Cloud NDB):

@app.route('/')
def root():
    'main application (GET) handler'
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10)
    return render_template('index.html', visits=visits)

Una best practice consiste nel garantire una chiara distinzione tra il codice dell'applicazione e l'accesso ai dati. In questo modo, il codice dell'applicazione principale non cambia quando il meccanismo di archiviazione dei dati sottostante viene modificato, come abbiamo fatto con questa migrazione.

6. Riepilogo/Pulizia

Esegui il deployment di un'applicazione

Esegui nuovamente il deployment dell'app con gcloud app deploy e verifica che funzioni. Il codice ora dovrebbe corrispondere a quello nel repository del modulo 2.

Se hai iniziato questa serie senza aver svolto i codelab precedenti, l'app non cambia. Registra tutte le visite alla pagina web principale (/) e ha questo aspetto dopo che hai visitato il sito un numero sufficiente di volte:

app visitme

Congratulazioni per aver completato questo codelab del modulo 2. Hai appena tagliato il traguardo, perché questa è l'ultima delle migrazioni fortemente consigliate di questa serie per quanto riguarda Datastore.

(Facoltativo) Pulizia

Eseguire la pulizia per evitare addebiti fino a quando non sarai pronto per passare al codelab di migrazione successivo. In qualità di sviluppatori esistenti, probabilmente siete già aggiornati sulle informazioni sui prezzi di App Engine.

(Facoltativo) Disattiva l'app

Se non sei ancora pronto per passare al tutorial successivo, disattiva l'app per evitare addebiti. Quando vuoi passare al codelab successivo, puoi riattivarlo. Mentre l'app è disattivata, non riceverà traffico per generare addebiti. Tuttavia, un altro aspetto per cui potresti ricevere una fattura è l'utilizzo di Datastore se supera la quota senza costi, quindi elimina i dati sufficienti per rientrare in questo limite.

D'altra parte, se non intendi continuare con le migrazioni e vuoi eliminare tutto completamente, puoi chiudere il progetto.

Passaggi successivi

Da qui, puoi decidere come procedere. Scegli una di queste opzioni:

  • Bonus del modulo 2: continua a leggere la parte bonus di questo tutorial per scoprire il porting a Python 3 e il runtime App Engine di nuova generazione.
  • Modulo 7: code di attività push di App Engine (obbligatorio se utilizzi le code di attività [push])
    • Aggiunge le attività push di App Engine taskqueue all'app del modulo 1
    • Prepara gli utenti alla migrazione a Cloud Tasks nel modulo 8
  • Modulo 4: esegui la migrazione a Cloud Run con Docker
    • Containerizzare l'app per eseguirla su Cloud Run con Docker
    • Ti consente di rimanere su Python 2
  • Modulo 5: esegui la migrazione a Cloud Run con Cloud Buildpacks
    • Containerizzare l'app per eseguirla su Cloud Run con Cloud Buildpacks
    • Non devi sapere nulla di Docker, dei container o di Dockerfiles
    • Richiede che tu abbia già eseguito la migrazione dell'app a Python 3
  • Modulo 3:
    • Modernizzare l'accesso a Datastore da Cloud NDB a Cloud Datastore
    • È la libreria utilizzata per le app Python 3 App Engine e non App Engine

7. BONUS: esegui la migrazione a Python 3

Per accedere al runtime e alle funzionalità più recenti di App Engine, ti consigliamo di eseguire la migrazione a Python 3. Nella nostra app di esempio, Datastore era l'unico servizio integrato che abbiamo utilizzato e, poiché abbiamo eseguito la migrazione da ndb a Cloud NDB, ora possiamo eseguire il porting al runtime Python 3 di App Engine.

Panoramica

Sebbene il porting a Python 3 non rientri nell'ambito di un tutorial di Google Cloud, questa parte del codelab offre agli sviluppatori un'idea di come differisce il runtime Python 3 di App Engine. Una delle caratteristiche più importanti del runtime di nuova generazione è l'accesso semplificato ai pacchetti di terze parti: non è necessario specificare i pacchetti integrati in app.yaml né copiare o caricare librerie non integrate; queste vengono installate implicitamente dall'elenco in requirements.txt.

Poiché il nostro esempio è molto semplice e Cloud NDB è compatibile con Python 2-3, non è necessario eseguire il porting esplicito del codice dell'applicazione alla versione 3.x. L'app viene eseguita sulle versioni 2.x e 3.x senza modifiche, il che significa che in questo caso le uniche modifiche richieste riguardano la configurazione:

  1. Semplifica app.yaml per fare riferimento a Python 3 e rimuovere le librerie di terze parti.
  2. Elimina appengine_config.py e la cartella lib perché non sono più necessari.

Oltre a main.py, i file requirements.txt e templates/index.html rimangono invariati.

Semplifica app.yaml

PRIMA:

L'unica vera modifica per questa app di esempio è l'accorciamento significativo di app.yaml. Ecco un riepilogo di ciò che abbiamo visto in app.yaml al termine del modulo 2:

runtime: python27
threadsafe: yes
api_version: 1

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

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

DOPO:

In Python 3, le direttive threadsafe, api_version e libraries sono tutte deprecate; tutte le app sono considerate thread-safe e api_version non viene utilizzato in Python 3. Nei servizi App Engine non sono più preinstallati pacchetti di terze parti integrati, pertanto anche libraries è deprecato. Per ulteriori informazioni su queste modifiche, consulta la documentazione sulle modifiche apportate a app.yaml. Di conseguenza, devi eliminare tutti e tre da app.yaml e aggiornare a una versione di Python 3 supportata (vedi di seguito).

(Facoltativo) Utilizzo della direttiva handlers

Inoltre, è stata ritirata anche la direttiva handlers, che indirizza il traffico alle applicazioni App Engine. Poiché il runtime di nuova generazione prevede che i framework web gestiscano il routing delle app, tutti gli "script di gestione" devono essere modificati in "auto". Combinando le modifiche riportate sopra, si ottiene questo app.yaml:

runtime: python38

handlers:
- url: /.*
  script: auto

Scopri di più su script: auto nella pagina della documentazione.

Rimozione dell'istruzione handlers

Poiché handlers è deprecato, puoi rimuovere anche l'intera sezione, lasciando un app.yaml su una sola riga:

runtime: python38

Per impostazione predefinita, verrà avviato il server web Gunicorn WSGI, disponibile per tutte le applicazioni. Se hai familiarità con gunicorn, questo è il comando eseguito quando viene avviato per impostazione predefinita con app.yaml:

gunicorn main:app --workers 2 -c /config/gunicorn.py

(Facoltativo) Utilizzo della direttiva entrypoint

Se, tuttavia, la tua applicazione richiede un comando di avvio specifico, questo può essere specificato con una direttiva entrypoint in cui app.yaml avrebbe questo aspetto:

runtime: python38
entrypoint: python main.py

Questo esempio richiede specificamente l'utilizzo del server di sviluppo Flask anziché gunicorn. Per l'avvio sull'interfaccia 0.0.0.0 sulla porta 8080, è necessario aggiungere all'app anche il codice che avvia il server di sviluppo, aggiungendo questa piccola sezione alla fine di main.py:

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080, debug=True)

Scopri di più su entrypoint nella pagina della documentazione. Altri esempi e best practice sono disponibili nella documentazione sull'avvio di App Engine Standard e nella documentazione sull'avvio di App Engine Flexible.

Elimina appengine_config.py e lib

Elimina il file appengine_config.py e la cartella lib. Durante la migrazione a Python 3, App Engine acquisisce e installa i pacchetti elencati in requirements.txt.

Il file di configurazione appengine_config.py viene utilizzato per riconoscere librerie/pacchetti di terze parti, sia che tu li abbia copiati personalmente sia che utilizzi quelli già disponibili sui server App Engine (integrati). Quando esegui la migrazione a Python 3, ecco un riepilogo delle modifiche principali:

  1. Nessun bundling delle librerie di terze parti copiate (elencate in requirements.txt)
  2. Nessun pip install in una cartella lib, il che significa nessuna cartella lib
  3. Nessuna libreria di terze parti integrata nella scheda in app.yaml
  4. Non è necessario fare riferimento all'app per le librerie di terze parti, quindi non è necessario il file appengine_config.py

È sufficiente elencare tutte le librerie di terze parti richieste in requirements.txt.

Esegui il deployment di un'applicazione

Esegui di nuovo il deployment dell'app per assicurarti che funzioni. Puoi anche verificare quanto la tua soluzione si avvicina al codice Python 3 di esempio del modulo 2. Per visualizzare le differenze con Python 2, confronta il codice con la sua versione Python 2.

Congratulazioni per aver completato il passaggio bonus del modulo 2. Consulta la documentazione sulla preparazione dei file di configurazione per il runtime Python 3. Infine, rivedi la pagina Riepilogo/Pulizia (precedente) per i passaggi successivi e la pulizia.

Preparazione della tua richiesta

Quando sarà il momento di eseguire la migrazione della tua applicazione, dovrai trasferire main.py e altri file dell'applicazione alla versione 3.x, pertanto una best practice è cercare di rendere la tua applicazione 2.x il più "compatibile con le versioni successive" possibile.

Esistono molte risorse online per aiutarti a raggiungere questo obiettivo, ma alcuni dei suggerimenti chiave sono:

  1. Assicurati che tutte le dipendenze dell'applicazione siano completamente compatibili con la versione 3.x
  2. Assicurati che la tua applicazione venga eseguita almeno su Python 2.6 (preferibilmente 2.7)
  3. Assicurati che l'applicazione superi l'intera suite di test (e una copertura minima dell'80%).
  4. Utilizza librerie di compatibilità come six, Future e/o Modernize
  5. Informati sulle principali differenze tra le versioni 2.x e 3.x non compatibili con le versioni precedenti
  6. Qualsiasi I/O porterà probabilmente a incompatibilità tra stringhe Unicode e stringhe di byte

L'app di esempio è stata progettata tenendo conto di tutto questo, ecco perché funziona su 2.x e 3.x fin da subito, in modo da poterci concentrare su ciò che deve essere modificato per utilizzare la piattaforma di nuova generazione.

8. Risorse aggiuntive

Problemi/feedback relativi ai codelab del modulo di migrazione di App Engine

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 1 (INIZIO) e il Modulo 2 (FINE) 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

Module 1

code

(n/a)

Modulo 2

code

code

Risorse App Engine

Di seguito sono riportate risorse aggiuntive relative a questa migrazione specifica: