Modulo 1: Migrazione da App Engine webapp2 a Flask

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 iniziale mostra i primi passaggi di migrazione per modernizzare il framework web nelle app App Engine: il passaggio da webapp2 a Flask. Nella tua app puoi utilizzare qualsiasi framework web che gestisca il routing, ma per questo tutorial utilizziamo Flask perché è ampiamente utilizzato dalla community.

Imparerai come

  • Utilizzare librerie di terze parti (integrate o meno)
  • 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?

Solo leggere Leggere e completare gli esercizi

2. Sfondo

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

Sebbene webapp2 (vedi documenti) esista ancora e possa essere utilizzato al di fuori di App Engine come framework web conforme a WSGI, non esegue il proprio routing delle richieste degli utenti al codice appropriato nell'applicazione. Si basa invece su App Engine, sui file di configurazione e sullo sviluppatore per eseguire il routing del traffico web ai "gestori" corrispondenti. Inoltre, i vantaggi principali di webapp2 sono indissolubilmente legati ai servizi in bundle di App Engine, il che lo rende effettivamente deprecato anche se funziona su Python 3 (vedi anche il 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 da molti altri servizi al di fuori di Google Cloud, il che rende le app molto più portatili. Se Flask non è il framework che vuoi utilizzare per spostare la tua applicazione, puoi selezionarne un altro, purché esegua il routing autonomamente. Questo codelab mostra ai responsabili delle decisioni in materia di tecnologia dell'informazione (ITDM) e agli sviluppatori quali sono i passaggi di migrazione, in modo che tu possa familiarizzare con questa procedura indipendentemente dal framework a cui esegui la migrazione.

Di seguito sono riportati i passaggi principali per questa migrazione:

  1. Configurazione/preparazione
  2. Aggiungere la libreria di terze parti Flask
  3. Aggiorna i file dell'applicazione
  4. Aggiorna il file modello HTML

3. Configurazione/preparazione

Prima di iniziare la parte principale del tutorial, configuriamo il progetto, recuperiamo il codice, poi ti (ri)familiarizziamo con il comando gcloud e implementiamo l'app di base in modo da sapere di aver iniziato con un codice funzionante.

1. Configura il progetto

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

2. Scarica l'app di esempio di base

Il repository di migrazione di GAE contiene tutto il codice necessario. Clonalo o scarica il file ZIP. Per questo tutorial, inizierai con il codice nella cartella Modulo 0 (START) e, al termine del tutorial, il codice dovrebbe corrispondere a quello della cartella Modulo 1 (FINISH). In caso contrario, controlla le differenze per poter passare al lab successivo.

La cartella Module 0 dovrebbe contenere file simili a questi, come illustrato con il comando POSIX ls:

$ ls
app.yaml        index.html      main.py

3. (Riacquisire) familiarità con i comandi di gcloud

Se non hai ancora il comando gcloud sulla tua macchina, installa Google Cloud SDK e assicurati che gcloud sia disponibile come parte del percorso di esecuzione. Familiarizza 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 GCP
  4. gcloud config set project PROJECT_ID: imposta l'ID progetto Google Cloud
  5. gcloud app deploy: esegui il deployment dell'applicazione App Engine

Se non hai sviluppato di recente con App Engine utilizzando gcloud, esegui i primi quattro comandi (da 1 a 4) per la configurazione prima di passare ai passaggi successivi. Vediamo rapidamente questi comandi.

Innanzitutto, gcloud components update ti assicura di avere l'ultima versione di Cloud SDK. L'esecuzione di questo comando dovrebbe generare 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

Successivamente, utilizza gcloud auth login per autenticarti per i comandi gcloud che emetterai 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

Utilizza gcloud config list per visualizzare le impostazioni del progetto attuali:

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

Your active configuration is: [default]

Il comando precedente dovrebbe guidarti nella creazione di un nuovo progetto o nella selezione di 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. Poi, 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, se vuoi, o utilizzare un progetto preesistente. Nella dashboard del progetto, dovresti vedere la scheda delle informazioni sul progetto che mostra il relativo ID (insieme al nome e al numero del progetto):

scheda informativa sul progetto

L'ultimo comando (#5), gcloud app deploy, serve per eseguire il deployment dell'app in App Engine. Poiché siamo solo all'inizio, l'esecuzione ora è facoltativa, ma non scoraggiamo 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 tua posizione). Tuttavia, non può essere modificato una volta impostato. Poi guarda il resto delle informazioni sul deployment. Al termine, riceverai una notifica dell'URL in cui verrà pubblicato il servizio della 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 di deployment originale appcfg.py update è stato sostituito da gcloud app deploy. Per scoprire di più su gcloud app deploy, consulta la relativa pagina della documentazione.

Un'altra modifica recente riguarda l'URL delle app di cui è stato eseguito il deployment, 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 URL nella documentazione relativa a richieste e routing.

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

app visitme

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

4. Aggiungere la libreria di terze parti Flask

Il runtime Python 2 di App Engine fornisce un insieme di librerie di terze parti"integrate" che devi solo specificare nel file app.yaml per utilizzarle. Sebbene questa migrazione non richieda il loro utilizzo, saranno presenti nel tutorial sulla migrazione successivo (per il modulo 2).

Le librerie di terze parti non 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 viene caricato tutto su App Engine. Per ulteriori informazioni, consulta la documentazione sul bundling delle librerie di terze parti.

Le librerie copiate come Flask richiedono di indicare ad App Engine di cercarle nella cartella lib utilizzando il file di configurazione appengine_config.py. Il file di configurazione appengine_config.py viene inserito 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 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 di questo documento, l'ultima versione è la 1.1.2, quindi crea requirements.txt con questa riga:

