Práticas recomendadas para fluxos de trabalho

Pode consultar as práticas recomendadas indicadas aqui quando orquestrar os seus serviços com fluxos de trabalho.

Esta não é uma lista exaustiva de recomendações e não lhe ensina os básicos de como usar os fluxos de trabalho. Este documento pressupõe que já tem uma compreensão geral do cenário Google Cloud geral e dos fluxos de trabalho. Para mais informações, consulte o Google Cloud Well-Architected Framework e a vista geral dos fluxos de trabalho.

Selecione um padrão de comunicação ideal

Ao criar uma arquitetura de microsserviços para implementar vários serviços, pode selecionar entre os seguintes padrões de comunicação:

  • Comunicação direta entre serviços

  • Comunicação indireta baseada em eventos (também conhecida como coreografia)

  • Configuração, coordenação e gestão automatizadas (também conhecidas como orquestração)

Certifique-se de que considera as vantagens e as desvantagens de cada uma das opções anteriores e selecione um padrão ideal para o seu exemplo de utilização. Por exemplo, a comunicação direta entre serviços pode ser mais simples de implementar do que outras opções, mas associa os seus serviços de forma mais estreita. Por outro lado, uma arquitetura orientada por eventos permite-lhe associar os seus serviços de forma flexível. No entanto, a monitorização e a depuração podem ser mais complicadas. Por último, um orquestrador central, como os fluxos de trabalho, embora seja menos flexível, permite-lhe coordenar a comunicação entre serviços sem a interdependência da comunicação direta entre serviços ou a complexidade dos eventos coreografados.

Também pode combinar padrões de comunicação. Por exemplo, na orquestração orientada por eventos, os serviços estreitamente relacionados são geridos numa orquestração que é acionada por um evento. Da mesma forma, pode criar um sistema em que uma orquestração resulte numa mensagem do Pub/Sub para outro sistema orquestrado.

Sugestões gerais

Depois de decidir usar os fluxos de trabalho como orquestrador de serviços, tenha em atenção as seguintes sugestões úteis.

Evite codificar URLs

Pode suportar fluxos de trabalho portáteis em vários ambientes e mais fáceis de manter evitando URLs codificados. Pode fazê-lo das seguintes formas:

  • Defina os URLs como argumentos de tempo de execução.

    Isto pode ser útil quando o fluxo de trabalho é invocado através de uma biblioteca cliente ou da API. (No entanto, isto 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}

    Quando executa o fluxo de trabalho, pode 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, consoante o ambiente no qual é implementado. Em alternativa, crie um fluxo de trabalho que possa ser reutilizado como um modelo e configurado de acordo com as variáveis de ambiente mantidas separadamente.

  • Use uma técnica de substituição que lhe permita criar um único ficheiro de definição do fluxo de trabalho, mas implemente variantes através de uma ferramenta que substitui marcadores de posição no seu fluxo de trabalho. Por exemplo, pode usar o Cloud Build para implementar um fluxo de trabalho e, no ficheiro de configuração do Cloud Build, adicionar um passo para substituir URLs de marcadores de posição 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, pode substituir os valores das variáveis no momento da compilação. Por exemplo:

    gcloud builds submit --config cloudbuild.yaml \
        --substitutions=_ENV=staging,_URL1="URL_ONE",_URL2="URL_TWO"

    Para mais informações, consulte o artigo Envie uma compilação através da CLI e da API.

    Em alternativa, pode usar o Terraform para aprovisionar a sua infraestrutura e definir um ficheiro de configuração que crie fluxos de trabalho para cada ambiente através de 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 sua configuração, podem ser atribuídos valores de várias formas. 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 em segurança no Secret Manager e recuperá-los.

Use passos aninhados

Todos os fluxos de trabalho têm de ter, pelo menos, um passo. Por predefinição, os fluxos de trabalho tratam os passos como se estivessem numa lista ordenada e executam-nos um de cada vez até que todos os passos tenham sido executados. Logicamente, alguns passos devem ser agrupados e pode usar um bloco steps para aninhar uma série de passos. Isto é conveniente, pois permite apontar para o passo atómico correto para processar um conjunto de passos.

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

Unir expressões

Todas as expressões têm de começar com um $ e estar entre chavetas:

${EXPRESSION}

Para evitar problemas de análise YAML, pode incluir expressões entre aspas. Por exemplo, as expressões que contêm dois pontos podem causar um comportamento inesperado quando os dois pontos são interpretados como a definição de um mapa. Pode resolver este problema ao incluir a expressão YAML entre aspas simples:

'${"Name: " + myVar}'

Também pode usar expressões que abrangem várias linhas. Por exemplo, pode ter de incluir uma consulta SQL entre aspas quando usar o conetor do BigQuery dos Workflows.

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 o artigo Execute várias tarefas do BigQuery em paralelo.

