Bonnes pratiques concernant les workflows

Lorsque vous orchestrez vos services à l'aide de Workflows, consultez les bonnes pratiques répertoriées ici.

Cette liste de recommandations n'est pas exhaustive et ne vous apprend pas les bases de l'utilisation de Workflows. Dans ce document, nous partons du principe que vous avez déjà une compréhension générale de l'environnement global de Google Cloud et de Workflows. Pour en savoir plus, consultez le framework d'architecture Google Cloud et la présentation des workflows.

Sélectionner un schéma de communication optimal

Lorsque vous concevez une architecture de microservices pour déployer plusieurs services, vous pouvez choisir l'un des modèles de communication suivants:

  • Communication directe de service à service

  • Communication indirecte basée sur des événements (également appelée chorégraphie)

  • Configuration, coordination et gestion automatisées (également appelées orchestration)

Prenez en compte les avantages et les inconvénients de chacune des options précédentes, et sélectionnez un modèle optimal pour votre cas d'utilisation. Par exemple, la communication directe de service à service peut être plus simple à mettre en œuvre que d'autres options, mais elle coupe étroitement vos services. En revanche, une architecture basée sur des événements vous permet d'associer faiblement vos services. Cependant, la surveillance et le débogage peuvent être plus compliqués. Enfin, un orchestrateur central tel que Workflows, bien que moins flexible, vous permet de coordonner la communication entre les services sans le couplage fort de la communication directe de service à service ou du caractère complexe des événements chorégraphiés.

Vous pouvez également combiner des modèles de communication. Par exemple, dans une orchestration basée sur des événements, des services étroitement liés sont gérés dans une orchestration qui est déclenchée par un événement. De même, vous pouvez concevoir un système dans lequel une orchestration entraîne l'envoi d'un message Pub/Sub à un autre système ordonnancé.

Conseils généraux

Une fois que vous avez décidé d'utiliser Workflows comme orchestrateur de services, tenez compte des conseils utiles suivants.

Évitez de coder les URL en dur

Vous pouvez prendre en charge des workflows transférables dans plusieurs environnements et plus faciles à gérer en évitant les URL codées en dur:

  • Définissez les URL en tant qu'arguments d'exécution.

    Cela peut être utile lorsque votre workflow est appelé via une bibliothèque cliente ou l'API. Toutefois, cela ne fonctionnera pas si votre workflow est déclenché par un événement d'Eventarc et que le seul argument pouvant être transmis est la charge utile de l'événement.

    Exemple

    main:
      params: [args]
      steps:
        - init:
            assign:
              - url1: ${args.urls.url1}
              - url2: ${args.urls.url2}

    Lorsque vous exécutez le workflow, vous pouvez spécifier les URL. Par exemple:

    gcloud workflows run multi-env --data='{"urls":{"url1": "URL_ONE", "url2": "URL_TWO"}}'
  • Utilisez des variables d'environnement et créez un workflow configuré de manière dynamique en fonction de l'environnement dans lequel il est déployé. Vous pouvez également créer un workflow qui peut être réutilisé comme modèle et configuré en fonction de variables d'environnement gérées séparément.

  • Utilisez une technique de substitution qui vous permet de créer un seul fichier de définition de workflow, mais de déployer des variantes à l'aide d'un outil qui remplace les espaces réservés dans votre workflow. Par exemple, vous pouvez utiliser Cloud Build pour déployer un workflow et, dans le fichier de configuration Cloud Build, ajouter une étape pour remplacer les URL d'espace réservé dans le workflow.

    Exemple

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

    Vous pouvez ensuite remplacer les valeurs des variables au moment de la compilation. Exemple :

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

    Pour en savoir plus, consultez Envoyer une compilation via la CLI et l'API.

    Vous pouvez également utiliser Terraform pour provisionner votre infrastructure et définir un fichier de configuration qui crée des workflows pour chaque environnement à l'aide de variables d'entrée.

    Exemple

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

    Lorsque des variables sont déclarées dans le module racine de votre configuration, vous pouvez leur attribuer des valeurs de différentes manières. Exemple :

    terraform apply -var="project_id=PROJECT_ID" -var="url1=URL_ONE" -var="url2=URL_TWO"
  • Utilisez le connecteur Secret Manager pour stocker des URL de manière sécurisée dans Secret Manager et les récupérer.

Utiliser des étapes imbriquées

Chaque workflow doit comporter au moins une étape. Par défaut, Workflows traite les étapes comme si elles se trouvaient dans une liste ordonnée et les exécute une par une jusqu'à ce que toutes les étapes aient été exécutées. Logiquement, certaines étapes doivent être regroupées et vous pouvez utiliser un bloc steps pour imbriquer une série d'étapes. Cela est pratique, car cela vous permet de pointer vers l'étape atomique correcte pour traiter un ensemble d'étapes.

