Tutorial sobre como usar o Workflows com o Cloud Run e o Cloud Run functions


Neste tutorial, você aprende a usar fluxos de trabalho para vincular uma série de serviços. Ao conectar dois serviços HTTP públicos usando funções do Cloud Run, uma API REST externa e um serviço particular do Cloud Run, é possível criar um aplicativo flexível e sem servidor.

Objetivos

Neste tutorial, você vai usar a Google Cloud CLI para criar um único fluxo de trabalho, conectando um serviço por vez:

  1. Implantar duas funções do Cloud Run: a primeira função gera um número aleatório e, em seguida, transmite esse número para a segunda função, que o multiplica.
  2. Usando fluxos de trabalho, conecte as duas funções HTTP juntas. Execute o fluxo de trabalho e retorne um resultado que será transmitido para uma API externa.
  3. Usando o Workflows, conecte uma API HTTP externa que retorne o log para um determinado número. Execute o fluxo de trabalho e retorne um resultado que é passado para um serviço do Cloud Run.
  4. Implantar um serviço do Cloud Run que permita apenas o acesso autenticado. O serviço retorna math.floor para um determinado número.
  5. Usando o Workflows, conecte o serviço do Cloud Run, execute todo o fluxo de trabalho e retorne um resultado final.

O diagrama a seguir mostra uma visão geral do processo e uma visualização do fluxo de trabalho final:

Visualização dos fluxos de trabalho

Custos

Neste documento, você usará os seguintes componentes faturáveis do Google Cloud:

Para gerar uma estimativa de custo baseada na projeção de uso deste tutorial, use a calculadora de preços. Novos usuários do Google Cloud podem estar qualificados para uma avaliação gratuita.

Antes de começar

As restrições de segurança definidas pela sua organização podem impedir que você conclua as etapas a seguir. Para informações sobre solução de problemas, consulte Desenvolver aplicativos em um ambiente restrito do Google Cloud.

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.
  3. To initialize the gcloud CLI, run the following command:

    gcloud init
  4. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  5. Make sure that billing is enabled for your Google Cloud project.

  6. Enable the Artifact Registry, Cloud Build, Cloud Run, Cloud Run functions, Cloud Storage, and Workflows APIs:

    gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com cloudfunctions.googleapis.com storage.googleapis.com workflows.googleapis.com
  7. Install the Google Cloud CLI.
  8. To initialize the gcloud CLI, run the following command:

    gcloud init
  9. Create or select a Google Cloud project.

    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  10. Make sure that billing is enabled for your Google Cloud project.

  11. Enable the Artifact Registry, Cloud Build, Cloud Run, Cloud Run functions, Cloud Storage, and Workflows APIs:

    gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com cloudfunctions.googleapis.com storage.googleapis.com workflows.googleapis.com
  12. Atualize os componentes da Google Cloud CLI:
    gcloud components update
  13. Ao executar comandos no Cloud Shell, você já está autenticado na gcloud CLI. Caso contrário, faça login usando sua conta:
    gcloud auth login
  14. Defina o local padrão usado neste tutorial:
    gcloud config set project PROJECT_ID
    export REGION=REGION
    gcloud config set functions/region ${REGION}
    gcloud config set run/region ${REGION}
    gcloud config set workflows/location ${REGION}

    Substitua REGION pelo local do Workflows compatível de sua escolha.

  15. Se você for o criador do projeto, receberá o papel de proprietário básico (roles/owner). Por padrão, esse papel do gerenciamento de identidade e acesso (IAM) inclui as permissões necessárias para acesso total à maioria dos recursos do Google Cloud, e você pode pular esta etapa.

    Se você não é o criador do projeto, as permissões necessárias precisam ser concedidas ao principal apropriado. Por exemplo, um principal pode ser uma Conta do Google (para usuários finais) ou uma conta de serviço (para aplicativos e cargas de trabalho de computação). Para mais informações, consulte a página Papéis e permissões do destino do evento.

    Permissões necessárias

    Para conseguir as permissões necessárias para concluir o tutorial, peça ao administrador para conceder a você os seguintes papéis do IAM no seu projeto:

    Para mais informações sobre a concessão de papéis, consulte Gerenciar o acesso a projetos, pastas e organizações.

    Também é possível conseguir as permissões necessárias por meio de papéis personalizados ou de outros papéis predefinidos.

  16. Ao implantar o fluxo de trabalho, você o associa a uma conta de serviço especificada. Crie uma conta de serviço para os fluxos de trabalho usarem:
    export SERVICE_ACCOUNT=workflows-sa
    gcloud iam service-accounts create ${SERVICE_ACCOUNT}
  17. Todos os serviços do Cloud Run são implantados de forma privada por padrão e só podem ser chamados por proprietários do projeto, editores do projeto, administradores do Cloud Run e invocadores do Cloud Run. Para permitir que a conta de serviço chame um serviço do Cloud Run autenticado, conceda o papel run.invoker à conta de serviço Workflows:
    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member "serviceAccount:${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com" \
        --role "roles/run.invoker"

