Il runtime Python

Il runtime Python è lo stack software responsabile dell'installazione del codice e delle dipendenze dell'applicazione e dell'esecuzione dell'applicazione nell'ambiente flessibile.

  • Le versioni 3.8 e successive sono basate su buildpacks, che richiede la scelta di un sistema operativo nel file app.yaml. Ad esempio, per utilizzare Python 3.12, devi specificare Ubuntu 22 come sistema operativo.

  • Le versioni 3.7 e precedenti sono state create utilizzando Docker.

Per l'elenco completo delle versioni di Python supportate e delle versioni di Ubuntu corrispondenti, consulta la pianificazione del supporto per l'esecuzione.

Nuove versioni di runtime

Per il runtime Python 3.8 e versioni successive, devi includere le impostazioni runtime_config e operating_system nel file app.yaml per specificare un sistema operativo.

Per utilizzare i nuovi runtime, devi installare la versione 420.0.0 o successiva dell'interfaccia a riga di comando di gcloud. Puoi aggiornare gli strumenti dell'interfaccia a riga di comando eseguendo il comando gcloud components update. Per visualizzare la versione installata, esegui il comando gcloud version.

(Facoltativo) Puoi specificare una versione del runtime includendo l'impostazione runtime_version nel file app.yaml. Per impostazione predefinita, se l'impostazione runtime_version non è specificata viene utilizzata la versione Python più recente.

Esempi

  • Per specificare Python 3.12 su Ubuntu 22:

    runtime: python
    env: flex
    entrypoint: gunicorn -b :$PORT main:app
    
    runtime_config:
        operating_system: "ubuntu22"
        runtime_version: "3.12"
    
  • Per specificare l'ultima versione supportata di Python su Ubuntu 22:

      runtime: python
      env: flex
      entrypoint: gunicorn -b :$PORT main:app
    
      runtime_config:
          operating_system: "ubuntu22"
    

Per ulteriori informazioni, consulta la pagina di riferimento app.yaml.

Versioni di runtime precedenti

Per la versione 3.7 e precedenti di Python, puoi specificare una versione utilizzando le impostazioni runtime_config e python_version nel file app.yaml dell'applicazione.

Esempio

runtime: python
env: flex
entrypoint: gunicorn -b :$PORT main:app

runtime_config:
    python_version: 3.7

Per Python 3.7 e versioni precedenti, l'interprete predefinito è Python 2.7.12 se runtime_config o python_version sono omessi. Ad esempio, puoi utilizzare il runtime predefinito specificando runtime: python nel file app.yaml:

runtime: python
env: flex

Per ulteriori informazioni, consulta la pagina di riferimento app.yaml.

Gli interpreti di cui viene eseguito il deployment per ogni impostazione della versione sono mostrati nella seguente tabella:

python_version impostazione Interprete di cui è stato eseguito il deployment ID runtime Esempio di app.yaml
2 (valore predefinito) 2.7.12 python2 runtime_config:
python_version: 2
3.4 3.4.8 python34 runtime_config:
python_version: 3.4
3.5 3.5.9 python35 runtime_config:
python_version: 3.5
3 o 3.6 3.6.10 python36 runtime_config:
python_version: 3
3.7 3.7.9 python37 runtime_config:
python_version: 3.7

Supporto di altro runtime Python

Se la versione Python desiderata non è elencata, sono disponibili diverse opzioni:

  1. Ambiente flessibile di App Engine: crea un runtime personalizzato e seleziona un'immagine di base valida con la versione Python che ti serve.
  2. Ambiente standard di App Engine: sono supportati Python 3.7, 3.8, 3.9, 3.10 e 3.11.
  3. Cloud Functions: sono supportati Python 3.7, 3.8, 3.9 e 3.10.
  4. Cloud Run: containerizza la tua app in base a un'immagine container per la versione Python di cui hai bisogno (consulta la guida rapida di Python). Poiché le immagini Python 3.10 sono già disponibili, puoi eseguire il deployment di quella versione oggi stesso.

Per l'ambiente flessibile di App Engine o Cloud Run, consulta Creazione di runtime personalizzati per le immagini di base fornite da Google o Immagini di base Python Docker per le immagini Python attualmente disponibili, incluse le informazioni sulle immagini Python 2.

