Migrazione al runtime Python 3

Python 2.7 ha raggiunto la fine del supporto il 31 gennaio 2024. Le applicazioni Python 2.7 esistenti continueranno a essere eseguite e a ricevere traffico. Tuttavia, App Engine potrebbe bloccare il nuovo deployment di applicazioni che utilizzano runtime dopo la data di fine dell'assistenza. Ti consigliamo di eseguire la migrazione all'ultima versione supportata di Python utilizzando le linee guida in questa pagina.

La migrazione al runtime Python 3 consente di utilizzare funzionalità di linguaggio aggiornate e di creare app più portabili, con codice idiomatico. Il runtime Python 3 utilizza la versione più recente dell'interprete Python open source fornito da Python Software Foundation. Le app integrate nel runtime Python 3 possono utilizzare il ricco ecosistema di pacchetti e framework di Python nella tua app, compresi quelli che utilizzano il codice C, dichiarando le dipendenze in un file requirements.txt.

Panoramica del processo di migrazione del runtime

Consigliamo il seguente approccio incrementale alla migrazione del runtime, in cui manteni un'applicazione funzionante e testabile per tutta la durata del processo:

  1. Esegui l'upgrade dell'app in modo che sia compatibile con Python 3.

    Sono disponibili diverse soluzioni per facilitare l'upgrade. Ad esempio, utilizza Six, Python-Future o Python-Modernize.

    Per ulteriori informazioni su questo passaggio del processo di migrazione del runtime, consulta Trasferimento del codice Python 2 a Python 3 sul sito della documentazione di Python Software Foundation.

  2. Scegli una di queste strategie di implementazione per qualsiasi servizio in bundle di App Engine utilizzato dalla tua app:

    1. Esegui la migrazione dei servizi in bundle legacy nell'app Python 2 a servizi Google Cloud non in bundle, servizi di terze parti o altre sostituzioni consigliate.

    2. Continua a utilizzare i servizi in bundle legacy nelle tue app Python 3. Questo approccio offre la flessibilità necessaria per passare ai servizi non in bundle più avanti nel ciclo di migrazione.

    Assicurati di testare l'app dopo aver eseguito la migrazione di ciascun servizio.

  3. Prepara i file di configurazione di App Engine per il runtime Python 3. Varie modifiche importanti influiscono sulle impostazioni di configurazione in app.yaml, incluse, a titolo esemplificativo:

    • Ora si presume che le app siano threadsafe. Se la tua applicazione non è threadsafe, devi impostare max_concurrent_requests in app.yaml su 1. Questa impostazione potrebbe comportare la creazione di un numero maggiore di istanze del necessario per un'app threadsafe, con costi inutili.
    • Il file app.yaml non indirizza più le richieste ai tuoi script. Devi utilizzare un framework web con il routing in-app e aggiornare o rimuovere tutti i gestori script in app.yaml. Per un esempio di come eseguire questa operazione con il framework Flask, consulta l'esempio di codice della guida alla migrazione di App Engine in GitHub.

      Per scoprire di più su come modificare questo e altri file di configurazione, consulta la sezione File di configurazione.

  4. Nei runtime di seconda generazione, i log delle app non sono più nidificati nei log delle richieste. Sono necessari passaggi aggiuntivi per visualizzare la visualizzazione nidificata dei log delle richieste e delle app in Esplora log. Per ulteriori informazioni, consulta Eseguire la migrazione a Cloud Logging.

  5. Testa ed esegui il deployment dell'app di cui è stato eseguito l'upgrade in un ambiente Python 3.

    Una volta superati tutti i test, esegui il deployment dell'app aggiornata in App Engine, ma evita il routing automatico del traffico alla nuova versione. Utilizza la suddivisione del traffico per eseguire lentamente la migrazione del traffico dalla tua app nel runtime Python 2 all'app nel runtime Python 3. In caso di problemi, puoi instradare tutto il traffico a una versione stabile finché il problema non viene risolto.

