Funzioni Cloud Functions HTTP in Python

1. Introduzione

b158ce75c3cccd6d.png

Python è un popolare linguaggio di programmazione open source utilizzato da data scientist, sviluppatori di applicazioni web, amministratori di sistema e altro ancora.

Cloud Functions è una piattaforma di serverless computing basata su eventi. Cloud Functions ti consente di scrivere il codice senza preoccuparti del provisioning delle risorse o della scalabilità per gestire i requisiti in continuo cambiamento.

Esistono due tipi di funzioni Cloud Functions:

  • Le funzioni HTTP rispondono alle richieste HTTP. In questo codelab ne creerai un paio.
  • Le funzioni in background sono attivate da eventi, come la pubblicazione di un messaggio in Cloud Pub/Sub o il caricamento di un file in Cloud Storage. Non affronteremo questo problema in questo lab, ma puoi scoprire di più nella documentazione.

efb3268e3b74ed4f.png

Questo codelab ti guiderà nella creazione delle tue funzioni Cloud Functions in Python.

Cosa creerai

In questo codelab, pubblicherai una funzione Cloud Functions che, se richiamata tramite HTTP, visualizza il codice "basato su Python" Logo:

a7aaf656b78050fd.png

Obiettivi didattici

  • Come scrivere una funzione Cloud Functions HTTP.
  • Come scrivere una funzione Cloud Functions HTTP che accetta argomenti.
  • Come testare una funzione Cloud Functions HTTP.
  • Come eseguire un server HTTP Python locale per provare la funzione.
  • Come scrivere una funzione Cloud Functions HTTP che restituisca un'immagine.

2. Configurazione e requisiti

Configurazione dell'ambiente autogestito

  1. Accedi alla console Google Cloud e crea un nuovo progetto o riutilizzane uno esistente. Se non hai ancora un account Gmail o Google Workspace, devi crearne uno.

fbef9caa1602edd0.png

a99b7ace416376c4.png

5e3ff691252acf41.png

  • Il Nome progetto è il nome visualizzato dei partecipanti del progetto. Si tratta di una stringa di caratteri non utilizzata dalle API di Google. Puoi sempre aggiornarla.
  • L'ID progetto è univoco in tutti i progetti Google Cloud ed è immutabile (non può essere modificato dopo essere stato impostato). La console Cloud genera automaticamente una stringa univoca. di solito non ti importa cosa sia. Nella maggior parte dei codelab, dovrai fare riferimento al tuo ID progetto (in genere identificato come PROJECT_ID). Se l'ID generato non ti soddisfa, potresti generarne un altro casuale. In alternativa, puoi provarne una personalizzata per verificare se è disponibile. Non può essere modificato dopo questo passaggio e rimane per tutta la durata del progetto.
  • Per informazione, c'è un terzo valore, un numero di progetto, utilizzato da alcune API. Scopri di più su tutti e tre questi valori nella documentazione.
  1. Successivamente, dovrai abilitare la fatturazione nella console Cloud per utilizzare risorse/API Cloud. L'esecuzione di questo codelab non ha alcun costo. Per arrestare le risorse ed evitare di incorrere in fatturazione dopo questo tutorial, puoi eliminare le risorse che hai creato o eliminare il progetto. I nuovi utenti di Google Cloud sono idonei al programma prova senza costi di 300$.

Avvia Cloud Shell

Mentre Google Cloud può essere utilizzato da remoto dal tuo laptop, in questo codelab utilizzerai Cloud Shell, un ambiente a riga di comando in esecuzione nel cloud.

Attiva Cloud Shell

  1. Dalla console Cloud, fai clic su Attiva Cloud Shell 853e55310c205094.png.

3c1dabeca90e44e5.png

Se è la prima volta che avvii Cloud Shell, ti verrà mostrata una schermata intermedia che descrive di cosa si tratta. Se ti è stata presentata una schermata intermedia, fai clic su Continua.

9c92662c6a846a5c.png

Il provisioning e la connessione a Cloud Shell dovrebbero richiedere solo qualche istante.