Implantar as primeiras funções do Cloud Run

Depois de receber uma solicitação HTTP, essa função HTTP gera um número aleatório entre 1 e 100 e, em seguida, retorna o número no formato JSON.

  1. Crie um diretório chamado randomgen e mude para ele:

    mkdir ~/randomgen
    cd ~/randomgen
  2. Crie um arquivo de texto com o nome de arquivo 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 aceitar uma dependência do Flask para processamento HTTP, crie um arquivo de texto para o gerenciador de pacotes pip. Nomeie o arquivo como requirements.txt e adicione o seguinte:

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

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

    A função pode levar alguns minutos para ser implantada. Se preferir, use a interface de funções do Cloud Run no Console do Google Cloud para implantar a função.

  5. Depois que a função randomgen for implantada, confirme a propriedade httpsTrigger.url:

    gcloud functions describe randomgen-function \
        --gen2 \
        --format="value(serviceConfig.uri)"
  6. Salve o URL. É necessário adicioná-lo ao arquivo de origem do fluxo de trabalho em exercícios posteriores.

  7. Teste a função com o seguinte comando curl:

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

    Um número é gerado e retornado aleatoriamente.

Implantar as segundas funções do Cloud Run

Depois de receber uma solicitação HTTP, essa função HTTP extrai o input do corpo JSON, multiplica-o por dois e retorna o resultado no formato JSON.

  1. Volte ao diretório principal.

    cd ~
  2. Crie um diretório chamado multiply e mude para ele:

    mkdir ~/multiply
    cd ~/multiply
  3. Crie um arquivo de texto com o nome de arquivo 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)
  4. Para aceitar uma dependência do Flask para processamento HTTP, crie um arquivo de texto para o gerenciador de pacotes pip. Nomeie o arquivo como requirements.txt e adicione o seguinte:

    flask>=1.0.2
    functions-framework==3.0.0
  5. Implante a função com um gatilho HTTP e permita acesso não autenticado:

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

    A função pode levar alguns minutos para ser implantada. Se preferir, use a interface de funções do Cloud Run no Console do Google Cloud para implantar a função.

  6. Depois que a função multiply for implantada, confirme a propriedade httpsTrigger.url:

    gcloud functions describe multiply-function \
        --gen2\
        --format="value(serviceConfig.uri)"
  7. Salve o URL. É necessário adicioná-lo ao arquivo de origem do fluxo de trabalho em exercícios posteriores.

  8. Teste a função com o seguinte comando curl:

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

    O número 10 deve ser retornado.

Conectar as duas funções do Cloud Run em um fluxo de trabalho