Exemple

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

Encapsuler les expressions

Toutes les expressions doivent commencer par $ et être placées entre accolades:

${EXPRESSION}

Pour éviter les problèmes d'analyse YAML, vous pouvez encapsuler les expressions entre guillemets. Par exemple, les expressions contenant des deux-points peuvent entraîner un comportement inattendu lorsque les deux-points sont interprétés comme la définition d'une carte. Vous pouvez résoudre ce problème en encapsulant l'expression YAML entre guillemets simples:

'${"Name: " + myVar}'

Vous pouvez également utiliser des expressions qui s'étendent sur plusieurs lignes. Par exemple, vous devrez peut-être encapsuler une requête SQL entre guillemets lorsque vous utilisez le connecteur Workflows BigQuery.

Exemple

- 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

Pour découvrir la définition complète du workflow, consultez la page Exécuter plusieurs tâches BigQuery en parallèle.

Utiliser des appels déclaratifs

Utilisez Workflows pour appeler des services à partir du workflow lui-même, gérer les résultats et exécuter des tâches simples, comme effectuer un appel HTTP. Les workflows peuvent appeler des services, analyser des réponses et construire des entrées pour d'autres services connectés. Appeler un service vous permet d'éviter les complications d'appels supplémentaires, de dépendances supplémentaires et de services d'appel de services. Envisagez de remplacer les services exempts de logique métier par des appels d'API déclaratifs et utilisez Workflows pour éliminer la complexité.

Cependant, vous devez créer des services pour effectuer toute tâche trop complexe pour Workflows, par exemple pour implémenter une logique métier réutilisable, des calculs complexes ou des transformations non compatibles avec les expressions Workflows et sa bibliothèque standard. Un cas compliqué est généralement plus facile à mettre en œuvre dans le code, plutôt que d'utiliser YAML ou JSON et la syntaxe Workflows.

Stockez uniquement ce dont vous avez besoin

Gardez le contrôle sur la consommation de mémoire afin de ne pas rencontrer de limites de ressources ou d'erreur indiquant un tel taux, comme ResourceLimitError, MemoryLimitExceededError ou ResultSizeLimitExceededError.

Soyez sélectif quant à ce que vous stockez dans les variables, en filtrant et en ne stockant que ce dont vous avez besoin. Si un service renvoie une charge utile trop volumineuse, utilisez une fonction distincte pour effectuer l'appel à votre place et ne renvoyer que les éléments requis.

Vous pouvez libérer de la mémoire en effaçant les variables. Par exemple, vous pouvez libérer de la mémoire nécessaire pour les étapes suivantes. Vous pouvez également avoir des appels avec des résultats qui ne vous intéressent pas, et vous pouvez les omettre.

Vous pouvez effacer une variable en attribuant null. En YAML, vous pouvez également attribuer une valeur vide ou ~ à une variable. Cela permet d'identifier la mémoire qui peut être récupérée en toute sécurité.

Exemple

  - step:
      assign:
        - bigVar:

Utiliser des sous-workflows et des workflows externes

Vous pouvez utiliser des sous-workflows pour définir une logique ou un ensemble d'étapes que vous souhaitez appeler plusieurs fois, ce qui simplifie la définition du workflow. Les sous-workflows sont semblables à une fonction ou à une routine d'un langage de programmation. Ils peuvent accepter des paramètres et des valeurs renvoyées, ce qui vous permet de créer des workflows plus complexes avec un plus large éventail d'applications.

Notez que les sous-workflows se trouvent localement dans votre définition de workflow et ne peuvent pas être réutilisés dans d'autres workflows. Toutefois, vous pouvez appeler des workflows à partir d'autres workflows. Les connecteurs Workflows peuvent vous y aider. Pour en savoir plus, consultez les présentations des connecteurs pour l'API Workflow Executions et l'API Workflows.

Utiliser des connecteurs Workflows

Workflows fournit un certain nombre de connectors qui facilitent l'accès à d'autres produits Google Cloud au sein d'un workflow. Les connecteurs simplifient les services d'appel, car ils gèrent la mise en forme des requêtes à votre place, en fournissant des méthodes et des arguments. Ainsi, vous n'avez pas besoin de connaître les détails d'une API Google Cloud. Les connecteurs ont également un comportement intégré pour gérer les tentatives et les opérations de longue durée, vous évitant ainsi les itérations et l'attente de la fin des appels. Les connecteurs s'en occupent à votre place.