9f0e51b578fecce5.png

Questa macchina virtuale viene caricata con tutti gli strumenti di sviluppo necessari. Offre una home directory permanente da 5 GB e viene eseguita in Google Cloud, migliorando notevolmente le prestazioni di rete e l'autenticazione. Gran parte, se non tutto, del lavoro in questo codelab può essere svolto con un browser.

Una volta stabilita la connessione a Cloud Shell, dovresti vedere che hai eseguito l'autenticazione e che il progetto è impostato sul tuo ID progetto.

  1. Esegui questo comando in Cloud Shell per verificare che l'account sia autenticato:
gcloud auth list

Output comando

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Esegui questo comando in Cloud Shell per confermare che il comando gcloud è a conoscenza del tuo progetto:
gcloud config list project

Output comando

[core]
project = <PROJECT_ID>

In caso contrario, puoi impostarlo con questo comando:

gcloud config set project <PROJECT_ID>

Output comando

Updated property [core/project].

Assicurati che le API Cloud Functions e Cloud Build siano abilitate

Esegui il comando seguente da Cloud Shell per assicurarti che le API Cloud Functions e Cloud Build siano abilitate:

gcloud services enable \
  cloudfunctions.googleapis.com \
  cloudbuild.googleapis.com

Nota: Cloud Build verrà chiamato dal comando gcloud functions deploy e creerà automaticamente il tuo codice in un'immagine container.

Scarica il codice sorgente

Dal terminale Cloud Shell, esegui questi comandi:

REPO_NAME="codelabs"
REPO_URL="https://github.com/GoogleCloudPlatform/$REPO_NAME"
SOURCE_DIR="cloud-functions-python-http"

git clone --no-checkout --filter=blob:none --depth=1 $REPO_URL
cd $REPO_NAME
git sparse-checkout set $SOURCE_DIR
git checkout
cd $SOURCE_DIR

Controlla il contenuto della directory di origine:

ls

Dovresti avere i seguenti file:

main.py  python-powered.png  test_main.py  web_app.py

3. Introduzione a Cloud Functions HTTP

Le funzioni HTTP Cloud Functions in Python sono scritte come normali funzioni Python. La funzione deve accettare un singolo argomento flask.Request, che di solito viene denominato request.

main.py

import flask


def hello_world(request: flask.Request) -> flask.Response:
    """HTTP Cloud Function.

    Returns:
    - "Hello World! 👋"
    """
    response = "Hello World! 👋"

    return flask.Response(response, mimetype="text/plain")

# ...

Puoi aprire il file con il tuo editor della riga di comando preferito (nano, vim o emacs). Puoi anche aprirla nell'editor di Cloud Shell dopo aver impostato la directory di origine come area di lavoro:

cloudshell open-workspace .

Eseguiamo il deployment di questa funzione come funzione Cloud Functions HTTP utilizzando il comando gcloud functions deploy:

FUNCTION_NAME="hello_world"

gcloud functions deploy $FUNCTION_NAME \
  --runtime python312 \
  --trigger-http \
  --allow-unauthenticated

Output comando:

...
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
...
entryPoint: FUNCTION_NAME
httpsTrigger:
  url: https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
...

Note sulle opzioni di gcloud functions deploy:

  • --runtime: specifica il runtime del linguaggio. Per Python, attualmente può essere python37, python38, python39, python310 o python312. Vedi Runtime.
  • --trigger-http: alla funzione verrà assegnato un endpoint. Le richieste HTTP (POST, PUT, GET, DELETE e OPTIONS) all'endpoint attivano l'esecuzione della funzione.
  • --allow-unauthenticated: la funzione sarà pubblica, consentendo a tutti i chiamanti, senza controllare l'autenticazione.
  • Per saperne di più, consulta gcloud Functions deploy.

Per testare la funzione, puoi fare clic sull'URL httpsTrigger.url visualizzato nell'output comando sopra. Puoi anche recuperare l'URL in modo programmatico e chiamare la funzione con i comandi seguenti:

URL=$(gcloud functions describe $FUNCTION_NAME --format "value(httpsTrigger.url)")
curl -w "\n" $URL

Dovresti ottenere il seguente risultato:

Hello World! 👋

4. Scrittura di una funzione Cloud Functions HTTP che accetta argomenti

Le funzioni sono più versatili quando accettano argomenti. Definiamo una nuova funzione hello_name che supporta un parametro name:

main.py

# ...

def hello_name(request: flask.Request) -> flask.Response:
    """HTTP Cloud Function.

    Returns:
    - "Hello {NAME}! 🚀" if "name=NAME" is defined in the GET request
    - "Hello World! 🚀" otherwise
    """
    name = request.args.get("name", "World")
    response = f"Hello {name}! 🚀"

    return flask.Response(response, mimetype="text/plain")

# ...

Eseguiamo il deployment di questa nuova funzione:

FUNCTION_NAME="hello_name"

gcloud functions deploy $FUNCTION_NAME \
  --runtime python312 \
  --trigger-http \
  --allow-unauthenticated

Output comando:

...
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
...
entryPoint: FUNCTION_NAME
httpsTrigger:
  url: https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
...

Per testare la funzione, puoi fare clic sull'URL httpsTrigger.url visualizzato nell'output comando sopra. Puoi anche recuperare l'URL in modo programmatico e chiamare la funzione con i comandi seguenti:

URL=$(gcloud functions describe $FUNCTION_NAME --format "value(httpsTrigger.url)")
curl -w "\n" $URL

Dovresti ottenere il risultato predefinito:

Hello World! 🚀

Stai ricevendo il risultato predefinito perché l'argomento name non è impostato. Aggiungi un parametro all'URL:

curl -w "\n" $URL?name=YOUR%20NAME

Questa volta riceverai una risposta personalizzata:

Hello YOUR NAME! 🚀

Il passaggio successivo consiste nell'aggiungere i test delle unità per garantire che le funzioni continuino a funzionare come previsto quando il codice sorgente viene aggiornato.

5. Redazione dei test

Le funzioni HTTP Cloud Functions in Python vengono testate utilizzando il modulo unittest della libreria standard. Non è necessario eseguire un emulatore o un'altra simulazione per testare la funzione: solo il normale codice Python.

Ecco l'aspetto di un test per le funzioni hello_world e hello_name:

test_main.py

import unittest
import unittest.mock

import main


class TestHello(unittest.TestCase):
    def test_hello_world(self):
        request = unittest.mock.Mock()

        response = main.hello_world(request)
        assert response.status_code == 200
        assert response.get_data(as_text=True) == "Hello World! 👋"

    def test_hello_name_no_name(self):
        request = unittest.mock.Mock(args={})

        response = main.hello_name(request)
        assert response.status_code == 200
        assert response.get_data(as_text=True) == "Hello World! 🚀"

    def test_hello_name_with_name(self):
        name = "FirstName LastName"
        request = unittest.mock.Mock(args={"name": name})

        response = main.hello_name(request)
        assert response.status_code == 200
        assert response.get_data(as_text=True) == f"Hello {name}! 🚀"
  1. I test Python sono scritti allo stesso modo degli altri file Python. Iniziano con un insieme di importazioni, quindi definiscono le classi e le funzioni.
  2. Il formato della dichiarazione di test è class TestHello(TestCase). Deve essere una classe che eredita da unittest.TestCase.
  3. La classe di test ha metodi, ognuno dei quali deve iniziare con test_, che rappresenta i singoli scenari di test.
  4. Ogni scenario di test testa una delle nostre funzioni simulando il parametro request (ovvero sostituendolo con un oggetto falso con i dati specifici richiesti per il test).
  5. Dopo aver richiamato ogni funzione, il test controlla la risposta HTTP per assicurarsi che fosse quella che ci aspettavamo.

Poiché main.py dipende da flask, assicurati che il framework Flask sia installato nel tuo ambiente di test:

pip install flask

L'installazione di Flask restituisce un risultato simile al seguente:

Collecting flask
...
Successfully installed ... flask-3.0.2 ...

Esegui questi test in locale:

python -m unittest

I tre test delle unità devono superare:

...
----------------------------------------------------------------------
Ran 3 tests in 0.001s

OK

Quindi, creerai una nuova funzione che restituisce il comando "Python Powered". .

6. Scrivi il codice "basato su Python" Funzione Cloud Functions HTTP

Rendiamo una nuova funzione un po' più divertente restituendo il codice "basato su Python" immagine per ogni richiesta:

a7aaf656b78050fd.png

Nell'elenco che segue viene mostrato il codice necessario:

main.py

# ...

def python_powered(request: flask.Request) -> flask.Response:
    """HTTP Cloud Function.

    Returns:
    - The official "Python Powered" logo
    """
    return flask.send_file("python-powered.png")

Esegui il deployment di una nuova funzione python_powered:

FUNCTION_NAME="python_powered"

gcloud functions deploy $FUNCTION_NAME \
  --runtime python312 \
  --trigger-http \
  --allow-unauthenticated

Output comando:

...
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
...
entryPoint: FUNCTION_NAME
httpsTrigger:
  url: https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME
...

Per testare la funzione, fai clic sull'URL httpsTrigger.url visualizzato nell'output comando in alto. Se tutto funziona correttamente, vedrai il file "Python basato su Python" in una nuova scheda del browser.

Adesso creerai un'app in modo da poter eseguire e provare la funzione localmente prima del deployment.

7. Esecuzione della funzione in locale

Puoi eseguire una funzione HTTP in locale creando un'app web e chiamando la funzione in una route. Puoi aggiungerlo nella stessa directory della funzione. Il file denominato web_app.py ha i seguenti contenuti:

web_app.py

import flask

import main

app = flask.Flask(__name__)


@app.get("/")
def index():
    return main.python_powered(flask.request)


if __name__ == "__main__":
    # Local development only
    # Run "python web_app.py" and open http://localhost:8080
    app.run(host="localhost", port=8080, debug=True)
  1. Questo file crea un'applicazione Flask.
  2. Registra una route all'URL di base gestito con una funzione denominata index().
  3. La funzione index() chiama quindi la nostra funzione python_powered, passando la richiesta corrente.

Assicurati che il framework Flask sia installato nel tuo ambiente di sviluppo:

pip install flask

L'installazione di Flask restituisce un risultato simile al seguente:

Collecting flask
...
Successfully installed ... flask-3.0.2 ...

Per eseguire questa applicazione in locale, esegui questo comando:

python web_app.py

Ora utilizza l'anteprima web di Cloud Shell per testare l'app web nel tuo browser. In Cloud Shell, fai clic su "Anteprima web". e seleziona "Anteprima sulla porta 8080":

6c9ff9e5c692c58e.gif

Cloud Shell apre l'URL di anteprima nel suo servizio proxy, in una nuova finestra del browser. L'anteprima web limita l'accesso tramite HTTPS esclusivamente al tuo account utente. Se tutto funziona correttamente, dovresti vedere il file "Python basato su Python" Logo.

8e5c3ead11cfd103.png

8. Complimenti!

b158ce75c3cccd6d.png

Hai eseguito il deployment di Cloud Functions HTTP, utilizzando funzioni idiomatiche che gestiscono le richieste web con il framework Flask.

I prezzi di Cloud Functions si basano sulla frequenza con cui viene richiamata la tua funzione, incluso un livello senza costi per le funzioni che non vengono eseguite spesso. Al termine del test delle funzioni Cloud Functions, puoi eliminarle utilizzando gcloud:

gcloud functions delete hello_world --quiet
gcloud functions delete hello_name --quiet
gcloud functions delete python_powered --quiet

Puoi eliminare le funzioni anche dalla console Google Cloud.

Ci auguriamo che l'utilizzo di Cloud Functions in Python sia di tuo gradimento.