Per esempi su come convertire le tue app Python 2 in Python 3, puoi fare riferimento a queste risorse aggiuntive.

Differenze principali tra i runtime Python 2 e Python 3

La maggior parte delle modifiche da apportare durante la migrazione del runtime deriva dalle seguenti differenze tra i runtime Python 2 e Python 3:

Differenze di utilizzo della memoria

Per i runtime di seconda generazione, la base di utilizzo della memoria è maggiore rispetto ai runtime di prima generazione. Ciò è dovuto a più fattori, ad esempio diverse versioni delle immagini di base e alle differenze nel modo in cui le due generazioni calcolano l'utilizzo della memoria.

I runtime di seconda generazione calcolano l'utilizzo della memoria dell'istanza come somma di ciò che viene usato da un processo di applicazione e del numero di file dell'applicazione memorizzati nella cache in modo dinamico. Per evitare che le applicazioni che consumano molta memoria subiscano arresti delle istanze a causa del superamento dei limiti di memoria, esegui l'upgrade a una classe di istanza più grande con più memoria.

Differenze di utilizzo della CPU

I runtime di seconda generazione possono notare una base di utilizzo della CPU più elevata in caso di avvio a freddo delle istanze. A seconda della configurazione di scalabilità di un'applicazione, questo potrebbe avere effetti collaterali involontari, ad esempio un numero di istanze più elevato del previsto se un'applicazione è configurata per la scalabilità in base all'utilizzo della CPU. Per evitare questo problema, esamina e testa le configurazioni di scalabilità delle applicazioni per assicurarti che il numero di istanze sia accettabile.

Differenze nell'intestazione delle richieste

I runtime di prima generazione consentono di inoltrare all'applicazione le intestazioni delle richieste con trattini bassi (ad es. X-Test-Foo_bar). I runtime di seconda generazione introducono Nginx nell'architettura host. A seguito di questa modifica, i runtime di seconda generazione sono configurati in modo da rimuovere automaticamente le intestazioni con trattini bassi (_). Per evitare problemi dell'applicazione, evita di utilizzare i trattini bassi nelle intestazioni delle richieste dell'applicazione.

Differenze dei worker Gunicorn

Per i runtime Python 3 e versioni successive, il numero di worker Gunicorn ha un impatto diretto sull'utilizzo della memoria. L'aumento dell'utilizzo della memoria è direttamente proporzionale all'aumento del conteggio dei worker. Per ridurre il consumo di memoria, valuta di ridurre il numero di worker Gunicorn. Consulta le best practice per i punti di ingresso per le istruzioni su come configurare il conteggio dei worker di Gunicorn

Problemi di compatibilità tra Python 2 e Python 3

Quando Python 3 è stato rilasciato per la prima volta nel 2008, sono state introdotte diverse modifiche incompatibili con le versioni precedenti. Alcune di queste modifiche richiedono solo aggiornamenti di minore entità al codice, ad esempio la modifica dell'istruzione print in una funzione print(). Altre modifiche potrebbero richiedere aggiornamenti significativi al codice, ad esempio l'aggiornamento del modo in cui gestisci dati binari, testo e stringhe.

Anche molte librerie open source popolari, incluse le librerie standard Python, sono cambiate quando sono passate da Python 2 a Python 3.

Servizi in bundle di App Engine nel runtime Python 3

Per ridurre il lavoro e la complessità della migrazione, l'ambiente standard di App Engine consente di accedere a molti dei servizi e delle API in bundle legacy nel runtime Python 3, ad esempio Memcache. L'app Python 3 può chiamare le API dei servizi in bundle tramite librerie idiomatiche di linguaggio e accedere alle stesse funzionalità del runtime Python 2.

Hai anche la possibilità di utilizzare prodotti Google Cloud che offrono funzionalità simili a quelle dei servizi in bundle legacy. Ti consigliamo di eseguire la migrazione ai prodotti Google Cloud non in bundle, in quanto ciò ti consente di sfruttare i miglioramenti continui e le nuove funzionalità.

