Consulte as práticas recomendadas listadas aqui ao orquestrar seus serviços usando o Workflows.
Esta não é uma lista completa de recomendações e não ensina o básico de como usar o Workflows. Este documento pressupõe que você já tenha uma compreensão geral do cenário e do Workflows. Google Cloud Para mais informações, consulte o Google Cloud Well-Architected Framework e a visão geral do Workflows.
Selecionar um padrão de comunicação ideal
Ao projetar uma arquitetura de microsserviços para implantar vários serviços, você pode selecionar um dos seguintes padrões de comunicação:
Comunicação direta entre serviços
Comunicação indireta orientada a eventos (também conhecida como coreografia)
Configuração, coordenação e gerenciamento automatizados (também conhecidos como orquestração)
Considere os benefícios e desvantagens de cada uma das opções anteriores e selecione um padrão ideal para seu caso de uso. Por exemplo, a comunicação direta entre serviços pode ser mais simples de implementar do que outras opções, mas ela acopla seus serviços. Em contraste, uma arquitetura orientada a eventos permite acoplar seus serviços de maneira flexível. No entanto, o monitoramento e a depuração podem ser mais complicados. Por fim, um orquestrador central como o Workflows, embora menos flexível, permite coordenar a comunicação entre serviços sem o acoplamento rígido da comunicação direta entre serviços ou a complexidade de eventos coreografados.
Também é possível combinar padrões de comunicação. Por exemplo, na orquestração orientada a eventos, os serviços relacionados são gerenciados em uma orquestração que é acionada por um evento. Da mesma forma, você pode projetar um sistema em que uma orquestração resulte em uma mensagem do Pub/Sub para outro sistema orquestrado.
Dicas gerais
Depois de decidir usar o Workflows como orquestrador de serviços, lembre-se das seguintes dicas úteis.
Evitar URLs fixados no código
É possível oferecer suporte a fluxos de trabalho portáteis em vários ambientes e mais fáceis de manter, evitando URLs fixados no código. Isso pode ser feito das seguintes maneiras:
Defina URLs como argumentos de execução.
Isso pode ser útil quando o fluxo de trabalho é invocado por uma biblioteca de cliente ou pela API. No entanto, isso não funciona se o fluxo de trabalho for acionado por um evento do Eventarc e o único argumento que pode ser transmitido for o payload do evento.
Exemplo
main: params: [args] steps: - init: assign: - url1: ${args.urls.url1} - url2: ${args.urls.url2}
Ao executar o fluxo de trabalho, é possível especificar os URLs. Por exemplo:
gcloud workflows run multi-env --data='{"urls":{"url1": "URL_ONE", "url2": "URL_TWO"}}'
Use variáveis de ambiente e crie um fluxo de trabalho configurado dinamicamente, dependendo do ambiente em que ele é implantado. Ou crie um fluxo de trabalho que possa ser reutilizado como um modelo e configurado de acordo com variáveis de ambiente mantidas separadamente.
Use uma técnica de substituição que permita criar um único arquivo de definição de fluxo de trabalho, mas implante variantes usando uma ferramenta que substitua marcadores no fluxo de trabalho. Por exemplo, é possível usar o Cloud Build para implantar um fluxo de trabalho e, no arquivo de configuração do Cloud Build, adicionar uma etapa para substituir URLs de marcador no fluxo de trabalho.
Exemplo
steps: ‐ id: 'replace-urls' name: 'gcr.io/cloud-builders/gcloud' entrypoint: bash args: - -c - | sed -i -e "s~REPLACE_url1~$_URL1~" workflow.yaml sed -i -e "s~REPLACE_url2~$_URL2~" workflow.yaml ‐ id: 'deploy-workflow' name: 'gcr.io/cloud-builders/gcloud' args: ['workflows', 'deploy', 'multi-env-$_ENV', '--source', 'workflow.yaml']
Em seguida, é possível substituir valores de variáveis no tempo de build. Por exemplo:
gcloud builds submit --config cloudbuild.yaml \ --substitutions=_ENV=staging,_URL1="URL_ONE",_URL2="URL_TWO"
Para mais informações, consulte Enviar uma build pela CLI e pela API.
Ou use o Terraform para provisionar sua infraestrutura e definir um arquivo de configuração que crie fluxos de trabalho para cada ambiente usando variáveis de entrada.
Exemplo
variable "project_id" { type = string } variable "url1" { type = string } variable "url2" { type = string } locals { env = ["staging", "prod"] } # Define and deploy staging and production workflows resource "google_workflows_workflow" "multi-env-workflows" { for_each = toset(local.env) name = "multi-env-${each.key}" project = var.project_id region = "us-central1" source_contents = templatefile("${path.module}/workflow.yaml", { url1 : "${var.url1}-${each.key}", url2 : "${var.url2}-${each.key}" }) }
Quando as variáveis são declaradas no módulo raiz da configuração, elas podem ser atribuídas valores de várias maneiras. Por exemplo:
terraform apply -var="project_id=PROJECT_ID" -var="url1=URL_ONE" -var="url2=URL_TWO"
Use o conector do Secret Manager para armazenar URLs com segurança no Secret Manager e recuperá-los.
Usar etapas aninhadas
Todo fluxo de trabalho precisa ter pelo menos uma etapa.
Por padrão, o Workflows trata as etapas como se estivessem em uma lista ordenada e as executa uma de cada vez até que todas sejam executadas. Logicamente, algumas etapas precisam ser agrupadas, e é possível usar um bloco steps para aninhar uma série de etapas. Isso é conveniente porque permite apontar para a etapa atômica correta para processar um conjunto de etapas.
Exemplo
main: params: [input] steps: - callWikipedia: steps: - checkSearchTermInInput: switch: - condition: ${"searchTerm" in input} assign: - searchTerm: ${input.searchTerm} next: readWikipedia - getCurrentDate: call: http.get args: url: https://timeapi.io/api/Time/current/zone?timeZone=Europe/Amsterdam result: currentDate - setFromCallResult: assign: - searchTerm: ${currentDate.body.dayOfWeek} - readWikipedia: call: http.get args: url: https://en.wikipedia.org/w/api.php query: action: opensearch search: ${searchTerm} result: wikiResult - returnOutput: return: ${wikiResult.body[1]}
Expressões de encapsulamento
Todas as expressões precisam começar com
um $ e estar entre chaves:
${EXPRESSION}Para evitar problemas de análise do YAML, é possível colocar expressões entre aspas. Por exemplo, expressões com dois-pontos podem causar um comportamento inesperado se os dois-pontos forem interpretados como a definição de um mapa. Para resolver esse problema, coloque a expressão YAML entre aspas simples:
'${"Name: " + myVar}'
Também é possível usar expressões que abrangem várias linhas. Por exemplo, talvez seja necessário colocar uma consulta SQL entre aspas ao usar o conector do Workflows BigQuery.
Exemplo
- runQuery: call: googleapis.bigquery.v2.jobs.query args: projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")} body: useLegacySql: false useQueryCache: false timeoutMs: 30000 # Find top 100 titles with most views on Wikipedia query: ${ "SELECT TITLE, SUM(views) FROM `bigquery-samples.wikipedia_pageviews." + table + "` WHERE LENGTH(TITLE) > 10 GROUP BY TITLE ORDER BY SUM(VIEWS) DESC LIMIT 100" } result: queryResult
Para a definição completa do fluxo de trabalho, consulte Executar vários jobs do BigQuery em paralelo.
Usar chamadas declarativas
Use o Workflows para chamar serviços do próprio fluxo de trabalho e processar os resultados, além de executar tarefas simples, como fazer uma chamada HTTP. O Workflows pode invocar serviços, analisar respostas e criar entradas para outros serviços conectados. Chamar um serviço permite evitar as complicações de invocações extras, dependências adicionais e serviços que chamam serviços. Considere substituir serviços que não têm lógica de negócios por chamadas de API declarativas e use o Workflows para abstrair a complexidade.
No entanto, é necessário criar serviços para fazer qualquer trabalho que seja muito complexo para o Workflows. Por exemplo, implementar lógica de negócios reutilizável, cálculos complexos ou transformações que não são compatíveis com expressões do Workflows e a biblioteca padrão. Um caso complicado geralmente é mais fácil de implementar no código, em vez de usar YAML ou JSON e a sintaxe do Workflows.
Armazenar apenas o que é necessário
Mantenha o consumo de memória sob controle para não encontrar
limites de recursos ou um erro que indique
isso, como ResourceLimitError, MemoryLimitExceededError, ou
ResultSizeLimitExceededError.
Seja seletivo sobre o que você armazena em variáveis, filtrando e armazenando apenas o que é necessário. Se um serviço retornar um payload muito grande, use uma função separada para fazer a chamada e retornar apenas o que é necessário.
É possível liberar memória limpando variáveis. Por exemplo, talvez você queira liberar memória necessária para etapas subsequentes. Ou você pode ter chamadas com resultados que não são importantes e pode omitir esses resultados.
É possível limpar uma variável atribuindo null. No YAML, também é possível atribuir um valor vazio ou ~ a uma variável. Isso identifica a memória que pode ser recuperada com segurança.
Exemplo
- step: assign: - bigVar:
Usar subfluxos de trabalho e fluxos de trabalho externos
É possível usar subfluxos de trabalho para definir uma parte da lógica ou um conjunto de etapas que você quer chamar várias vezes, simplificando a definição do fluxo de trabalho. Os subfluxos de trabalho são semelhantes a uma função ou rotina em uma linguagem de programação. Eles podem aceitar parâmetros e retornar valores, permitindo criar fluxos de trabalho mais complexos com uma variedade maior de aplicativos.
Os subfluxos de trabalho são locais para a definição do fluxo de trabalho e não podem ser reutilizados em outros fluxos de trabalho. No entanto, é possível chamar fluxos de trabalho de outros fluxos de trabalho. Os conectores do Workflows podem ajudar com isso. Para mais informações, consulte as visões gerais do conector para a API Workflow Executions e a API Workflows.
Usar conectores do Workflows
O Workflows oferece vários conectores que facilitam o acesso a outros Google Cloud produtos em um fluxo de trabalho. Os conectores simplificam os serviços de chamada porque processam a formatação das solicitações, fornecendo métodos e argumentos para que você não precise conhecer os detalhes de umaGoogle Cloud API. Os conectores também têm um comportamento integrado para processar novas tentativas e operações de longa duração para que você não precise evitar iterar e aguardar a conclusão das chamadas. Os conectores cuidam disso para você.
Se você precisar chamar uma Google Cloud API, primeiro verifique se existe um conector do Workflows para ela. E, se você não encontrar um conector para um Google Cloud produto, poderá solicitá-lo.
Saiba como usar um conector e, para uma referência detalhada dos conectores disponíveis, consulte a Referência de conectores.
Executar etapas do fluxo de trabalho em paralelo
Embora o Workflows possa executar etapas sequencialmente, também é possível executar etapas independentes em paralelo. Em alguns casos, isso pode acelerar significativamente a execução do fluxo de trabalho. Para mais informações, consulte Executar etapas do fluxo de trabalho em paralelo.
Aplicar novas tentativas e o padrão de saga
Projete fluxos de trabalho resilientes que possam lidar com falhas de serviço temporárias e permanentes. Os erros do Workflows podem ser gerados, por exemplo, por solicitações HTTP, funções, conectores ou pelo próprio código do fluxo de trabalho. Adicione tratamento de erros e novas tentativas para que uma falha em uma etapa não cause a falha de todo o fluxo de trabalho.
- É possível gerar erros personalizados
usando a sintaxe
raise. - É possível detectar erros usando
um
try/exceptbloco. - É possível tentar novamente as etapas usando um
try/retrybloco e definir o número máximo de tentativas.
Algumas transações comerciais abrangem vários serviços. Portanto, é necessário um mecanismo para implementar transações que abrangem serviços. O padrão de design de saga é uma maneira de gerenciar a consistência de dados em microsserviços em cenários de transação distribuída. Uma saga é uma sequência de transações que publica um evento para cada transação e que aciona a próxima transação. Se uma transação falhar, a saga executará transações de compensação que neutralizam as falhas anteriores na sequência. Teste o tutorial Novas tentativas e padrão de saga no Workflows no GitHub.
Usar callbacks para aguardar
Callbacks permitem que as execuções de fluxo de trabalho aguardem outro serviço para fazer uma solicitação ao endpoint de callback. Essa solicitação retoma a execução do fluxo de trabalho.
Com os callbacks, é possível sinalizar para o fluxo de trabalho que evento especificado ocorreu e aguardar esse evento sem a necessidade de pesquisa. Por exemplo, é possível criar um fluxo de trabalho que notifique quando um produto está em estoque novamente ou quando um item é enviado, ou que aguarde para permitir uma interação humana como revisar um pedido ou validar uma tradução. Também é possível aguardar eventos usando callbacks e gatilhos do Eventarc.
Orquestrar jobs de longa duração
Se você precisar executar cargas de trabalho de processamento em lote de longa duração, use o Batch ou os jobs do Cloud Run, e use o Workflows para gerenciar os serviços. Isso permite combinar vantagens e provisionar e orquestrar todo o processo com eficiência.
O Batch é um serviço totalmente gerenciado que permite programar, enfileirar e executar cargas de trabalho em lote em instâncias de máquina virtual (VM) do Compute Engine. É possível usar o conector do Workflows para o Batch para programar e executar um job em lote do Batch. Para mais detalhes, teste o tutorial.
Os jobs do Cloud Run são usados para executar códigos que executam tarefas (um job) e são encerrados quando o trabalho é concluído. O Workflows permite executar jobs do Cloud Run como parte de um fluxo de trabalho para realizar processamentos de dados mais complexos ou orquestrar um sistema de jobs atuais. Teste o tutorial que demonstra como usar o Workflows para executar um job do Cloud Run.
Colocar tarefas de longa duração em contêineres
É possível automatizar a execução de um contêiner de longa duração usando o Workflows e o Compute Engine. Por exemplo, é possível colocar uma tarefa de longa duração em contêineres para que ela possa ser executada em qualquer lugar e, em seguida, executar o contêiner em uma VM do Compute Engine pela duração máxima de uma execução de fluxo de trabalho (um ano).
Usando o Workflows, é possível automatizar a criação da VM, a execução do contêiner na VM e a exclusão da VM. Isso permite usar um servidor e executar um contêiner, mas abstrai a complexidade de gerenciar os dois e pode ser útil se você tiver limitações de tempo ao usar um serviço como as funções do Cloud Run ou o Cloud Run. Teste o tutorial Contêineres de longa duração com o Workflows e o Compute Engine no GitHub.
Executar ferramentas de linha de comando no Workflows
O Cloud Build é um serviço que executa suas builds como uma série de etapas de build, em que cada uma delas é executada em um contêiner do Docker. Google Cloud A execução de etapas de build é análoga à execução de comandos em um script.
A Google Cloud CLI inclui as ferramentas de linha de comando gcloud, bq, e
kubectl, mas não há uma maneira direta de executar comandos da CLI gcloud
no Workflows. No entanto, o Cloud Build fornece imagens de contêiner que incluem a CLI gcloud. É possível executar
comandos da CLI gcloud nesses contêineres em uma etapa do Cloud Build
e criar essa etapa no Workflows usando o
conector do Cloud Build.
Exemplo
Executar gcloud em um fluxo de trabalho:
Run kubectl in a workflow:
Usar o Terraform para criar o fluxo de trabalho
O Terraform é uma ferramenta de infraestrutura como código que permite criar, alterar e melhorar de maneira previsível a infraestrutura em nuvem usando códigos.
É possível definir e implantar um fluxo de trabalho usando o recurso do Terraform
google_workflows_workflow. Para mais informações, consulte
Criar um fluxo de trabalho usando o Terraform.
Para ajudar a gerenciar e manter fluxos de trabalho grandes, é possível criar o fluxo de trabalho
em um arquivo YAML separado e importar esse arquivo para o Terraform usando a
templatefile função
que lê um arquivo em um determinado caminho e renderiza o conteúdo como um modelo.
Exemplo
# Define a workflow resource "google_workflows_workflow" "workflows_example" { name = "sample-workflow" region = var.region description = "A sample workflow" service_account = google_service_account.workflows_service_account.id # Import main workflow YAML file source_contents = templatefile("${path.module}/workflow.yaml",{}) }
Da mesma forma, se você tiver um fluxo de trabalho principal chamando vários subfluxos de trabalho, poderá definir o fluxo de trabalho principal e os subfluxos de trabalho em arquivos separados e usar a função templatefile para importá-los.
Exemplo
# Define a workflow resource "google_workflows_workflow" "workflows_example" { name = "sample-workflow" region = var.region description = "A sample workflow" service_account = google_service_account.workflows_service_account.id # Import main workflow and subworkflow YAML files source_contents = join("", [ templatefile( "${path.module}/workflow.yaml",{} ), templatefile( "${path.module}/subworkflow.yaml",{} )]) }
Se você estiver se referindo a números de linha ao depurar um fluxo de trabalho, todos os arquivos YAML importados pelo arquivo de configuração do Terraform serão mesclados e implantados como um único fluxo de trabalho.
Implantar um fluxo de trabalho de um repositório Git
O Cloud Build usa gatilhos de build para ativar a automação de CI/CD. Você pode configurar gatilhos para ouvir eventos de entrada, como quando um novo commit é enviado para um repositório ou quando uma solicitação de envio é iniciada e, em seguida, executar um build automaticamente quando novos eventos chegam.
É possível usar um gatilho de build do Cloud Build para iniciar automaticamente uma build e implantar um fluxo de trabalho de um repositório Git. É possível configurar o gatilho para implantar o fluxo de trabalho em qualquer alteração no repositório de origem ou implantar o fluxo de trabalho somente quando a alteração corresponder a critérios específicos.
Essa abordagem pode ajudar a gerenciar o ciclo de vida da implantação. Por exemplo, é possível implantar mudanças em um fluxo de trabalho em um ambiente de staging, executar testes nesse ambiente e, em seguida, iniciar essas mudanças de maneira incremental no ambiente de produção. Para mais informações, consulte Implantar um fluxo de trabalho de um repositório Git usando o Cloud Build.
Otimizar o uso
O custo para executar um fluxo de trabalho é mínimo. No entanto, para uso de alto volume, aplique as diretrizes a seguir para otimizar o uso e diminuir o custo:
Em vez de usar domínios personalizados, verifique se todas as chamadas para Google Cloud serviços usam
*.appspot.com,*.cloud.goog,*.cloudfunctions.net, ou*.run.apppara que você seja cobrado por etapas internas e não externas.Aplique uma política de novas tentativas personalizada que equilibre suas necessidades de latência e confiabilidade com os custos. Novas tentativas mais frequentes diminuem a latência e aumentam a confiabilidade, mas também podem aumentar os custos.
Ao usar conectores que aguardam operações de longa duração, defina uma política de pesquisa personalizada que otimize a latência para o custo. Por exemplo, se você espera que uma operação leve mais de uma hora, talvez queira uma política que inicialmente sonde após um minuto em caso de falha imediata e, em seguida, a cada 15 minutos.
Combine atribuições em uma etapa.
Evite o uso excessivo de etapas
sys.log. Considere usar o registro de chamadas em vez disso.Entenda quais operações são consideradas uma etapa. As operações que não contam como etapas por conta própria são contadas quando usadas em uma etapa aplicável. Por exemplo, o seguinte conta como uma etapa:
- type_check: return: if(get_type((int("6"))) == integer, 1, 2)As principais operações que contam e não contam para o limite máximo de etapas são categorizadas na tabela a seguir:
Categoria Operação Conta como uma etapa - Operações de dados: atribuição, retorno de valores
- Fluxo de controle: saltos (
next), switches, início de umforloop, e cada iteração de umforloop - Chamadas: invocar
sys.get_envou outra função de biblioteca padrão função, outro fluxo de trabalho ou um conector - Simultaneidade: geração de linhas de execução e execução paralela
- Tratamento de erros: cada bloco
raise,try,retryeexceptconta como uma etapa separada, mesmo que outras operações façam parte da mesma etapa maior.Por exemplo, uma etapa que inclui um bloco
trycom uma operação de chamada conta como três etapas: uma para a etapa principal, uma para a tentativa e uma para a chamada. A adição de umretrybloco adiciona mais três etapas (uma para a nova tentativa, uma para a tentativa e uma para a chamada), totalizando seis etapas.
Não conta como uma etapa - Leitura e gravação em
listas,
mapas, e
variáveis
Embora uma pesquisa individual não adicione uma etapa extra, uma etapa que contenha a pesquisa, por exemplo, uma
assignetapa—conta como uma etapa. -
Funções auxiliares de expressão integradas específicas:
len(),int()eget_type() - Operações de comparação e aritmética
- Concatenação de strings
- Operações booleanas
Resumo das práticas recomendadas
A tabela a seguir resume as dicas gerais e as práticas recomendadas neste documento.
A seguir
- Práticas recomendadas de segurança
- Visão geral da depuração
- Resolver problemas
- Problemas conhecidos do Workflows