Flask==1.1.2

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

2. Crea appengine_config.py

Il passaggio successivo consiste nel far riconoscere ad App Engine le librerie esterne di terze parti. 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, ovvero 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 relative dipendenze:

$ pip install -t lib -r requirements.txt

Che tu abbia utilizzato pip o pip2, al termine dell'installazione del pacchetto, dovresti avere una cartella lib con contenuti simili a questi:

$ 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 ndb Datastore e, infine, dall'estensione App Engine che elabora i modelli in stile Django. Dovresti visualizzare quanto segue:

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

Quando passi a Flask, importi contemporaneamente sia Flask che i componenti del renderer dei modelli. Elimina la coppia di importazioni correlate a webapp2 e sostituiscile come segue (lascia l'importazione ndb invariata):

  • 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 (potrebbero essercene altri):

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

Tieni presente che app.yaml esegue il routing di livello superiore e potrebbe chiamare gestori diversi. L'app di esempio è abbastanza semplice da far convergere tutte le route nel gestore main.py.

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

  • DOPO:
app = Flask(__name__)

In Flask, inizializzi il framework e poi utilizzi i decoratori per definire le route. Inoltre, le route sono associate a funzioni, non a classi o metodi.

Non è previsto includere un tutorial su Flask in questo codelab, quindi dedica un po' di tempo a seguire il tutorial su Flask e a esaminare la documentazione di Flask per acquisire maggiore familiarità con il framework.

3. Modello dei dati

Non ci sono modifiche. Datastore sarà l'argomento del prossimo codelab.

4. Gestori

L'applicazione, indipendentemente dal framework utilizzato (webapp2 o Flask), esegue tre operazioni:

  1. Gestire le richieste GET del percorso principale (/)
  2. Registra una "visita" di una pagina web (crea/memorizza l'oggetto Visit)
  3. Visualizzare le 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 semplice caso, abbiamo solo GET, quindi viene 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 accennato in precedenza, Flask esegue il proprio routing. Anziché una classe gestore, scrivi funzioni e le decori con la route per cui devono essere chiamate. Gli utenti possono specificare i metodi HTTP gestiti nella chiamata del decoratore, ad esempio: @app.route('/app/', methods=['GET', 'POST']). Poiché il valore predefinito è solo GET (e implicitamente HEAD), può essere omesso.

Durante la migrazione a Flask, sostituisci la classe MainHandler e il relativo metodo get() con la seguente funzione di routing 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, questo non è rappresentativo della tua app, che sarà sicuramente più complessa di questo esempio. Uno degli obiettivi principali di questi tutorial è aiutarti a iniziare, a sviluppare una "memoria muscolare" e a capire dove apportare modifiche nel codice specifico di App Engine. Per verificare di aver apportato correttamente questa modifica, confronta la tua versione con il Modulo 1 main.py.

5. File ausiliari

Non sono state apportate modifiche al file .gcloudignore. Il suo scopo è specificare i file da non eseguire il deployment in App Engine che non sono necessari per eseguire il deployment ed eseguire l'applicazione, inclusi, a titolo esemplificativo, Python ausiliario, il controllo del codice sorgente, il boilerplate del repository e altri file. Il nostro .gcloudignore è simile a questo (i commenti sono stati rimossi per brevità):

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

6. Aggiorna il file modello HTML

1. Spostare il file modello

Nella cartella del repository di base (Modulo 0), il file modello index.html si trova nella stessa cartella dei file dell'applicazione. Poiché Flask richiede che i file HTML vengano inseriti in una cartella templates, devi creare questa cartella (mkdir templates) e spostarvi index.html. In un sistema conforme a POSIX come Linux o Mac OS X, i comandi sarebbero:

mkdir templates
mv index.html templates

2. Aggiorna il file modello

Dopo aver spostato index.html in templates, è il momento di apportare una piccola modifica obbligatoria. Diamo un'occhiata al file 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 i modelli Django che eseguono callable come visit.timestamp.ctime senza parentesi ( ), Jinja2 le richiede esplicitamente. Sebbene possa sembrare una piccola modifica, i modelli Jinja sono più potenti perché puoi passare argomenti nelle chiamate.

In Django, devi creare un "tag modello" o scrivere un filtro. Con questa comprensione, aggiorna index.html aggiungendo una coppia 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

Una volta completate tutte le modifiche in questo tutorial, i file nella cartella dell'applicazione dovrebbero essere identici (o quasi) al file nella cartella del repository del modulo 1. Ora esegui il deployment e verifica che l'applicazione Flask del modulo 1 funzioni 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. Accedere all'app all'indirizzo PROJECT_ID.appspot.com, da un browser web o da un comando curl o wget per verificare che funzioni come previsto.

Se ricevi un errore del server, in genere significa che c'è un errore di battitura nel codice Python. Dai un'occhiata ai log dell'applicazione per eseguire un'indagine. Confronta anche i tuoi file con quelli nel repository del modulo 1 (link appena sopra).

(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

Esistono due moduli di migrazione che INIZIANO con il codice del Modulo 1 completato, i moduli 2 e 7:

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

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 0 (START) e il modulo 1 (FINISH) sono disponibili nella tabella di seguito. Puoi accedervi anche dal repository per tutte le migrazioni di App Engine, che puoi clonare o scaricare come file ZIP.

Codelab

Python 2

Python 3

Modulo 0

code

(n/a)

Module 1

code

(n/a)

Risorse App Engine

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