Utilizzare Workflows per collegare i servizi

Questo tutorial mostra come utilizzare Workflows per collegare una serie di servizi. Se colleghi due servizi HTTP pubblici utilizzando le funzioni Cloud Run, un'API REST esterna e un servizio Cloud Run privato, puoi creare un'applicazione serverless flessibile.

Esegui il deployment delle prime funzioni Cloud Run

Dopo aver ricevuto una richiesta HTTP, questa funzione HTTP genera un numero casuale compreso tra 1 e 100, quindi restituisce il numero in formato JSON.

  1. Crea una directory denominata randomgen e passa a questa directory:

    mkdir ~/randomgen
    cd ~/randomgen
  2. Crea un file di testo con il nome file main.py contenente il seguente codice Python:

    import functions_framework
    import random
    from flask import jsonify
    
    
    @functions_framework.http
    def randomgen(request):
        randomNum = random.randint(1, 100)
        output = {"random": randomNum}
        return jsonify(output)
  3. Per supportare una dipendenza da Flask per l'elaborazione HTTP, crea un file di testo per il gestore di pacchetti pip. Assegna il nome requirements.txt e aggiungi quanto segue:

    flask>=1.0.2
    functions-framework==3.0.0
  4. Esegui il deployment della funzione con un trigger HTTP e consenti l'accesso non autenticato:

    gcloud functions deploy randomgen-function \
        --gen2 \
        --runtime python310 \
        --entry-point=randomgen \
        --trigger-http \
        --allow-unauthenticated

    Il deployment della funzione potrebbe richiedere alcuni minuti. In alternativa, puoi utilizzare l'interfaccia Cloud Run Functions nella console Google Cloud per eseguire il deployment della funzione.

  5. Una volta eseguito il deployment della funzione randomgen, puoi confermare la proprietà httpsTrigger.url:

    gcloud functions describe randomgen-function \
        --gen2 \
        --format="value(serviceConfig.uri)"
  6. Salva l'URL. Dovrai aggiungerlo al file di origine del flusso di lavoro negli esercizi successivi.

  7. Puoi provare la funzione con il seguente comando curl:

    curl $(gcloud functions describe randomgen-function \
        --gen2 \
        --format="value(serviceConfig.uri)")

    Viene generato e restituito un numero casuale.

Esegui il deployment della seconda funzione Cloud Run

Dopo aver ricevuto una richiesta HTTP, questa funzione HTTP estrae input dal corpo JSON, lo moltiplica per 2 e restituisce il risultato in formato JSON.

  1. Torna alla tua home directory:

    cd ~
  2. Crea una directory denominata multiply e passa a questa directory:

    mkdir ~/multiply
    cd ~/multiply
  3. Crea un file di testo con il nome file main.py contenente il seguente codice Python:

    import functions_framework
    from flask import jsonify
    
    
    @functions_framework.http
    def multiply(request):
        request_json = request.get_json()
        output = {"multiplied": 2 * request_json['input']}
        return jsonify(output)
  4. Per supportare una dipendenza da Flask per l'elaborazione HTTP, crea un file di testo per il gestore di pacchetti pip. Assegna il nome requirements.txt e aggiungi quanto segue:

    flask>=1.0.2
    functions-framework==3.0.0
  5. Esegui il deployment della funzione con un trigger HTTP e consenti l'accesso non autenticato:

    gcloud functions deploy multiply-function \
        --gen2 \
        --runtime python310 \
        --entry-point=multiply \
        --trigger-http \
        --allow-unauthenticated

    Il deployment della funzione potrebbe richiedere alcuni minuti. In alternativa, puoi utilizzare l'interfaccia Cloud Run Functions nella console Google Cloud per eseguire il deployment della funzione.

  6. Una volta eseguito il deployment della funzione multiply, puoi confermare la proprietà httpsTrigger.url:

    gcloud functions describe multiply-function \
        --gen2\
        --format="value(serviceConfig.uri)"
  7. Salva l'URL. Dovrai aggiungerlo al file di origine del flusso di lavoro negli esercizi successivi.

  8. Puoi provare la funzione con il seguente comando curl:

    curl -X POST MULTIPLY_FUNCTION_URL \
        -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
        -H "Content-Type: application/json" \
        -d '{"input": 5}'

    Deve essere restituito il numero 10.

Collega le due funzioni Cloud Run in un flusso di lavoro

Un flusso di lavoro è costituito da una serie di passaggi descritti utilizzando la sintassi di Workflows, che può essere scritta in formato YAML o JSON. Questa è la definizione del flusso di lavoro. Per una spiegazione dettagliata, consulta la pagina Riferimento alla sintassi.

  1. Torna alla tua home directory:

    cd ~
  2. Crea un file di testo con il nome file workflow.yaml contenente il seguente contenuto:

    - randomgen_function:
        call: http.get
        args:
            url: RANDOMGEN_FUNCTION_URL
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: MULTIPLY_FUNCTION_URL
            body:
                input: ${randomgen_result.body.random}
        result: multiply_result
    - return_result:
        return: ${multiply_result}
    

    Questo file di origine collega le due funzioni HTTP e restituisce un risultato finale.

  3. Dopo aver creato il flusso di lavoro, puoi eseguirne il deployment, rendendolo pronto per l'esecuzione.

    gcloud workflows deploy WORKFLOW_NAME \
        --source=workflow.yaml \
        --service-account=${SERVICE_ACCOUNT}@PROJECT_ID.

    Sostituisci WORKFLOW_NAME con un nome per il flusso di lavoro.

  4. Esegui il workflow:

    gcloud workflows run WORKFLOW_NAME

    Un'esecuzione è una singola esecuzione della logica contenuta nella definizione di un workflow. Tutte le esecuzioni del flusso di lavoro sono indipendenti e la scalabilità rapida di Workflows consente un numero elevato di esecuzioni simultanee.

    Dopo l'esecuzione del flusso di lavoro, l'output dovrebbe essere simile al seguente:

    result: '{"body":{"multiplied":120},"code":200,"headers":{"Alt-Svc":"h3-29=\":443\";
    ...
    startTime: '2021-05-05T14:17:39.135251700Z'
    state: SUCCEEDED
    ...
    

Connettere un servizio REST pubblico nel flusso di lavoro

Aggiorna il flusso di lavoro esistente e connetti un'API REST pubblica (math.js) che può valutare espressioni matematiche. Ad esempio, curl https://api.mathjs.org/v4/?'expr=log(56)'.

Tieni presente che, dopo aver eseguito il deployment del workflow, puoi modificarlo anche tramite la pagina Workflows della Google Cloud console.

  1. Modifica il file di origine del workflow e sostituiscilo con i seguenti contenuti:

    - randomgen_function:
        call: http.get
        args:
            url: RANDOMGEN_FUNCTION_URL
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: MULTIPLY_FUNCTION_URL
            body:
                input: ${randomgen_result.body.random}
        result: multiply_result
    - log_function:
        call: http.get
        args:
            url: https://api.mathjs.org/v4/
            query:
                expr: ${"log(" + string(multiply_result.body.multiplied) + ")"}
        result: log_result
    - return_result:
        return: ${log_result}
    

    In questo modo, il servizio REST esterno viene collegato alle funzioni Cloud Run e viene restituito un risultato finale.

  2. Esegui il deployment del workflow modificato:

    gcloud workflows deploy WORKFLOW_NAME \
        --source=workflow.yaml \
        --service-account=${SERVICE_ACCOUNT}@PROJECT_ID.

Esegui il deployment di un servizio Cloud Run

Esegui il deployment di un servizio Cloud Run che, dopo aver ricevuto una richiesta HTTP, estrae input dal corpo JSON, ne calcola math.floor e restituisce il risultato.

  1. Crea una directory denominata floor e passa a questa directory:

    mkdir ~/floor
    cd ~/floor
  2. Crea un file di testo con il nome file app.py contenente il seguente codice Python:

    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)))

  3. Nella stessa directory, crea un file Dockerfile con il seguente contenuto:

    # 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

  4. Crea un repository standard di Artifact Registry in cui puoi archiviare la tua immagine container Docker:

    gcloud artifacts repositories create REPOSITORY \
        --repository-format=docker \
        --location=${REGION}

    Sostituisci REPOSITORY con un nome univoco per il repository.

  5. Crea l'immagine container:

    export SERVICE_NAME=floor
    gcloud builds submit --tag ${REGION}-docker.pkg.dev/PROJECT_ID/REPOSITORY/${SERVICE_NAME}
  6. Esegui il deployment dell'immagine container in Cloud Run, assicurandoti che accetti solo chiamate autenticate:

    gcloud run deploy ${SERVICE_NAME} \
        --image ${REGION}-docker.pkg.dev/PROJECT_ID/REPOSITORY/${SERVICE_NAME}:latest \
        --no-allow-unauthenticated

Quando vedi l'URL del servizio, il deployment è completato. Dovrai specificare questo URL quando aggiorni la definizione del workflow.

Connetti il servizio Cloud Run nel flusso di lavoro

Aggiorna il flusso di lavoro esistente e specifica l'URL del servizio Cloud Run.

  1. Torna alla tua home directory:

    cd ~
  2. Modifica il file di origine del workflow e sostituiscilo con i seguenti contenuti:

    - randomgen_function:
        call: http.get
        args:
            url: RANDOMGEN_FUNCTION_URL
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: MULTIPLY_FUNCTION_URL
            body:
                input: ${randomgen_result.body.random}
        result: multiply_result
    - log_function:
        call: http.get
        args:
            url: https://api.mathjs.org/v4/
            query:
                expr: ${"log(" + string(multiply_result.body.multiplied) + ")"}
        result: log_result
    - floor_function:
        call: http.post
        args:
            url: CLOUD_RUN_SERVICE_URL
            auth:
                type: OIDC
            body:
                input: ${log_result.body}
        result: floor_result
    - create_output_map:
        assign:
          - outputMap:
              randomResult: ${randomgen_result}
              multiplyResult: ${multiply_result}
              logResult: ${log_result}
              floorResult: ${floor_result}
    - return_output:
        return: ${outputMap}
    
    • Sostituisci RANDOMGEN_FUNCTION_URL con l'URL della tua funzione randomgen.
    • Sostituisci MULTIPLY_FUNCTION_URL con l'URL della tua funzione multiply.
    • Sostituisci CLOUD_RUN_SERVICE_URL con l'URL del servizio Cloud Run.

    In questo modo viene collegato il servizio Cloud Run nel flusso di lavoro. Tieni presente che la chiave auth garantisce che un token di autenticazione venga trasmesso nella chiamata al servizio Cloud Run. Per saperne di più, consulta Effettuare richieste autenticate da un flusso di lavoro.

  3. Esegui il deployment del workflow modificato:

    gcloud workflows deploy WORKFLOW_NAME \
        --source=workflow.yaml \
        --service-account=${SERVICE_ACCOUNT}@PROJECT_ID.
  4. Esegui il workflow finale:

    gcloud workflows run WORKFLOW_NAME

    L'output dovrebbe essere simile al seguente:

    result: '{"floorResult":{"body":"4","code":200
      ...
      "logResult":{"body":"4.02535169073515","code":200
      ...
      "multiplyResult":{"body":{"multiplied":56},"code":200
      ...
      "randomResult":{"body":{"random":28},"code":200
      ...
    startTime: '2023-11-13T21:22:56.782669001Z'
    state: SUCCEEDED
    

Complimenti! Hai eseguito il deployment e l'esecuzione di un flusso di lavoro che connette una serie di servizi.

Per creare workflow più complessi utilizzando espressioni, salti condizionali, codifica o decodifica Base64, subworkflow e altro ancora, consulta i riferimenti alla sintassi di Workflows e la panoramica della libreria standard.