Si vous devez appeler une API Google Cloud, vérifiez d'abord s'il existe un connecteur Workflows pour cette API. De plus, si vous ne voyez pas de connecteur pour un produit Google Cloud, vous pouvez le demander.

Découvrez comment utiliser un connecteur. Pour obtenir une référence détaillée des connecteurs disponibles, consultez la documentation de référence sur les connecteurs.

Exécuter les étapes du workflow en parallèle

Bien que Workflows puisse exécuter des étapes de manière séquentielle, vous pouvez également exécuter des étapes indépendantes en parallèle. Dans certains cas, cela peut accélérer considérablement l'exécution de votre workflow. Pour en savoir plus, consultez la section Exécuter les étapes du workflow en parallèle.

Appliquer des nouvelles tentatives et le modèle saga

Concevez des workflows résilients et capables de gérer les défaillances de service temporaires et permanentes. Les erreurs liées aux workflows peuvent être générées, par exemple, par des requêtes HTTP, des fonctions ou des connecteurs ayant échoué, ou bien générées par votre propre code de workflow. Ajoutez la gestion des exceptions et des nouvelles tentatives afin que l'échec d'une étape n'entraîne pas l'échec de l'ensemble du workflow.

Certaines transactions commerciales couvrent plusieurs services. Vous avez donc besoin d'un mécanisme pour implémenter des transactions couvrant plusieurs services. Le modèle de conception saga est un moyen de gérer la cohérence des données entre les microservices dans des scénarios de transaction distribuée. Une saga est une séquence de transactions qui publie un événement pour chaque transaction et déclenche la transaction suivante. Si une transaction échoue, la saga exécute des transactions compensatoires qui compensent les échecs précédents de la séquence. Essayez le tutoriel Retries and Saga Pattern in Workflows (Tentatives et modèle Saga dans Workflows) sur GitHub.

Utiliser des rappels pour patienter

Les rappels permettent aux exécutions de workflow d'attendre qu'un autre service envoie une requête au point de terminaison de rappel. Cette requête reprend l'exécution du workflow.

Les rappels vous permettent de signaler à votre workflow qu'un événement spécifié s'est produit et d'attendre cet événement sans interrogation. Par exemple, vous pouvez créer un workflow qui vous avertit lorsqu'un produit est de nouveau en stock ou expédié, ou qui attend une interaction humaine, telle que la vérification d'une commande ou la validation d'une traduction. Vous pouvez également attendre les événements à l'aide de rappels et de déclencheurs Eventarc.

Orchestrer des jobs de longue durée

Si vous devez exécuter des charges de travail de traitement par lot de longue durée, vous pouvez utiliser des tâches par lot ou des tâches Cloud Run, et vous pouvez utiliser Workflows pour gérer les services. Cela vous permet de combiner les avantages, et de provisionner et orchestrer efficacement l'ensemble du processus.

Batch est un service entièrement géré qui vous permet de planifier, de mettre en file d'attente et d'exécuter des charges de travail par lot sur des instances de machines virtuelles (VM) Compute Engine. Vous pouvez utiliser le connecteur de workflows pour Batch afin de planifier et d'exécuter un job Batch. Pour en savoir plus, consultez le tutoriel.

Les tâches Cloud Run permettent d'exécuter du code qui effectue un travail (un job) et se ferme une fois le travail terminé. Workflows vous permet d'exécuter des tâches Cloud Run dans le cadre d'un workflow afin d'effectuer un traitement de données plus complexe ou d'orchestrer un système de jobs existants. Essayez le tutoriel qui montre comment utiliser Workflows pour exécuter une tâche Cloud Run.

Conteneuriser les tâches de longue durée

Vous pouvez automatiser l'exécution d'un conteneur de longue durée à l'aide de Workflows et de Compute Engine. Par exemple, vous pouvez conteneuriser une tâche de longue durée afin qu'elle puisse s'exécuter n'importe où, puis exécuter le conteneur sur une VM Compute Engine pour la durée maximale d'exécution d'un workflow (un an).

À l'aide de Workflows, vous pouvez automatiser la création de la VM, l'exécution du conteneur sur la VM et la suppression de la VM. Cela vous permet d'utiliser un serveur et d'exécuter un conteneur, mais cela élimine la complexité liée à la gestion des deux et peut être utile si vous rencontrez des limites de temps lors de l'utilisation d'un service tel que Cloud Functions ou Cloud Run. Essayez le tutoriel Conteneurs de longue durée avec Workflows et Compute Engine sur GitHub.

