1. Introduzione

Puoi utilizzare Workflows per creare workflow serverless che collegano una serie di attività serverless in un ordine definito da te. Puoi combinare la potenza delle API di Google Cloud, dei prodotti serverless come Cloud Functions e Cloud Run e delle chiamate ad API esterne per creare applicazioni serverless flessibili.
Workflows non richiede alcuna gestione dell'infrastruttura e offre scalabilità senza interruzioni in base alla domanda, incluso lo scale down fino a zero. Grazie al modello di prezzi a consumo, paghi solo in base al tempo di esecuzione.
In questo codelab imparerai a connettere vari servizi Google Cloud e API HTTP esterne con Workflows. Più nello specifico, collegherai due servizi Cloud Functions pubblici, un servizio Cloud Run privato e un'API HTTP pubblica esterna in un workflow.
Obiettivi didattici
- Nozioni di base su Workflows.
- Come connettere Cloud Functions pubbliche a Workflows.
- Come connettere servizi Cloud Run privati con Workflows.
- Come connettere API HTTP esterne con Workflows.
2. Configurazione e requisiti
Configurazione dell'ambiente autonomo
- Accedi alla console Cloud e crea un nuovo progetto o riutilizzane uno esistente. Se non hai già un account Gmail o G Suite, devi crearne uno.
Ricorda l'ID progetto, un nome univoco tra tutti i progetti Google Cloud (il nome sopra è già stato utilizzato e non funzionerà per te, mi dispiace). In questo codelab verrà chiamato PROJECT_ID.
- Successivamente, dovrai abilitare la fatturazione in Cloud Console per utilizzare le risorse Google Cloud.
L'esecuzione di questo codelab non dovrebbe costare molto, se non nulla. Assicurati di seguire le istruzioni riportate nella sezione "Pulizia", che ti consiglia come arrestare le risorse in modo da non incorrere in addebiti oltre questo tutorial. I nuovi utenti di Google Cloud possono beneficiare del programma prova senza costi di 300$.
Avvia Cloud Shell
Sebbene Google Cloud possa essere gestito da remoto dal tuo laptop, in questo codelab utilizzerai Google Cloud Shell, un ambiente a riga di comando in esecuzione nel cloud.
Nella console GCP, fai clic sull'icona di Cloud Shell nella barra degli strumenti in alto a destra:
Bastano pochi istanti per eseguire il provisioning e connettersi all'ambiente. Al termine, dovresti vedere un risultato simile a questo:
Questa macchina virtuale è caricata con tutti gli strumenti per sviluppatori di cui avrai bisogno. Offre una home directory permanente da 5 GB e viene eseguita su Google Cloud, migliorando notevolmente le prestazioni e l'autenticazione della rete. Tutto il lavoro di questo lab può essere svolto semplicemente con un browser.
3. Panoramica di Workflows
Nozioni di base
Un workflow è costituito da una serie di passaggi descritti utilizzando la sintassi basata su YAML di Workflows. Questa è la definizione di workflow. Per una spiegazione dettagliata della sintassi YAML di Workflows, consulta la pagina Riferimento alla sintassi.
Quando viene creato un workflow, viene eseguito il deployment, rendendolo pronto per l'esecuzione. Un'esecuzione è una singola esecuzione della logica contenuta nella definizione di un workflow. Tutte le esecuzioni di un workflow sono indipendenti e il prodotto supporta un numero elevato di esecuzioni simultanee.
Attivare i servizi
In questo codelab, collegherai Cloud Functions, i servizi Cloud Run e Workflows. Utilizzerai anche Cloud Build e Cloud Storage durante la creazione dei servizi.
Attiva tutti i servizi necessari:
gcloud services enable \ cloudfunctions.googleapis.com \ run.googleapis.com \ workflows.googleapis.com \ cloudbuild.googleapis.com \ storage.googleapis.com
Nel passaggio successivo, collegherai due Cloud Functions in un workflow.
4. Esegui il deployment della prima funzione Cloud Functions
La prima funzione è un generatore di numeri casuali in Python.
Crea una directory per il codice della funzione e accedi a questa directory:
mkdir ~/randomgen cd ~/randomgen
Crea un file main.py nella directory con il seguente contenuto:
import random, json
from flask import jsonify
def randomgen(request):
randomNum = random.randint(1,100)
output = {"random":randomNum}
return jsonify(output)
Quando riceve una richiesta HTTP, questa funzione genera un numero casuale compreso tra 1 e 100 e lo restituisce al chiamante in formato JSON.
La funzione si basa su Flask per l'elaborazione HTTP e dobbiamo aggiungerlo come dipendenza. Le dipendenze in Python vengono gestite con pip e sono espresse in un file di metadati chiamato requirements.txt.
Crea un file requirements.txt nella stessa directory con il seguente contenuto:
flask>=1.0.2
Esegui il deployment della funzione con un trigger HTTP e con le richieste non autenticate consentite con questo comando:
gcloud functions deploy randomgen \
--runtime python312 \
--trigger-http \
--allow-unauthenticated
Una volta eseguito il deployment della funzione, puoi visualizzare il relativo URL nella proprietà url visualizzata nella console o con il comando gcloud functions describe.
Puoi anche visitare l'URL della funzione con il seguente comando curl:
curl $(gcloud functions describe randomgen --format='value(url)')
La funzione è pronta per il workflow.
5. Esegui il deployment della seconda funzione Cloud Functions
La seconda funzione è un moltiplicatore. Moltiplica l'input ricevuto per 2.
Crea una directory per il codice della funzione e accedi a questa directory:
mkdir ~/multiply cd ~/multiply
Crea un file main.py nella directory con il seguente contenuto:
import random, json
from flask import jsonify
def multiply(request):
request_json = request.get_json()
output = {"multiplied":2*request_json['input']}
return jsonify(output)
Quando riceve una richiesta HTTP, questa funzione estrae input dal corpo JSON, lo moltiplica per 2 e lo restituisce in formato JSON al chiamante.
Crea lo stesso file requirements.txt nella stessa directory con il seguente contenuto:
flask>=1.0.2
Esegui il deployment della funzione con un trigger HTTP e con le richieste non autenticate consentite con questo comando:
gcloud functions deploy multiply \
--runtime python312 \
--trigger-http \
--allow-unauthenticated
Una volta eseguito il deployment della funzione, puoi anche visitare l'URL della funzione con il seguente comando curl:
curl $(gcloud functions describe multiply --format='value(url)') \
-X POST \
-H "content-type: application/json" \
-d '{"input": 5}'
La funzione è pronta per il workflow.
6. Collega due funzioni Cloud Functions
Nel primo workflow, collega le due funzioni.
Crea un file workflow.yaml con il seguente contenuto.
- randomgenFunction:
call: http.get
args:
url: https://<region>-<project-id>.cloudfunctions.net/randomgen
result: randomgenResult
- multiplyFunction:
call: http.post
args:
url: https://<region>-<project-id>.cloudfunctions.net/multiply
body:
input: ${randomgenResult.body.random}
result: multiplyResult
- returnResult:
return: ${multiplyResult}
In questo flusso di lavoro, ottieni un numero casuale dalla prima funzione e lo passi alla seconda funzione. Il risultato è il numero casuale moltiplicato.
Esegui il deployment del primo workflow:
gcloud workflows deploy workflow --source=workflow.yaml
Esegui il primo workflow:
gcloud workflows execute workflow
Una volta eseguito il workflow, puoi visualizzare il risultato passando l'ID esecuzione fornito nel passaggio precedente:
gcloud workflows executions describe <your-execution-id> --workflow workflow
L'output includerà result e state:
result: '{"body":{"multiplied":108},"code":200 ... }
...
state: SUCCEEDED
7. Connettere un'API HTTP esterna
Successivamente, connetterai math.js come servizio esterno nel flusso di lavoro.
In math.js, puoi valutare le espressioni matematiche nel seguente modo:
curl https://api.mathjs.org/v4/?'expr=log(56)'
Questa volta utilizzerai Cloud Console per aggiornare il flusso di lavoro. Trova Workflows nella console Google Cloud:

Trova il tuo flusso di lavoro e fai clic sulla scheda Definition:

Modifica la definizione del workflow e includi una chiamata a math.js.
- randomgenFunction:
call: http.get
args:
url: https://<region>-<project-id>.cloudfunctions.net/randomgen
result: randomgenResult
- multiplyFunction:
call: http.post
args:
url: https://<region>-<project-id>.cloudfunctions.net/multiply
body:
input: ${randomgenResult.body.random}
result: multiplyResult
- logFunction:
call: http.get
args:
url: https://api.mathjs.org/v4/
query:
expr: ${"log(" + string(multiplyResult.body.multiplied) + ")"}
result: logResult
- returnResult:
return: ${logResult}
Il flusso di lavoro ora inserisce l'output della funzione di moltiplicazione in una chiamata alla funzione di log in math.js.
La UI ti guiderà nella modifica e nel deployment del flusso di lavoro. Una volta eseguito il deployment, fai clic su Execute per eseguire il flusso di lavoro. Vedrai i dettagli dell'esecuzione:

Nota il codice di stato 200 e un body con l'output della funzione di log.
Hai appena integrato un servizio esterno nel nostro flusso di lavoro. Fantastico!
8. Esegui il deployment di un servizio Cloud Run
Nell'ultima parte, finalizza il flusso di lavoro con una chiamata a un servizio Cloud Run privato. Ciò significa che il workflow deve essere autenticato per chiamare il servizio Cloud Run.
Il servizio Cloud Run restituisce il math.floor del numero passato.
Crea una directory per il codice del servizio e vai al suo interno:
mkdir ~/floor cd ~/floor
Crea un file app.py nella directory con il seguente contenuto:
import json
import logging
import os
import math
from flask import Flask, request
app = Flask(__name__)
@app.route('/', methods=['POST'])
def handle_post():
content = json.loads(request.data)
input = float(content['input'])
return f"{math.floor(input)}", 200
if __name__ != '__main__':
# Redirect Flask logs to Gunicorn logs
gunicorn_logger = logging.getLogger('gunicorn.error')
app.logger.handlers = gunicorn_logger.handlers
app.logger.setLevel(gunicorn_logger.level)
app.logger.info('Service started...')
else:
app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))
Cloud Run esegue il deployment dei container, quindi hai bisogno di un Dockerfile e il tuo container deve essere associato alle variabili di ambiente 0.0.0.0 e PORT, da cui il codice riportato sopra.
Quando riceve una richiesta HTTP, questa funzione estrae input dal corpo JSON, chiama math.floor e restituisce il risultato al chiamante.
Nella stessa directory, crea il seguente Dockerfile:
# Use an official lightweight Python image. # https://hub.docker.com/_/python FROM python:3.7-slim # Install production dependencies. RUN pip install Flask gunicorn # Copy local code to the container image. WORKDIR /app COPY . . # Run the web service on container startup. Here we use the gunicorn # webserver, with one worker process and 8 threads. # For environments with multiple CPU cores, increase the number of workers # to be equal to the cores available. CMD exec gunicorn --bind 0.0.0.0:8080 --workers 1 --threads 8 app:app
Crea il container:
export SERVICE_NAME=floor
gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}
Una volta creato il container, esegui il deployment in Cloud Run. Nota il flag no-allow-unauthenticated. In questo modo, il servizio accetta solo chiamate autenticate:
gcloud run deploy ${SERVICE_NAME} \
--image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \
--platform managed \
--no-allow-unauthenticated
Una volta eseguito il deployment, il servizio è pronto per il workflow.
9. Collega il servizio Cloud Run
Prima di poter configurare Workflows per chiamare il servizio Cloud Run privato, devi creare un service account da utilizzare per Workflows:
export SERVICE_ACCOUNT=workflows-sa
gcloud iam service-accounts create ${SERVICE_ACCOUNT}
Concedi il ruolo run.invoker al service account. In questo modo, il service account potrà chiamare i servizi Cloud Run autenticati:
gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \
--member "serviceAccount:${SERVICE_ACCOUNT}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \
--role "roles/run.invoker"
Aggiorna la definizione del flusso di lavoro in workflow.yaml in modo da includere il servizio Cloud Run. Nota che stai includendo anche il campo auth per assicurarti che Workflows trasmetta il token di autenticazione nelle chiamate al servizio Cloud Run:
- randomgenFunction:
call: http.get
args:
url: https://<region>-<project-id>.cloudfunctions.net/randomgen
result: randomgenResult
- multiplyFunction:
call: http.post
args:
url: https://<region>-<project-id>.cloudfunctions.net/multiply
body:
input: ${randomgenResult.body.random}
result: multiplyResult
- logFunction:
call: http.get
args:
url: https://api.mathjs.org/v4/
query:
expr: ${"log(" + string(multiplyResult.body.multiplied) + ")"}
result: logResult
- floorFunction:
call: http.post
args:
url: https://floor-<random-hash>.run.app
auth:
type: OIDC
body:
input: ${logResult.body}
result: floorResult
- returnResult:
return: ${floorResult}
Aggiorna il workflow. Questa volta passando in service-account:
gcloud workflows deploy workflow \
--source=workflow.yaml \
--service-account=${SERVICE_ACCOUNT}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com
Esegui il workflow:
gcloud workflows execute workflow
Dopo qualche secondo, puoi esaminare l'esecuzione del workflow per vedere il risultato:
gcloud workflows executions describe <your-execution-id> --workflow workflow
L'output includerà un numero intero result e state:
result: '{"body":"5","code":200 ... }
...
state: SUCCEEDED
10. Complimenti!
Congratulazioni per aver completato il codelab.
Argomenti trattati
- Nozioni di base su Workflows.
- Come connettere Cloud Functions pubbliche a Workflows.
- Come connettere servizi Cloud Run privati con Workflows.
- Come connettere API HTTP esterne con Workflows.