Use chamadas declarativas

Use os fluxos de trabalho para chamar serviços a partir do próprio fluxo de trabalho e processar os resultados, bem como para executar tarefas simples, como fazer uma chamada HTTP. Os fluxos de trabalho podem invocar serviços, analisar respostas e criar entradas para outros serviços associados. Chamar um serviço permite-lhe evitar as complicações de invocações adicionais, dependências adicionais e serviços que chamam serviços. Considere substituir os serviços que não têm lógica empresarial por chamadas de API declarativas e usar fluxos de trabalho para abstrair a complexidade.

No entanto, deve criar serviços para realizar qualquer trabalho demasiado complexo para os fluxos de trabalho. Por exemplo, implementar lógica empresarial reutilizável, cálculos complexos ou transformações que não são suportadas pelas expressões dos fluxos de trabalho e a respetiva biblioteca padrão. Normalmente, é mais fácil implementar um caso complicado no código do que usar YAML ou JSON e a sintaxe de fluxos de trabalho.

Armazene apenas o que precisa

Mantenha o consumo de memória sob controlo para não encontrar limites de recursos nem um erro que o indique, como ResourceLimitError, MemoryLimitExceededError ou ResultSizeLimitExceededError.

Seja seletivo quanto ao que armazena em variáveis, filtrando e armazenando apenas o que precisa. Se um serviço devolver um payload demasiado grande, use uma função separada para fazer a chamada por si e devolver apenas o que é necessário.

Pode libertar memória limpando as variáveis. Por exemplo, pode querer libertar memória necessária para passos subsequentes. Em alternativa, pode ter chamadas com resultados que não lhe interessam e pode omitir esses resultados por completo.

Pode limpar uma variável atribuindo null. Em YAML, também pode atribuir um valor vazio ou ~ a uma variável. Isto identifica a memória que pode ser reclamada em segurança.

Exemplo

  - step:
      assign:
        - bigVar:

Use subfluxos de trabalho e fluxos de trabalho externos

Pode usar subfluxos de trabalho para definir uma parte da lógica ou um conjunto de passos que 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 a uma rotina numa linguagem de programação. Podem aceitar parâmetros e devolver valores, o que lhe permite criar fluxos de trabalho mais complexos com uma gama mais ampla de aplicações.

Tenha em atenção que os subfluxos de trabalho são locais à definição do fluxo de trabalho e não podem ser reutilizados noutros fluxos de trabalho. No entanto, pode chamar fluxos de trabalho a partir de outros fluxos de trabalho. Os conetores do Workflows podem ajudar com esta tarefa. Para mais informações, consulte as vistas gerais dos conetores para a API Workflow Executions e a API Workflows.

Use conetores do Workflows

Os fluxos de trabalho oferecem vários conetores que facilitam o acesso a outros Google Cloud produtos num fluxo de trabalho. Os conetores simplificam os serviços de chamadas porque processam a formatação dos pedidos por si, fornecendo métodos e argumentos para que não precise de saber os detalhes de umaGoogle Cloud API. Os conetores também têm um comportamento incorporado para processar novas tentativas e operações de longa duração, para que possa evitar a iteração e a espera pela conclusão das chamadas. Os conetores encarregam-se desta tarefa por si.

Se precisar de chamar uma Google Cloud API, verifique primeiro se existe um conetor do Workflows para a mesma. Além disso, se não vir um conetor para um Google Cloud produto, pode solicitá-lo.

Saiba como usar um conetor e, para uma referência detalhada dos conetores disponíveis, consulte a Referência de conetores.

Execute passos do fluxo de trabalho em paralelo

Embora os fluxos de trabalho possam executar passos sequencialmente, também pode executar passos independentes em paralelo. Em alguns casos, isto pode acelerar significativamente a execução do fluxo de trabalho. Para mais informações, consulte o artigo Execute etapas do fluxo de trabalho em paralelo.

Aplique novas tentativas e o padrão de saga

Crie fluxos de trabalho resilientes que possam processar falhas de serviço transitórias e permanentes. Os erros dos fluxos de trabalho podem ser apresentados, por exemplo, por pedidos HTTP com falhas, funções, conetores ou gerados pelo seu próprio código de fluxo de trabalho. Adicione processamento de erros e novas tentativas para que uma falha num passo não cause a falha de todo o fluxo de trabalho.

Algumas transações comerciais abrangem vários serviços, pelo que precisa de um mecanismo para implementar transações que abrangem serviços. O padrão de design de saga é uma forma de gerir a consistência dos dados nos microsserviços em cenários de transações distribuídas. Uma saga é uma sequência de transações que publica um evento para cada transação e que aciona a transação seguinte. Se uma transação falhar, a saga executa transações de compensação que contrariam as falhas anteriores na sequência. Experimente o tutorial Repetições e padrão Saga em fluxos de trabalho no GitHub.