Exécuter des outils de ligne de commande à partir de Workflows

Cloud Build est un service qui exécute vos compilations sur Google Cloud sous la forme d'une série d'étapes de compilation, où chaque étape est exécutée dans un conteneur Docker. L'exécution des étapes de compilation est analogue à l'exécution de commandes dans un script.

La Google Cloud CLI inclut les outils de ligne de commande gcloud, gsutil, bq et kubectl, mais il n'existe aucun moyen direct d'exécuter des commandes de gcloud CLI à partir de Workflows. Cependant, Cloud Build fournit des images de conteneur qui incluent la gcloud CLI. Vous pouvez exécuter des commandes de gcloud CLI dans ces conteneurs à partir d'une étape Cloud Build, puis créer cette étape dans Workflows à l'aide du connecteur Cloud Build.

Exemple

Exécutez gcloud dans un workflow:

# 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")}

Utiliser Terraform pour créer votre workflow

Terraform est un outil Infrastructure as Code qui vous permet de créer, de modifier et d'améliorer de manière prévisible votre infrastructure cloud à l'aide de code.

Vous pouvez définir et déployer un workflow à l'aide de la ressource Terraform google_workflows_workflow. Pour en savoir plus, consultez la page Créer un workflow à l'aide de Terraform.

Pour vous aider à gérer et maintenir des workflows volumineux, vous pouvez les créer dans un fichier YAML distinct et importer ce fichier dans Terraform à l'aide de la fonction templatefile, qui lit un fichier à un chemin d'accès donné et en affiche le contenu en tant que modèle.

Exemple

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

De même, si un workflow principal appelle plusieurs sous-workflows, vous pouvez les définir dans des fichiers distincts et utiliser la fonction templatefile pour les importer.

Exemple

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

Notez que si vous faites référence aux numéros de ligne lors du débogage d'un workflow, tous les fichiers YAML importés via le fichier de configuration Terraform sont fusionnés et déployés en tant que workflow unique.

Déployer un workflow à partir d'un dépôt Git

Cloud Build utilise des déclencheurs de compilation pour permettre l'automatisation CI/CD. Vous pouvez configurer des déclencheurs pour écouter les événements entrants, par exemple lorsqu'un nouveau commit est envoyé vers un dépôt ou lorsqu'une demande d'extraction est lancée, puis exécuter automatiquement une compilation lorsque de nouveaux événements arrivent.

Vous pouvez utiliser un déclencheur Cloud Build pour démarrer automatiquement une compilation et déployer un workflow à partir d'un dépôt Git. Vous pouvez configurer le déclencheur pour déployer votre workflow sur toute modification apportée au dépôt source, ou ne déployer le workflow que lorsque la modification répond à des critères spécifiques.

Cette approche peut vous aider à gérer le cycle de vie de votre déploiement. Par exemple, vous pouvez déployer des modifications dans un workflow dans un environnement de préproduction, exécuter des tests sur cet environnement, puis lancer ces modifications de manière incrémentielle dans l'environnement de production. Pour en savoir plus, consultez la page Déployer un workflow à partir d'un dépôt Git à l'aide de Cloud Build.

Optimiser l'utilisation

Le coût d'exécution d'un workflow est minime. Toutefois, en cas d'utilisation élevée, appliquez les consignes suivantes pour optimiser l'utilisation et réduire les coûts:

  • Au lieu d'utiliser des domaines personnalisés, assurez-vous que tous les appels aux services Google Cloud utilisent *.appspot.com, *.cloud.goog, *.cloudfunctions.net ou *.run.app pour que les étapes internes et non externes vous soient facturées.

  • Appliquez une règle de nouvelle tentative personnalisée qui permette d'équilibrer vos besoins en termes de latence et de fiabilité avec les coûts. Des tentatives plus fréquentes réduisent la latence et augmentent la fiabilité, mais peuvent également augmenter les coûts.

  • Lorsque vous utilisez des connecteurs qui attendent des opérations de longue durée, définissez une règle d'interrogation personnalisée qui optimise la latence pour les coûts. Par exemple, si vous prévoyez qu'une opération dure plus d'une heure, vous pouvez avoir besoin d'une règle qui interroge initialement une minute en cas d'échec immédiat, puis toutes les 15 minutes.

  • Combinez les attributions en une seule étape.

  • Évitez une utilisation excessive des étapes sys.log. Envisagez plutôt d'utiliser la journalisation des appels.

Récapitulatif des bonnes pratiques

Le tableau suivant récapitule les conseils généraux et les bonnes pratiques recommandés dans ce document.

Conseils généraux
Bonnes pratiques

Étapes suivantes