Modulo 1: Migrazione da App Engine webapp2 a Flask

1. Panoramica

Questa serie di codelab (tutorial pratici e self-service) mira ad aiutare gli sviluppatori di Google App Engine (standard) a modernizzare le loro app, guidandoli attraverso una serie di migrazioni. Il passaggio più significativo è abbandonare i servizi originali in bundle per il runtime perché i runtime di nuova generazione sono più flessibili e offrono agli utenti una maggiore varietà di opzioni di servizi. Il passaggio al runtime di nuova generazione consente un'integrazione più semplice con i prodotti Google Cloud, l'utilizzo di una gamma più ampia di servizi supportati e il supporto delle release nelle lingue attuali.

Questo tutorial iniziale mostra i primi passaggi di migrazione per modernizzare il framework web nelle app di App Engine: passare da webapp2 a Flask. Nella tua app, puoi utilizzare qualsiasi framework web che gestisca il routing, ma per questo tutorial useremo Flask, perché è ampiamente utilizzato dalla community.

Imparerai a

  • Usa librerie di terze parti (integrate o di altro tipo)
  • Aggiorna i file di configurazione
  • Esegui la migrazione di un'app semplice da webapp2 a Flask

Che cosa ti serve

Sondaggio

Come utilizzerai questo codelab?

Da leggere solo Leggilo e completa gli esercizi

2. Sfondo

Il framework webapp è stato integrato in pacchetti quando App Engine è stato lanciato per la prima volta su Python 2.5 nel 2008. Anni dopo è stato sostituito dal successivo webapp2, quando il runtime 2.7 ha ritirato la versione 2.5 nel 2013.

Sebbene webapp2 (vedi i documenti) esista ancora e possa essere utilizzato al di fuori di App Engine come framework web conforme a WSGI, non esegue il routing delle richieste dell'utente al codice appropriato nell'applicazione. Si basa invece su App Engine, sui file di configurazione e sullo sviluppatore per eseguire l'instradamento del traffico web verso i "gestori" corrispondenti. Inoltre, i vantaggi principali di webapp2 sono inestricabilmente legati ai servizi in bundle di App Engine, il che lo ritira in modo efficace anche se funziona su Python 3 (vedi anche problema correlato).

Questo modulo offre ai professionisti un'esperienza pratica per la migrazione di una semplice app webapp2 a Flask, un framework supportato da App Engine e molti altri servizi al di fuori di Google Cloud, rendendo le app molto più portabili. Se Flask non è il framework desiderato in cui spostare la tua applicazione, puoi selezionarne un altro, a condizione che esegua il proprio routing. Questo codelab mostra ai responsabili delle decisioni IT (ITDM) e agli sviluppatori i passaggi di migrazione, in modo che tu possa familiarizzare con questo processo indipendentemente dal framework di destinazione effettivo.

Di seguito sono riportati i passaggi principali della migrazione:

  1. Configurazione/pre-lavoro
  2. Aggiungi libreria di terze parti Flask
  3. Aggiorna i file dell'applicazione
  4. Aggiorna il file del modello HTML

3. Configurazione/pre-lavoro

Prima di proseguire con la parte principale del tutorial, configuriamo il nostro progetto, recuperiamo il codice, quindi (ri)fartiilizziamo il comando gcloud ed eseguiamo il deployment dell'app di base in modo da sapere che abbiamo iniziato a lavorare con il codice.

1. Configura il progetto

In qualità di sviluppatore esistente, è probabile che la dashboard di App Engine mostri già quali servizi hai in esecuzione. Ai fini di questo tutorial, ti consigliamo di creare un nuovo progetto o di riutilizzarne uno esistente per questo tutorial. Assicurati che il progetto abbia un account di fatturazione attivo e che App Engine (app) sia abilitato.

2. Scarica l'app di esempio di riferimento

Il repository della migrazione GAE contiene tutto il codice di cui hai bisogno. Clonalo o scarica il relativo file ZIP. Per questo tutorial, inizierai con il codice nella cartella del modulo 0 (START) e, una volta completato l'esercitazione, il codice dovrebbe corrispondere alla cartella del modulo 1 (FINISH). In caso contrario, controlla le differenze in modo da poter passare al lab successivo.

La cartella del modulo 0 deve contenere file simili a questo, come illustrato con il comando POSIX ls:

$ ls
app.yaml        index.html      main.py

3. (Ri)Acquisisci familiarità con i comandi gcloud

Se non hai ancora il comando gcloud sulla tua macchina, installa Google Cloud SDK, assicurati che gcloud sia disponibile nel percorso di esecuzione e acquisisci familiarità con i seguenti comandi gcloud:

  1. gcloud components update: aggiorna Google Cloud SDK
  2. gcloud auth login: accedi al tuo account con credenziali
  3. gcloud config list: elenca le impostazioni di configurazione del progetto Google Cloud
  4. gcloud config set project PROJECT_ID: imposta l'ID progetto Google Cloud
  5. gcloud app deploy: esegui il deployment della tua applicazione App Engine

Se di recente non hai sviluppato App Engine con gcloud, devi eseguire i primi quattro comandi (#1-#4) per effettuare la configurazione prima di andare ai passaggi successivi. Facciamo una rapida panoramica di questi comandi.

Innanzitutto, gcloud components update garantisce di avere la versione più recente di Cloud SDK. L'esecuzione di questo comando dovrebbe restituire un output simile al seguente:

$ gcloud components update

Your current Cloud SDK version is: 317.0.0
You will be upgraded to version: 318.0.0

┌──────────────────────────────────────────────────┐
│        These components will be updated.         │
├──────────────────────────┬────────────┬──────────┤
│           Name           │  Version   │   Size   │
├──────────────────────────┼────────────┼──────────┤
│ Cloud SDK Core Libraries │ 2020.11.06 │ 15.5 MiB │
│ gcloud cli dependencies  │ 2020.11.06 │ 10.6 MiB │
└──────────────────────────┴────────────┴──────────┘

The following release notes are new in this upgrade.
Please read carefully for information about new features, breaking changes,
and bugs fixed.  The latest full release notes can be viewed at:
  https://cloud.google.com/sdk/release_notes

318.0.0 (2020-11-10)

      . . .
      (release notes)
      . . .

    Subscribe to these release notes at
    https://groups.google.com/forum/#!forum/google-cloud-sdk-announce.

Do you want to continue (Y/n)?

╔════════════════════════════════════════════════════════════╗
╠═ Creating update staging area                             ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Uninstalling: Cloud SDK Core Libraries                   ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Uninstalling: gcloud cli dependencies                    ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: Cloud SDK Core Libraries                     ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Installing: gcloud cli dependencies                      ═╣
╠════════════════════════════════════════════════════════════╣
╠═ Creating backup and activating new installation          ═╣
╚════════════════════════════════════════════════════════════╝

Performing post processing steps...done.

Update done!

To revert your SDK to the previously installed version, you may run:
  $ gcloud components update --version 317.0.0

Dopodiché, usa gcloud auth login per autenticarti per i comandi gcloud che effettuerai in futuro:

$ gcloud auth login
Your browser has been opened to visit:

    https://accounts.google.com/o/oauth2/auth?response_type=code&client_id= . . .

You are now logged in as [YOUR_EMAIL].
Your current project is [PROJECT_ID].  You can change this setting by running:
  $ gcloud config set project PROJECT_ID

Usa gcloud config list per vedere quali sono le impostazioni attuali del tuo progetto:

$ gcloud config list
[core]
account = YOUR_EMAIL
disable_usage_reporting = False
project = PROJECT_ID

Your active configuration is: [default]

Il comando riportato sopra dovrebbe aiutarti a creare un nuovo progetto o a selezionarne uno esistente. Se l'output di gcloud config list non corrisponde al progetto selezionato che intendi utilizzare per questo tutorial, esegui gcloud config set project PROJECT_ID per impostare l'ID progetto. Quindi, verifica che sia impostato l'ID progetto corretto eseguendo di nuovo gcloud config list.

$ gcloud config set project PROJECT_ID
Updated property [core/project].

Se preferisci utilizzare la console Cloud, puoi seguire l'interfaccia utente per creare un nuovo progetto oppure utilizzare un progetto preesistente già in tuo possesso. Nella dashboard del progetto dovresti vedere la scheda informativa del progetto che mostra il relativo ID (insieme al nome e al numero del progetto):

scheda informativa del progetto

L'ultimo comando (#5), gcloud app deploy, consente di eseguire il deployment dell'app in App Engine. Poiché abbiamo appena iniziato, eseguirlo ora è facoltativo, ma sicuramente non sconsigliamo di eseguire il deployment del codice del Modulo 0 per confermare che funzioni. Al momento dell'esecuzione, seleziona la regione geografica in cui vuoi che venga eseguita l'app (in genere la località in cui ti trovi). Una volta impostato, il valore non può essere modificato. Quindi, guarda le altre informazioni sul deployment. Al termine dell'operazione, riceverai una notifica con l'URL su cui verrà pubblicata la tua app. Ecco una versione ridotta di ciò che potresti vedere:

$ gcloud app deploy
Services to deploy:

descriptor:      [/private/tmp/mod0-baseline/app.yaml]
source:          [/private/tmp/mod0-baseline]
target project:  [PROJECT_ID]
target service:  [default]
target version:  [20201116t220827]
target url:      [https://PROJECT_ID.REG_ABBR.r.appspot.com]


Do you want to continue (Y/n)?

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 1 file to Google Cloud Storage                 ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://PROJECT_ID.REG_ABBR.r.appspot.com]

You can stream logs from the command line by running:
  $ gcloud app logs tail -s default

To view your application in the web browser run:
  $ gcloud app browse

Se non utilizzi App Engine da un po' di tempo, potresti notare che il comando appcfg.py update del deployment originale è stato sostituito da gcloud app deploy. Per saperne di più su gcloud app deploy, consulta la relativa pagina della documentazione.

Un'altra modifica recente è la configurazione delle app di cui è stato eseguito il deployment, URL modificato da http://PROJECT_ID.appspot.com a http://PROJECT_ID.REG_ABBR.r.appspot.com. La maggior parte delle app verrà convertita nel nuovo formato. Scopri di più sul formato dell'URL nella documentazione relativa alle richieste e al routing.

Dopo il deployment dell'app, aggiorna il browser (possibilmente alcune volte) per visualizzare le visite più recenti:

app visitme

Se la tua app è nuova, vedrai solo una o poche visite.

4. Aggiungi libreria di terze parti Flask

Il runtime Python 2 di App Engine fornisce un set di dati "integrati" librerie di terze parti dove non devi fare altro che specificarle nel file app.yaml da utilizzare. Anche se questa migrazione non richiede l'uso di questi strumenti, verrà mostrata nel prossimo tutorial sulla migrazione (per il Modulo 2).

Le librerie di terze parti che non sono integrate devono essere specificate in un file denominato requirements.txt e installate localmente nella cartella lib nella stessa directory del codice dell'applicazione in cui tutto viene caricato in App Engine. La documentazione sul raggruppamento di librerie di terze parti contiene ulteriori informazioni.

Per le librerie copiate come Flask è necessario indicare ad App Engine di cercarle nella cartella lib utilizzando il file di configurazione appengine_config.py. Il file di configurazione appengine_config.py si trova nella stessa cartella dell'applicazione di primo livello di requirements.txt e lib. In questa parte del tutorial imparerai a:

  • Crea requirements.txt (specifica le librerie di terze parti [non integrate] copiate)
  • Crea appengine_config.py (riconosci le librerie di terze parti)
  • Installare pacchetti e dipendenze (di terze parti)

1. Crea requirements.txt

Crea un file requirements.txt per specificare i pacchetti. Nel nostro caso, Flask è la libreria di terze parti necessaria. Al momento della stesura del presente documento, l'ultima versione è la 1.1.2, quindi crea requirements.txt con questa sola riga:

Flask==1.1.2

Per scoprire di più sui formati accettati, consulta la documentazione di requirements.txt.

2. Crea appengine_config.py

Il passaggio successivo prevede che App Engine riconosca le librerie di terze parti esterne. Crea un file denominato appengine_config.py con il seguente contenuto:

from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)

Questo codice fa esattamente ciò che abbiamo specificato in precedenza, ossia indirizza App Engine alla cartella lib per le librerie copiate.

3. Installa pacchetti e dipendenze

Ora esegui il comando pip install per creare la cartella lib e installare Flask e le sue dipendenze lì:

$ pip install -t lib -r requirements.txt

A prescindere dal fatto che tu abbia utilizzato pip o pip2, al termine dell'installazione del pacchetto dovresti avere una cartella lib con un contenuto simile a questo:

$ ls lib
bin/
click/
click-7.1.2.dist-info/
flask/
Flask-1.1.2.dist-info/
itsdangerous/
itsdangerous-1.1.0.dist-info/
jinja2/
Jinja2-2.11.2.dist-info/
markupsafe/
MarkupSafe-1.1.1.dist-info/
werkzeug/
Werkzeug-1.0.1.dist-info/

5. Aggiorna i file dell'applicazione

Ora aggiorniamo il file dell'applicazione, main.py.

1. Importazioni

Le importazioni vengono eseguite per prime, come in tutti i file Python. L'importazione del framework webapp2 è seguita dalla libreria Datastore ndb e, infine, dall'estensione App Engine che elabora i modelli basati su Django. Dovresti visualizzare quanto segue:

  • PRIMA:
import webapp2
from google.appengine.ext import ndb
from google.appengine.ext.webapp import template

Quando lo sposti in Flask, importi contemporaneamente sia Flask sia le parti del renderer del modello. Elimina la coppia di importazioni correlate a webapp2 e sostituiscile come segue (lascia l'importazione di ndb così com'è):

  • DOPO:
from flask import Flask, render_template, request
from google.appengine.ext import ndb

2. Avvio

Le app che utilizzano webapp2 richiedono un singolo array (elenco Python) che elenca tutte le route e i gestori in qualsiasi file Python (e potrebbero essercene altri):

  • PRIMA:
app = webapp2.WSGIApplication([
    ('/', MainHandler),
], debug=True)

Tieni presente che app.yaml esegue il routing di livello più elevato e potrebbe chiamare gestori diversi. L'app di esempio è abbastanza semplice da far arrivare tutte le route al gestore main.py.

Flask non utilizza tabelle di routing come questa, quindi elimina queste righe in main.py. Flask richiede anche l'inizializzazione, quindi aggiungi la seguente riga all'inizio di main.py appena sotto le importazioni:

  • DOPO:
app = Flask(__name__)

In Flask, inizializza il framework e poi utilizza i decorator per definire le route. Inoltre, le route sono abbinate a funzioni, non a classi o metodi.

Includere un tutorial di Flask in questo codelab non rientra nell'ambito, quindi dedica un po' di tempo a svolgere il tutorial di Flask e consulta la documentazione di Flask per acquisire dimestichezza con il framework.

3. Modello dei dati

Non ci sono modifiche qui. Datastore sarà l'argomento centrale del codelab successivo.

4. Gestori

L'applicazione, indipendentemente dal framework utilizzato (webapp2 o Flask), fa tre cose:

  1. Gestisci le richieste GET del percorso principale (/)
  2. Registra una pagina web "visita" (crea/archivia oggetto Visit)
  3. Mostra le prime 10 visite più recenti (con un modello predefinito, index.html)

Il framework webapp2 utilizza un modello di esecuzione basato su classi in cui vengono creati gestori per ogni metodo HTTP supportato. Nel nostro caso semplice, abbiamo solo GET, quindi è definito un metodo get():

  • PRIMA:
class MainHandler(webapp2.RequestHandler):
    def get(self):
        store_visit(self.request.remote_addr, self.request.user_agent)
        visits = fetch_visits(10) or ()  # empty sequence if None
        tmpl = os.path.join(os.path.dirname(__file__), 'index.html')
        self.response.out.write(template.render(tmpl, {'visits': visits}))

Come indicato in precedenza, Flask esegue il proprio routing. Invece di una classe gestore, puoi scrivere le funzioni e decorarle con la route a cui devono essere richiamate. Gli utenti possono specificare i metodi HTTP gestiti nella chiamata decorator, ad es. @app.route('/app/', methods=['GET', 'POST']). Poiché il valore predefinito è solo GET (e implicitamente HEAD), può essere lasciato non attivo.

Durante la migrazione a Flask, sostituisci la classe MainHandler e il relativo metodo get() con la seguente funzione di routing di Flask:

  • DOPO:
@app.route('/')
def root():
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10) or ()  # empty sequence if None
    return render_template('index.html', visits=visits)