Per esaminare ulteriormente la containerizzazione delle app App Engine per Cloud Run, consulta il codelab e i contenuti video relativi alla containerizzazione con Docker o senza Docker. Tieni presente che al momento questi contenuti riguardano solo le migrazioni dell'ambiente standard di App Engine alle migrazioni di Cloud Run.

Dipendenze

Il runtime cerca un file requirements.txt nella directory di origine dell'applicazione e utilizza pip per installare le dipendenze prima di avviare l'applicazione. Per saperne di più sulla dichiarazione e sulla gestione dei pacchetti, consulta Utilizzo delle librerie Python.

Se la tua app richiede dipendenze private, devi utilizzare un runtime personalizzato basato sul runtime Python per installare i pacchetti appropriati.

Utilizzo delle librerie C con Python

Per abilitare l'utilizzo dei pacchetti Python che richiedono estensioni C, le intestazioni per la versione corrente di Python e i seguenti pacchetti Ubuntu sono preinstallati nel sistema:

  • build-essential
  • ca-certificates
  • curl
  • gfortran
  • git
  • libatlas-dev
  • libblas-dev
  • libcurl4-openssl-dev
  • libffi-dev
  • libfreetype6-dev
  • libjpeg-dev
  • liblapack-dev
  • libmemcached-dev
  • libmysqlclient-dev
  • libpng12-dev
  • libpq-dev
  • libquadmath0
  • libsasl2-2
  • libsasl2-dev
  • libsasl2-modules
  • libsqlite3-dev
  • libssl-dev
  • libxml2-dev
  • libxslt1-dev
  • libz-dev
  • mercurial
  • netbase
  • pkg-config
  • sasl2-bin
  • swig
  • wget
  • zlib1g-dev

Questi pacchetti consentono l'installazione delle librerie Python più diffuse. Se la tua applicazione richiede ulteriori dipendenze a livello di sistema operativo, dovrai utilizzare un runtime personalizzato basato su questo runtime per installare i pacchetti appropriati.

Avvio dell'applicazione

Il runtime avvia l'applicazione utilizzando il criterio entrypoint definito nel file app.yaml. Il punto di ingresso deve avviare un processo che risponda alle richieste HTTP sulla porta definita dalla variabile di ambiente PORT.

La maggior parte delle applicazioni web utilizza un server WSGI come Gunicorn, uWSGI o Attendress.

Prima di poter utilizzare uno di questi server, devi aggiungerli come dipendenza in requirements.txt dell'applicazione. Se utilizzi gunicorn per la tua applicazione Flask, assicurati che la versione Python dell'applicazione sia compatibile con gunicorn.

Il runtime assicura che tutte le dipendenze vengano installate prima della chiamata del punto di ingresso.

Flask==2.0.2
gunicorn==20.1.0

Un punto di ingresso di esempio in cui viene utilizzato gunicorn per un'applicazione Flask:

entrypoint: gunicorn -b :$PORT main:app

Ecco un esempio di punto di ingresso in cui viene utilizzato gunicorn per un'applicazione Django:

entrypoint: gunicorn -b :$PORT mydjangoapp:wsgi

Gunicorn è il server WSGI consigliato, ma è assolutamente possibile utilizzare qualsiasi altro server WSGI. Ad esempio, ecco un punto di ingresso che utilizza uWSGI con Flask:

entrypoint: uwsgi --http :$PORT --wsgi-file main.py --callable app

Per le applicazioni in grado di gestire le richieste senza un server WSGI, puoi semplicemente eseguire uno script Python:

entrypoint: python main.py

Gli esempi di entry point di base mostrati sopra sono da intendersi come punti di partenza e potrebbero funzionare per le tue applicazioni web. Tuttavia, la maggior parte delle applicazioni dovrà configurare ulteriormente il server WSGI. Anziché specificare tutte le impostazioni nel punto di ingresso, crea un file gunicorn.conf.py nella directory root del progetto, in cui si trova il file app.yaml, e specificalo nel punto di ingresso:

entrypoint: gunicorn -c gunicorn.conf.py -b :$PORT main:app

Puoi leggere tutti i valori di configurazione di Gunicorn nella sua documentazione.

Worker

Gunicorn utilizza i worker per gestire le richieste. Per impostazione predefinita, Gunicorn utilizza i sync worker. Questa classe worker è compatibile con tutte le applicazioni web, ma ogni worker può gestire una sola richiesta alla volta. Per impostazione predefinita, gunicorn utilizza uno di questi worker. Questo può spesso causare il sottoutilizzo delle istanze e l'aumento della latenza nelle applicazioni sotto carico.