Um fluxo de trabalho é composto por uma série de etapas descritas usando a sintaxe dos fluxos de trabalho, que pode ser escrita em formato YAML ou JSON. Essa é a definição do fluxo de trabalho. Para uma explicação detalhada, consulte a página Referência de sintaxe.

  1. Volte ao diretório principal.

    cd ~
  2. Crie um arquivo de texto com o nome workflow.yaml que contenha o conteúdo a seguir:

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

    Esse arquivo de origem vincula as duas funções HTTP e retorna um resultado final.

  3. Depois de criar o fluxo de trabalho, é possível implantá-lo, o que o prepara para a execução.

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

    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 fluxo de trabalho são independentes, e o rápido escalonamento do Workflows permite um grande número de execuções simultâneas.

    Depois que o fluxo de trabalho for executado, o resultado será semelhante a este:

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

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

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

Como você implantou seu fluxo de trabalho, também pode editá-lo na página "Fluxos de trabalho" no console do Google Cloud.

  1. Edite o arquivo de origem do fluxo de trabalho e substitua-o pelo conteúdo a seguir:

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

    Isso vincula o serviço REST externo às funções do Cloud Run e retorna um resultado final.

  2. Implante o fluxo de trabalho modificado:

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

Implantar um serviço do Cloud Run

Implantar um serviço do Cloud Run que, depois de receber uma solicitação HTTP, extrai input do corpo JSON, calcula o math.floor e retorna o resultado.

  1. Crie um diretório chamado floor e mude para ele:

    mkdir ~/floor
    cd ~/floor
  2. Crie um arquivo de texto com o nome de arquivo 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 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 para armazenar a imagem do contêiner do 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 do contêiner:

    export SERVICE_NAME=floor
    gcloud builds submit --tag ${REGION}-docker.pkg.dev/PROJECT_ID/REPOSITORY/${SERVICE_NAME}
  6. Implante a imagem do contêiner no Cloud Run, garantindo que ele aceite apenas chamadas autenticadas:

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

Quando você vir o URL do serviço, a implantação estará concluída. Você precisará especificar esse URL ao atualizar a definição do fluxo de trabalho.

Conectar o serviço Cloud Run no fluxo de trabalho

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

  1. Volte ao diretório principal.

    cd ~
  2. Edite o arquivo de origem do fluxo de trabalho e substitua-o pelo conteúdo a seguir:

    - 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}
    
    • Substitua RANDOMGEN_FUNCTION_URL pelo URL da função randomgen.
    • Substitua MULTIPLY_FUNCTION_URL pelo URL da função multiply.
    • Substitua CLOUD_RUN_SERVICE_URL pelo URL do serviço do Cloud Run.

    Isso conecta o serviço Cloud Run ao fluxo de trabalho. A chave auth garante que um token de autenticação seja transmitido na chamada ao serviço do Cloud Run. Para mais informações, consulte Fazer solicitações autenticadas de um fluxo de trabalho.

  3. Implante o fluxo de trabalho modificado:

    gcloud workflows deploy WORKFLOW_NAME \
        --source=workflow.yaml \
        --service-account=${SERVICE_ACCOUNT}@PROJECT_ID.iam.gserviceaccount.com
  4. Executar o fluxo de trabalho final:

    gcloud workflows run WORKFLOW_NAME

    A saída será semelhante a esta:

    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
    

Parabéns! Você implantou e executou um fluxo de trabalho que conecta uma série de serviços.

Para criar fluxos de trabalho mais complexos usando expressões, saltos condicionais, codificação/decodificação Base64, subfluxos de trabalho e muito mais, consulte a Referência de sintaxe dos fluxos de trabalho e a Visão geral da biblioteca padrão.

Limpar

Se você criou um novo projeto para este tutorial, exclua o projeto. Se você usou um projeto atual e quer mantê-lo sem as alterações incluídas neste tutorial, exclua os recursos criados para o tutorial.

Excluir o projeto

O jeito mais fácil de evitar cobranças é excluindo o projeto que você criou para o tutorial.

Para excluir o projeto:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

delete-tutorial-resources

A seguir