Use os retornos de chamada para esperar

As callbacks permitem que as execuções do fluxo de trabalho aguardem que outro serviço faça um pedido ao ponto final de callback. Esse pedido retoma a execução do fluxo de trabalho.

Com os callbacks, pode sinalizar ao seu fluxo de trabalho que ocorreu um evento especificado e aguardar esse evento sem sondar. Por exemplo, pode criar um fluxo de trabalho que lhe envia uma notificação quando um produto volta a estar em stock ou quando um artigo é enviado; ou que aguarda para permitir a interação humana, como rever uma encomenda ou validar uma tradução. Também pode aguardar eventos através de callbacks e acionadores do Eventarc.

Orquestre tarefas de longa duração

Se precisar de executar cargas de trabalho de processamento em lote de execução prolongada, pode usar o Batch ou os trabalhos do Cloud Run e pode usar os Workflows para gerir os serviços. Isto permite-lhe combinar vantagens e aprovisionar e orquestrar todo o processo de forma eficiente.

O Batch é um serviço totalmente gerido que lhe permite agendar, colocar em fila e executar cargas de trabalho em lote em instâncias de máquinas virtuais (VMs) do Compute Engine. Pode usar o conetor Workflows para o Batch para agendar e executar uma tarefa do Batch. Para ver detalhes, experimente o tutorial.

As tarefas do Cloud Run são usadas para executar código que realiza trabalho (uma tarefa) e termina quando o trabalho está concluído. Os fluxos de trabalho permitem-lhe executar tarefas do Cloud Run como parte de um fluxo de trabalho para realizar um processamento de dados mais complexo ou orquestrar um sistema de tarefas existentes. Experimente o tutorial que demonstra como usar os Workflows para executar uma tarefa do Cloud Run.

Coloque tarefas de execução prolongada em contentores

Pode automatizar a execução de um contentor de longa duração através dos Workflows e do Compute Engine. Por exemplo, pode colocar uma tarefa de execução prolongada num contentor para que possa ser executada em qualquer lugar e, em seguida, executar o contentor numa VM do Compute Engine durante a duração máxima de uma execução do fluxo de trabalho (um ano).

Com os fluxos de trabalho, pode automatizar a criação da VM, a execução do contentor na VM e a eliminação da VM. Isto permite-lhe usar um servidor e executar um contentor, mas abstrai a complexidade da gestão de ambos e pode ser útil se tiver limitações de tempo ao usar um serviço como as funções do Cloud Run ou o Cloud Run. Experimente o tutorial Contentores de execução prolongada com fluxos de trabalho e o Compute Engine no GitHub.

Execute ferramentas de linha de comandos a partir de fluxos de trabalho

O Cloud Build é um serviço que executa as suas compilações como Google Cloud uma série de passos de compilação, em que cada passo de compilação é executado num contentor Docker. A execução de passos de compilação é análoga à execução de comandos num script.

A CLI do Google Cloud inclui as ferramentas de linha de comando gcloud, bq e kubectl, mas não existe uma forma direta de executar comandos da CLI gcloud a partir dos Workflows. No entanto, o Cloud Build fornece imagens de contentores que incluem a CLI gcloud. Pode executar comandos da CLI gcloud nesses contentores a partir de um passo do Cloud Build e pode criar esse passo nos fluxos de trabalho através do conector do Cloud Build.

Exemplo

Execute o gcloud num fluxo de trabalho:

# This example shows how to execute gcloud commands from Workflows
# using Cloud Build and returns the output

main:
  steps:
  - execute_command:
      call: gcloud
      args:
          args: "workflows list"
      result: result
  - return_result:
      return: ${result}

gcloud:
  params: [args]
  steps:
  - create_build:
      call: googleapis.cloudbuild.v1.projects.builds.create
      args:
        projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
        parent: ${"projects/" + sys.get_env("GOOGLE_CLOUD_PROJECT_ID") + "/locations/global"}
        body:
          serviceAccount: ${sys.get_env("GOOGLE_CLOUD_SERVICE_ACCOUNT_NAME")}
          options:
            logging: CLOUD_LOGGING_ONLY
          steps:
          - name: gcr.io/google.com/cloudsdktool/cloud-sdk
            entrypoint: /bin/bash
            args: ${["-c", "gcloud " + args + " > $$BUILDER_OUTPUT/output"]}
      result: result_builds_create
  - return_build_result:
      return: ${text.split(text.decode(base64.decode(result_builds_create.metadata.build.results.buildStepOutputs[0])), "\n")}