Ti consigliamo di impostare il numero di worker su 2-4 volte il numero di core della CPU per l'istanza più uno. Puoi specificare questo elemento in gunicorn.conf.py come:

import multiprocessing

workers = multiprocessing.cpu_count() * 2 + 1

Inoltre, alcune applicazioni web che sono per lo più legate all'I/O possono migliorare le prestazioni utilizzando una classe worker diversa. Se la tua classe worker richiede dipendenze aggiuntive, ad esempio gevent o tornado, dovranno essere dichiarate nel requirements.txt dell'applicazione.

HTTPS e proxy di inoltro

App Engine termina la connessione HTTPS al bilanciatore del carico e inoltra la richiesta alla tua applicazione. La maggior parte delle applicazioni non ha bisogno di sapere se la richiesta è stata inviata tramite HTTPS o meno, ma le applicazioni che hanno bisogno di queste informazioni devono configurare Gunicorn in modo che consideri attendibile il proxy App Engine nel proprio gunicorn.conf.py:

forwarded_allow_ips = '*'
secure_scheme_headers = {'X-FORWARDED-PROTO': 'https'}

Gunicorn ora garantirà che il valore da wsgi.url_scheme a 'https', che la maggior parte dei framework web utilizzerà per indicare che la richiesta è sicura. Se il tuo server o framework WSGI non supporta questa funzionalità, controlla manualmente il valore dell'intestazione X-Forwarded-Proto.

Alcune applicazioni devono anche verificare l'indirizzo IP dell'utente. Questa opzione è disponibile nell'intestazione X-Forwarded-For.

Tieni presente che l'impostazione secure_scheme_headers in gunicorn.conf.py deve essere in maiuscolo, ad esempio X-FORWARDED-PROTO, ma le intestazioni che il tuo codice può leggere saranno in lettere maiuscole e minuscole, ad esempio X-Forwarded-Proto.

Estendere il runtime

Il runtime Python dell'ambiente flessibile può essere utilizzato per creare un runtime personalizzato. Per ulteriori informazioni, consulta Personalizzazione di Python.

Variabili di ambiente

Le seguenti variabili di ambiente sono impostate dall'ambiente di runtime:

Variabile di ambiente Descrizione
GAE_INSTANCE Il nome dell'istanza corrente.
GAE_MEMORY_MB La quantità di memoria disponibile per il processo di applicazione.
GAE_SERVICE Il nome del servizio specificato nel file app.yaml della tua applicazione oppure, se non viene specificato alcun nome, il nome è impostato su default.
GAE_VERSION L'etichetta della versione dell'applicazione corrente.
GOOGLE_CLOUD_PROJECT L'ID progetto associato all'applicazione, visibile nella console Google Cloud
PORT La porta che riceverà le richieste HTTP.

Puoi impostare variabili di ambiente aggiuntive nel file app.yaml.

Server metadati

Ogni istanza dell'applicazione può utilizzare il server di metadati di Compute Engine per eseguire query sulle informazioni relative all'istanza, tra cui nome host, indirizzo IP esterno, ID istanza, metadati personalizzati e informazioni sull'account di servizio. App Engine non consente di impostare metadati personalizzati per ogni istanza, ma puoi impostare metadati personalizzati a livello di progetto e leggerli dalle istanze di App Engine e Compute Engine.

Questa funzione di esempio utilizza il server metadati per ottenere l'indirizzo IP esterno dell'istanza:

METADATA_NETWORK_INTERFACE_URL = (
    "http://metadata/computeMetadata/v1/instance/network-interfaces/0/"
    "access-configs/0/external-ip"
)


def get_external_ip():
    """Gets the instance's external IP address from the Compute Engine metadata
    server.

    If the metadata server is unavailable, it assumes that the application is running locally.

    Returns:
        The instance's external IP address, or the string 'localhost' if the IP address
        is not available.
    """
    try:
        r = requests.get(
            METADATA_NETWORK_INTERFACE_URL,
            headers={"Metadata-Flavor": "Google"},
            timeout=2,
        )
        return r.text
    except requests.RequestException:
        logging.info("Metadata server could not be reached, assuming local.")
        return "localhost"