1. Introdução
É possível usar fluxos de trabalho para criar fluxos de trabalho sem servidor que vinculam uma série de tarefas sem servidor na ordem que você definir. É possível combinar o poder das APIs do Google Cloud, produtos sem servidor, como o Cloud Functions e o Cloud Run, e chamadas para APIs externas para criar aplicativos flexíveis sem servidor.
Os fluxos de trabalho não exigem gerenciamento de infraestrutura e são escalonados perfeitamente de acordo com a demanda, incluindo redução da escala a zero. Com o modelo de preços de pagamento por uso, você paga apenas pelo tempo de execução.
Neste codelab, você vai aprender a conectar vários serviços do Google Cloud e APIs HTTP externas com o Workflows. Mais especificamente, você vai conectar dois serviços públicos do Cloud Functions, um serviço particular do Cloud Run e uma API HTTP pública externa a um fluxo de trabalho.
O que você vai aprender
- Noções básicas do Workflows.
- Como conectar o Cloud Functions público com o Workflows.
- Como conectar serviços particulares do Cloud Run com o Workflows.
- Como conectar APIs HTTP externas ao Workflows.
2. Configuração e requisitos
Configuração de ambiente autoguiada
- Faça login no Console do Cloud e crie um novo projeto ou reutilize um existente. Crie uma se você ainda não tiver uma conta do Gmail ou do G Suite.
Lembre-se do código do projeto, um nome exclusivo em todos os projetos do Google Cloud. O nome acima já foi escolhido e não servirá para você. Faremos referência a ele mais adiante neste codelab como PROJECT_ID
.
- Em seguida, será necessário ativar o faturamento no Console do Cloud para usar os recursos do Google Cloud.
A execução deste codelab não será muito cara, se for o caso. Siga todas as instruções na seção "Limpeza", que orienta você sobre como encerrar recursos para não incorrer em cobranças além deste tutorial. Novos usuários do Google Cloud estão qualificados para o programa de avaliação gratuita de US$ 300.
Inicie o Cloud Shell
Embora o Google Cloud e o Spanner possam ser operados remotamente do seu laptop, neste codelab usaremos o Google Cloud Shell, um ambiente de linha de comando executado no Cloud.
No Console do GCP, clique no ícone do Cloud Shell na barra de ferramentas localizada no canto superior direito:
O provisionamento e a conexão com o ambiente levarão apenas alguns instantes para serem concluídos: Quando o processamento for concluído, você verá algo como:
Essa máquina virtual contém todas as ferramentas de desenvolvimento necessárias. Ela oferece um diretório principal persistente de 5 GB, além de ser executada no Google Cloud. Isso aprimora o desempenho e a autenticação da rede. Todo o trabalho neste laboratório pode ser feito apenas com um navegador.
3. Visão geral dos fluxos de trabalho
Noções básicas
Um fluxo de trabalho é composto por uma série de etapas descritas usando a sintaxe baseada em YAML do Workflows. Essa é a definição do fluxo de trabalho. Para uma explicação detalhada sobre a sintaxe YAML do Workflows, consulte a página Referência de sintaxe.
Quando um fluxo de trabalho é criado, ele é implantado e fica pronto para execução. Uma execução é uma única execução da lógica contida na definição de um fluxo de trabalho. Todas as execuções do fluxo de trabalho são independentes, e o produto aceita um alto número de execuções simultâneas.
Ativar serviços
Neste codelab, você vai conectar os serviços do Cloud Functions e do Cloud Run com o Workflows. Você também vai usar o Cloud Build e o Cloud Storage durante a criação de serviços.
Ative todos os serviços necessários:
gcloud services enable \ cloudfunctions.googleapis.com \ run.googleapis.com \ workflows.googleapis.com \ cloudbuild.googleapis.com \ storage.googleapis.com
Na próxima etapa, você vai conectar duas funções do Cloud em um fluxo de trabalho.
4. Implantar a primeira função do Cloud
A primeira função é um gerador de números aleatórios em Python.
Crie e navegue até um diretório para o código da função:
mkdir ~/randomgen cd ~/randomgen
Crie um arquivo main.py
no diretório com o seguinte conteúdo:
import random, json from flask import jsonify def randomgen(request): randomNum = random.randint(1,100) output = {"random":randomNum} return jsonify(output)
Quando recebe uma solicitação HTTP, essa função gera um número aleatório entre 1 e 100 e retorna no formato JSON de volta ao autor da chamada.
A função depende do Flask para o processamento HTTP, e precisamos adicionar isso como uma dependência. Dependências no Python são gerenciadas com pip e expressas em um arquivo de metadados chamado requirements.txt
.
Crie um arquivo requirements.txt
no mesmo diretório com o seguinte conteúdo:
flask>=1.0.2
Implante a função com um gatilho HTTP e com solicitações não autenticadas permitidas com este comando:
gcloud functions deploy randomgen \ --runtime python37 \ --trigger-http \ --allow-unauthenticated
Depois que a função for implantada, você verá o URL dela na propriedade httpsTrigger.url
exibida no console ou com o comando gcloud functions describe
.
Você também pode acessar esse URL da função com o seguinte comando curl
:
curl $(gcloud functions describe randomgen --format='value(httpsTrigger.url)')
A função está pronta para o fluxo de trabalho.
5. Implantar a segunda função do Cloud
A segunda função é um multiplicador. Ela multiplica a entrada recebida por 2.
Crie e navegue até um diretório para o código da função:
mkdir ~/multiply cd ~/multiply
Crie um arquivo main.py
no diretório com o seguinte conteúdo:
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 recebe uma solicitação HTTP, essa função extrai o input
do corpo JSON, o multiplica por 2 e retorna no formato JSON de volta para o autor da chamada.
Crie o mesmo arquivo requirements.txt
no mesmo diretório com o seguinte conteúdo:
flask>=1.0.2
Implante a função com um gatilho HTTP e com solicitações não autenticadas permitidas com este comando:
gcloud functions deploy multiply \ --runtime python37 \ --trigger-http \ --allow-unauthenticated
Depois que a função for implantada, também será possível acessar esse URL da 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}'
A função está pronta para o fluxo de trabalho.
6. Conecte duas funções do Cloud
No primeiro fluxo de trabalho, conecte as duas funções.
Crie um arquivo workflow.yaml
com o seguinte conteúdo.
- 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}
Neste fluxo de trabalho, você recebe um número aleatório da primeira função e o transmite para a segunda função. O resultado é o número aleatório multiplicado.
Implante o primeiro fluxo de trabalho:
gcloud workflows deploy workflow --source=workflow.yaml
Execute o primeiro fluxo de trabalho:
gcloud workflows execute workflow
Depois que o fluxo de trabalho é executado, você pode ver o resultado ao transmitir o ID da execução fornecido na etapa anterior:
gcloud workflows executions describe <your-execution-id> --workflow workflow
A saída vai incluir result
e state
:
result: '{"body":{"multiplied":108},"code":200 ... } ... state: SUCCEEDED
7. Conectar uma API HTTP externa
Em seguida, conecte math.js como um serviço externo no fluxo de trabalho.
No math.js, é possível avaliar expressões matemáticas como estas:
curl https://api.mathjs.org/v4/?'expr=log(56)'
Desta vez, você vai usar o console do Cloud para atualizar nosso fluxo de trabalho. Encontre Workflows
no Console do Google Cloud:
Encontre seu fluxo de trabalho e clique na guia Definition
:
Edite a definição do fluxo de trabalho e inclua uma chamada para 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}
O fluxo de trabalho agora alimenta a saída da função de multiplicação em uma chamada de função de registro em math.js
.
A interface vai guiar você para editar e implantar o fluxo de trabalho. Depois de implantado, clique em Execute
para executar o fluxo de trabalho. Você verá os detalhes da execução:
Observe o código de status 200
e um body
com a saída da função de registro.
Você integrou um serviço externo ao nosso fluxo de trabalho. Muito legal!
8. Implantar um serviço do Cloud Run
Na última parte, finalize o fluxo de trabalho com uma chamada para um serviço particular do Cloud Run. Isso significa que o fluxo de trabalho precisa ser autenticado para chamar o serviço do Cloud Run.
O serviço do Cloud Run retorna o math.floor
do número transmitido.
Crie e navegue até um diretório para o código de serviço:
mkdir ~/floor cd ~/floor
Crie um arquivo app.py
no diretório com o seguinte conteúdo:
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)))
Como o Cloud Run implanta contêineres, você precisa de um Dockerfile
, e o contêiner precisa se vincular às variáveis de ambiente 0.0.0.0
e PORT
. Por isso, o código acima é usado.
Quando recebe uma solicitação HTTP, essa função extrai o input
do corpo JSON, chama math.floor e retorna o resultado para o autor da chamada.
No mesmo diretório, crie o seguinte 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
Criar o contêiner:
export SERVICE_NAME=floor gcloud builds submit --tag gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME}
Depois que o contêiner for criado, implante no Cloud Run. Observe a sinalização no-allow-unauthenticated
. Isso garante que o serviço aceite apenas chamadas autenticadas:
gcloud run deploy ${SERVICE_NAME} \ --image gcr.io/${GOOGLE_CLOUD_PROJECT}/${SERVICE_NAME} \ --platform managed \ --no-allow-unauthenticated
Depois de implantado, o serviço estará pronto para o fluxo de trabalho.
9. Conectar o serviço do Cloud Run
Antes de configurar o Workflows para chamar o serviço particular do Cloud Run, você precisa criar uma conta de serviço para o Workflows:
export SERVICE_ACCOUNT=workflows-sa gcloud iam service-accounts create ${SERVICE_ACCOUNT}
Conceda o papel run.invoker
à conta de serviço. Assim, a conta de serviço poderá chamar os serviços autenticados do Cloud Run:
gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member "serviceAccount:${SERVICE_ACCOUNT}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com" \ --role "roles/run.invoker"
Atualize a definição do fluxo de trabalho em workflow.yaml
para incluir o serviço do Cloud Run. Observe como você também está incluindo o campo auth
para garantir que os fluxos de trabalho transmitam o token de autenticação nas chamadas para o serviço do 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}
Atualizar o fluxo de trabalho. Desta vez, passando a conta de serviço:
gcloud workflows deploy workflow \ --source=workflow.yaml \ --service-account=${SERVICE_ACCOUNT}@${GOOGLE_CLOUD_PROJECT}.iam.gserviceaccount.com
Execute o fluxo de trabalho:
gcloud workflows execute workflow
Em alguns segundos, confira o resultado da execução do fluxo de trabalho:
gcloud workflows executions describe <your-execution-id> --workflow workflow
A saída vai incluir um número inteiro result
e state
:
result: '{"body":"5","code":200 ... } ... state: SUCCEEDED
10. Parabéns!
Parabéns por concluir o codelab.
O que vimos
- Noções básicas do Workflows.
- Como conectar o Cloud Functions público com o Workflows.
- Como conectar serviços particulares do Cloud Run com o Workflows.
- Como conectar APIs HTTP externas ao Workflows.