Naturalmente ciò non è rappresentativo della tua app, il che sarà sicuramente più complesso di questo campione. Uno degli obiettivi principali di questi tutorial è aiutarti a iniziare, sviluppare un po' di quella "memoria muscolare", e capire dove apportare modifiche al codice specifico di App Engine. Per confermare di avere apportato correttamente questa modifica, confronta la tua con il Modulo 1 main.py.

5. File ausiliari

Nessuna modifica al file .gcloudignore. Il suo scopo è specificare i file di cui non eseguire il deployment in App Engine e che non sono necessari per il deployment e l'esecuzione dell'applicazione, inclusi, a titolo esemplificativo, Python ausiliario, controllo del codice sorgente, boilerplate del repository e altri file. Il nostro .gcloudignore si presenta così (con commenti rimossi per brevità):

.gcloudignore
.git
.gitignore
.hgignore
.hg/
*.pyc
*.pyo
__pycache__/
/setup.cfg
README.md

6. Aggiorna il file del modello HTML

1. Sposta il file del modello

Nella cartella del repository di riferimento (modulo 0), il file modello index.html si trova nella stessa cartella dei file dell'applicazione. Poiché Flask richiede file HTML inseriti in una cartella templates, devi creare tale cartella (mkdir templates) e spostare index.html al suo interno. In un sistema compatibile con POSIX come Linux o Mac OS X, i comandi sarebbero:

mkdir templates
mv index.html templates

2. Aggiorna file modello

Dopo aver spostato index.html in templates, è il momento di apportare una modifica piccola ma obbligatoria. Diamo un'occhiata al file del modello originale nella sua interezza:

<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<body>

<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
    <li>{{ visit.timestamp.ctime }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>

</body>
</html>

Mentre webapp2 utilizza modelli Django che eseguono chiamate come visit.timestamp.ctime senza parentesi ( ), Jinja2 li richiede esplicitamente. Anche se sembra un piccolo ritocco, i modelli Jinja sono subito più potenti perché è possibile passare argomenti nelle chiamate.

In Django, devi creare un "tag modello" o scrivere un filtro. Alla luce di queste informazioni, aggiorna index.html aggiungendo un paio di parentesi alla chiamata visit.timestamp.ctime:

  • PRIMA:
<li>{{ visit.timestamp.ctime }} from {{ visit.visitor }}</li>
  • DOPO:
<li>{{ visit.timestamp.ctime() }} from {{ visit.visitor }}</li>

Questa è l'unica modifica richiesta. non sono necessarie ulteriori modifiche a index.html per tutti i codelab di migrazione rimanenti.

7. Riepilogo/Pulizia

Esegui il deployment di un'applicazione

Dopo aver completato tutte le modifiche in questo tutorial, i file nella cartella dell'applicazione dovrebbero essere identici (o quasi) al file della cartella di repository del Modulo 1. Ora esegui il deployment e controlla che l'applicazione Flask del modulo 1 viene eseguita in modo identico alla versione webapp2 del modulo 0.

Utilizza il comando gcloud app deploy come abbiamo fatto in precedenza durante il deployment del codice originale del Modulo 0. Accesso all'app all'indirizzo PROJECT_ID.appspot.com, da un browser web oppure da un comando curl o wget per confermare che funziona come previsto.

Se si verifica un errore del server, significa in genere un errore di battitura nel codice Python. Dai un'occhiata ai log dell'applicazione per ulteriori indagini. Confronta anche i tuoi file con quelli del repository del modulo 1 (link sopra).

(Facoltativo) Eseguire la pulizia

Che ne dici di eseguire la pulizia per evitare di ricevere addebiti finché non decidi di passare al codelab di migrazione successivo? In qualità di sviluppatori esistenti, probabilmente sei già al passo con le informazioni sui prezzi di App Engine.

(Facoltativo) Disattiva l'app

Se non vuoi ancora passare al prossimo tutorial, disattiva la tua app per evitare che ti vengano addebitati dei costi. Quando vuoi passare al codelab successivo, puoi riabilitarlo. Mentre l'app è disabilitata, non riceverà traffico che comporta addebiti, ma un'altra cosa che ti può essere fatturata è l'utilizzo di Datastore se supera la quota senza costi, quindi eliminane un numero sufficiente per rientrare nel limite.

Se invece non intendi continuare con le migrazioni e vuoi eliminare tutto il tutto, puoi chiudere il progetto.

Passaggi successivi

Ci sono due moduli di migrazione che AVVIANO con il codice completato del Modulo 1, i Moduli 2 e 7:

  • Modulo 2 (obbligatorio se utilizzi Datastore)
    • Esegui la migrazione da App Engine ndb a Cloud NDB
    • Dopo il passaggio a Cloud NDB, diventano disponibili molte altre opzioni
      • Containerizzazione dell'app per l'esecuzione su Cloud Run
      • Ulteriore migrazione dell'app alla libreria client di Cloud Datastore
      • Migrazione dell'app in Cloud Firestore per accedere alle funzionalità di Firebase
  • Modulo 7 (obbligatorio se utilizzi code di attività [push])
    • Aggiungi utilizzo taskqueue di App Engine (push)
    • Prepara l'app del modulo 1 per la migrazione a Cloud Tasks nel modulo 8

8. Risorse aggiuntive

Problemi/feedback dei codelab per i moduli di migrazione di App Engine

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 0 (START) e il modulo 1 (FINISH) sono disponibili nella tabella seguente. Sono inoltre accessibili dal repository per tutte le migrazioni di App Engine che puoi clonare o scaricare un file ZIP.

Codelab

Python 2

Python 3

Modulo 0

codice

(n/d)

Module 1

codice

(n/d)

Risorse App Engine

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