Run kubectl in a workflow:

# This example shows how to execute kubectl commands from Workflows
# using Cloud Build and returns the output

main:
  steps:
  - execute_command:
      call: kubectl
      args:
          args: "--help"
      result: result
  - return_result:
      return: ${result}

kubectl:
  params: [args]
  steps:
  - create_build:
      call: googleapis.cloudbuild.v1.projects.builds.create
      args:
        projectId: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
        parent: ${"projects/" + sys.get_env("GOOGLE_CLOUD_PROJECT_ID") + "/locations/global"}
        body:
          serviceAccount: ${sys.get_env("GOOGLE_CLOUD_SERVICE_ACCOUNT_NAME")}
          options:
            logging: CLOUD_LOGGING_ONLY
          steps:
          - name: gcr.io/cloud-builders/kubectl
            entrypoint: /bin/bash
            args: ${["-c", "kubectl " + args + " > $$BUILDER_OUTPUT/output"]}
      result: result_builds_create
  - return_build_result:
      return: ${text.split(text.decode(base64.decode(result_builds_create.metadata.build.results.buildStepOutputs[0])), "\n")}

Use o Terraform para criar o seu fluxo de trabalho

O Terraform é uma ferramenta de infraestrutura como código que lhe permite criar, alterar e melhorar de forma previsível a sua infraestrutura na nuvem através de código.

Pode definir e implementar um fluxo de trabalho através do recurso Terraform google_workflows_workflow. Para mais informações, consulte o artigo Crie um fluxo de trabalho com o Terraform.

Para ajudar a gerir e manter fluxos de trabalho grandes, pode criar o seu fluxo de trabalho num ficheiro YAML separado e importar esse ficheiro para o Terraform através da função templatefile, que lê um ficheiro num determinado caminho e renderiza o respetivo 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 tiver um fluxo de trabalho principal que chame vários subfluxos de trabalho, pode definir o fluxo de trabalho principal e os subfluxos de trabalho em ficheiros separados e usar a função templatefile para os importar.

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",{}
      )])
  }

Tenha em atenção que, se estiver a referir-se aos números das linhas ao depurar um fluxo de trabalho, todos os ficheiros YAML importados através do ficheiro de configuração do Terraform são unidos e implementados como um único fluxo de trabalho.

Implemente um fluxo de trabalho a partir de um repositório Git

O Cloud Build usa acionadores de compilação para ativar a automatização de CI/CD. Pode configurar acionadores para ouvir eventos recebidos, como quando um novo commit é enviado para um repositório ou quando é iniciada uma solicitação de obtenção, e, em seguida, executar automaticamente uma compilação quando chegarem novos eventos.

Pode usar um acionador do Cloud Build para iniciar automaticamente uma compilação e implementar um fluxo de trabalho a partir de um repositório Git. Pode configurar o acionador para implementar o fluxo de trabalho em qualquer alteração ao repositório de origem ou implementar o fluxo de trabalho apenas quando a alteração corresponder a critérios específicos.

Esta abordagem pode ajudar a gerir o ciclo de vida da implementação. Por exemplo, pode implementar alterações num fluxo de trabalho num ambiente de teste, executar testes nesse ambiente e, em seguida, lançar incrementalmente estas alterações no ambiente de produção. Para mais informações, consulte o artigo Implemente um fluxo de trabalho a partir de um repositório Git com o Cloud Build.

Otimize a utilização

O custo de execução de um fluxo de trabalho é mínimo. No entanto, para uma utilização de volume elevado, aplique as seguintes diretrizes para otimizar a utilização e diminuir o custo:

  • Em vez de usar domínios personalizados, certifique-se de que todas as chamadas para serviços Google Cloud usam *.appspot.com, *.cloud.goog, *.cloudfunctions.net ou *.run.app para que a faturação seja feita por passos internos e não externos.

  • Aplique uma política de repetição personalizada que equilibre as suas necessidades de latência e fiabilidade com os custos. As novas tentativas mais frequentes diminuem a latência e aumentam a fiabilidade, mas também podem aumentar os custos.

  • Quando usar conetores que aguardam operações de longa duração, defina uma política de sondagem personalizada que otimize a latência em função do custo. Por exemplo, se espera que uma operação demore mais de uma hora, pode querer uma política que faça sondagens inicialmente após um minuto em caso de falha imediata e, em seguida, a cada 15 minutos.

  • Combine atribuições num único passo.

  • Evite a utilização excessiva de passos sys.log. Em alternativa, considere usar o registo de chamadas.

Resumo das práticas recomendadas

A tabela seguinte resume as sugestões gerais e as práticas recomendadas neste documento.

Sugestões gerais
Práticas recomendadas

O que se segue?