Per i servizi in bundle che non sono disponibili come prodotti separati in Google Cloud, ad esempio elaborazione di immagini, ricerca e messaggistica, puoi utilizzare i nostri fornitori di terze parti suggeriti o altre soluzioni alternative.

File di configurazione

Prima di poter eseguire l'app nel runtime Python 3 dell'ambiente standard di App Engine, potresti dover modificare alcuni dei file di configurazione utilizzati da App Engine:

Framework web necessario per indirizzare le richieste di contenuti dinamici

Nel runtime Python 2, puoi creare gestori di URL nel file app.yaml per specificare l'app da eseguire quando viene richiesto un URL o un pattern URL specifico.

Nel runtime Python 3, la tua app deve utilizzare un framework web come Flask o Django per instradare le richieste di contenuti dinamici anziché utilizzare gestori di URL in app.yaml. Per i contenuti statici, puoi continuare a creare gestori di URL nel file app.yaml dell'app.

App solo con contenuti statici

Quando ospita un'app web statica su App Engine, devi specificare nel file app.yaml i gestori per mappare gli URL ai file statici.

In Python 2, se una richiesta non corrisponde a nessuno dei gestori specificati nel file app.yaml, App Engine restituisce un codice di errore 404.

In Python 3, se una richiesta non corrisponde a nessuno dei gestori, App Engine cerca un file main.py e restituisce un errore 5xx se un file main.py non viene trovato. Poiché le app App Engine con solo contenuti statici non richiedono un file main.py, la maggior parte degli utenti visualizza questo errore, oltre a visualizzare gli errori di avvio dell'istanza nei log delle app.

Per mantenere lo stesso comportamento di restituzione di un errore 404 quando nessuno dei gestori statici corrisponde ed evitare errori nei log, puoi:

  • Aggiungi un gestore statico catch-all che punta a una directory vuota nel file app.yaml
  • Aggiungi un'app dinamica semplice nel file main.py per restituire un errore 404

Esempi di utilizzo di una delle due opzioni:

app.yaml

Crea una directory vuota nella directory principale dell'app, ad esempio empty/. Nella sezione del gestore del file app.yaml, crea un nuovo gestore alla fine per rilevare tutti gli altri pattern URL e specifica la directory empty negli elementi static_files e upload:

  handlers:
  - url:
    .
    .
    .
  - url: /(.*)$
    static_files: empty/\1
    upload: empty/.*$

main.py

Crea un file main.py e aggiungi il seguente codice per restituire un errore 404:

  def app(env, start_response):
    start_response('404 Not Found', [('Content-Type','text/html')])
    return [b"Not Found"]

Test

Ti consigliamo di utilizzare un approccio di test idiomatico a Python, anziché dipendere da dev_appserver. Ad esempio, potresti usare venv per creare un ambiente Python 3 locale isolato. Puoi utilizzare qualsiasi framework di test Python standard per scrivere test di unità, integrazione e sistema. Potresti anche configurare versioni di sviluppo dei tuoi servizi o utilizzare gli emulatori locali disponibili per molti prodotti Google Cloud.

Facoltativamente, puoi utilizzare la versione di anteprima di dev_appserver che supporta Python 3. Per scoprire di più su questa funzionalità di test, consulta Utilizzo del server di sviluppo locale.

Deployment in corso

I deployment tramite appcfg.py non sono supportati per Python 3. Utilizza invece lo strumento a riga di comando gcloud per eseguire il deployment della tua app.

Logging

Il logging nel runtime Python 3 segue lo standard di logging in Cloud Logging. Nel runtime Python 3, i log delle app non sono più raggruppati con i log delle richieste, ma sono separati in record diversi. Per scoprire di più sulla lettura e sulla scrittura dei log nel runtime Python 3, consulta la guida alla registrazione.

Risorse aggiuntive per la migrazione

Per ulteriori informazioni su come eseguire la migrazione delle app App Engine ai servizi Cloud autonomi o al runtime Python 3, consulta queste risorse di App Engine: