Tutorial de workflows (1.ª geração)

Este tutorial mostra como usar fluxos de trabalho para associar uma série de serviços. Ao ligar dois serviços HTTP públicos (através de funções do Cloud Run), uma API REST externa e um serviço privado do Cloud Run, pode criar uma aplicação flexível e sem servidor.

Implemente o primeiro serviço de funções do Cloud Run

Após receber um pedido HTTP, esta função HTTP gera um número aleatório entre 1 e 100 e, em seguida, devolve o número no formato JSON.

  1. Crie um diretório denominado randomgen e altere para o mesmo:

    mkdir ~/randomgen
    cd ~/randomgen
  2. Crie um ficheiro de texto com o nome main.py que contenha o seguinte código 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. Para suportar uma dependência do Flask para o processamento HTTP, crie um ficheiro de texto para o gestor de pacotes pip. Atribua-lhe o nome de ficheiro requirements.txt e adicione o seguinte:

    flask>=1.0.2
    functions-framework==3.0.0
  4. Implemente a função com um acionador HTTP e permita o acesso não autenticado:

    gcloud functions deploy randomgen \
        --runtime python37 \
        --trigger-http \
        --allow-unauthenticated

A implementação da função pode demorar alguns minutos. Em alternativa, pode usar a interface de funções do Cloud Run na Google Cloud consola para implementar a função.

  1. Depois de implementar a função, pode confirmar a propriedade httpsTrigger.url:

    gcloud functions describe randomgen
  2. Pode experimentar a função com o seguinte comando curl:

    curl $(gcloud functions describe randomgen --format='value(httpsTrigger.url)')

    É gerado e devolvido um número aleatório.

Implemente o segundo serviço de funções do Cloud Run

Após receber um pedido HTTP, esta função HTTP extrai o input do corpo JSON, multiplica-o por 2 e devolve o resultado no formato JSON.

  1. Crie um diretório denominado multiply e altere para o mesmo:

    mkdir ~/multiply
    cd ~/multiply
  2. Crie um ficheiro de texto com o nome main.py que contenha o seguinte código 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)
  3. Para suportar uma dependência do Flask para o processamento HTTP, crie um ficheiro de texto para o gestor de pacotes pip. Atribua-lhe o nome de ficheiro requirements.txt e adicione o seguinte:

    flask>=1.0.2
    functions-framework==3.0.0
  4. Implemente a função com um acionador HTTP e permita o acesso não autenticado:

    gcloud functions deploy multiply \
        --runtime python37 \
        --trigger-http \
        --allow-unauthenticated

A implementação da função pode demorar alguns minutos.Em alternativa, pode usar a interface de funções do Cloud Run na Google Cloud consola para implementar a função.

  1. Depois de implementar a função, pode confirmar a propriedade httpsTrigger.url:

    gcloud functions describe multiply
  2. Pode experimentar a função com o seguinte comando curl:

    curl $(gcloud functions describe multiply --format='value(httpsTrigger.url)') \
        -X POST \
        -H "content-type: application/json" \
        -d '{"input": 5}'

    Deve ser devolvido o número 10.

Associe os dois serviços de funções do Cloud Run num fluxo de trabalho

Um fluxo de trabalho é composto por uma série de passos descritos através da sintaxe Workflows, que pode ser escrita no formato YAML ou JSON. Esta é a definição do fluxo de trabalho. Para uma explicação detalhada, consulte a página Referência de sintaxe.

  1. Navegue de volta para o diretório inicial:

    cd ~
  2. Crie um ficheiro de texto com o nome de ficheiro workflow.yaml que contenha o seguinte conteúdo:

    - randomgen_function:
        call: http.get
        args:
            url: https://REGION-PROJECT_ID.cloudfunctions.net/randomgen
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: https://REGION-PROJECT_ID.cloudfunctions.net/multiply
            body:
                input: ${randomgen_result.body.random}
        result: multiply_result
    - return_result:
        return: ${multiply_result}
    

    Isto associa as duas funções HTTP e devolve um resultado final.

  3. Depois de criar o fluxo de trabalho, pode implementá-lo, o que o torna pronto para execução.

    gcloud workflows deploy WORKFLOW_NAME --source=workflow.yaml

    Substitua WORKFLOW_NAME por um nome para o fluxo de trabalho.

  4. Execute o fluxo de trabalho:

    gcloud workflows run WORKFLOW_NAME

    Uma execução é uma única execução da lógica contida na definição de um fluxo de trabalho. Todas as execuções de fluxos de trabalho são independentes e o dimensionamento rápido dos fluxos de trabalho permite um elevado número de execuções simultâneas.

    Após a execução do fluxo de trabalho, o resultado deve ser semelhante ao seguinte:

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

Associe um serviço REST público no fluxo de trabalho

Atualize o seu fluxo de trabalho existente e associe uma API REST pública (math.js) que possa avaliar expressões matemáticas. Por exemplo, curl https://api.mathjs.org/v4/?'expr=log(56)'.

Tenha em atenção que, uma vez que implementou o fluxo de trabalho, também o pode editar através da página Fluxos de trabalho na Google Cloud consola.

  1. Edite o ficheiro de origem do fluxo de trabalho e substitua-o pelo seguinte conteúdo:

    - randomgen_function:
        call: http.get
        args:
            url: https://REGION-PROJECT_ID.cloudfunctions.net/randomgen
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: https://REGION-PROJECT_ID.cloudfunctions.net/multiply
            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}
    

    Isto associa o serviço REST externo aos serviços de funções do Cloud Run e devolve um resultado final.

  2. Implemente o fluxo de trabalho modificado:

    gcloud workflows deploy WORKFLOW_NAME --source=workflow.yaml

Implemente um serviço do Cloud Run

Implemente um serviço do Cloud Run que, após receber um pedido HTTP, extraia input do corpo JSON, calcule o respetivo math.floor e devolva o resultado.

  1. Crie um diretório denominado floor e altere para o mesmo:

    mkdir ~/floor
    cd ~/floor
  2. Crie um ficheiro de texto com o nome app.py que contenha o seguinte código 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. No mesmo diretório, crie um ficheiro Dockerfile com o seguinte conteúdo:

    # 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. Crie um repositório padrão do Artifact Registry onde pode armazenar a sua imagem de contentor Docker:

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

    Substitua REPOSITORY por um nome exclusivo para o repositório.

  5. Crie a imagem de contentor:

    export SERVICE_NAME=floor
    gcloud builds submit --tag ${REGION}-docker.pkg.dev/PROJECT_ID/REPOSITORY/${SERVICE_NAME}
  6. Implemente a imagem do contentor no Cloud Run, garantindo que apenas aceita chamadas autenticadas:

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

Quando vir o URL do serviço, a implementação está concluída. Tem de especificar esse URL quando atualizar a definição do fluxo de trabalho.

Associe o serviço do Cloud Run no fluxo de trabalho

Atualize o fluxo de trabalho existente e especifique o URL do serviço do Cloud Run.

  1. Edite o ficheiro de origem do fluxo de trabalho e substitua-o pelo seguinte conteúdo:

    - randomgen_function:
        call: http.get
        args:
            url: https://REGION-PROJECT_ID.cloudfunctions.net/randomgen
        result: randomgen_result
    - multiply_function:
        call: http.post
        args:
            url: https://REGION-PROJECT_ID.cloudfunctions.net/multiply
            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}
    

    Substitua CLOUD_RUN_SERVICE_URL pelo URL do serviço do Cloud Run.

    Isto associa o serviço do Cloud Run no fluxo de trabalho. Tenha em atenção que a chave auth garante que um símbolo de autenticação está a ser transmitido na chamada ao serviço do Cloud Run. Para mais informações, consulte o artigo Faça pedidos autenticados a partir de um fluxo de trabalho.

  2. Implemente o fluxo de trabalho modificado:

    gcloud workflows deploy WORKFLOW_NAME \
        --source=workflow.yaml
  3. Execute o fluxo de trabalho final:

    gcloud workflows run WORKFLOW_NAME

    O resultado deve ser semelhante ao seguinte:

    result: '{"Floor":{"body":"4","code":200
      ...
      "Log":{"body":"4.02535169073515","code":200
      ...
      "Multiply":{"body":{"multiplied":56},"code":200
      ...
      "Random":{"body":{"random":28},"code":200
      ...
    startTime: '2023-11-13T21:22:56.782669001Z'
    state: SUCCEEDED
    

Parabéns! Implementou e executou um fluxo de trabalho que associa uma série de serviços.

Para criar fluxos de trabalho mais complexos com expressões, saltos condicionais, codificação ou descodificação Base64, subfluxos de trabalho e muito mais, consulte a referência da sintaxe dos fluxos de trabalho e a vista geral da biblioteca padrão.