Aller au contenu

Orchestrer plusieurs états

À la fin, vous saurez

  • Énoncer les trois problèmes que le découpage en états fait apparaître : l'ordre, les sorties partagées et le code répété
  • Écrire une orchestration minimale avec un Makefile ou un script, et en connaître les limites
  • Décrire ce qu'apportent Terragrunt, Terramate, les Stacks de HCP Terraform et Atlantis, et ce qu'ils coûtent
  • Expliquer les fonctionnalités d'OpenTofu qui réduisent le besoin d'outil externe (variables dans le backend)
  • Choisir un niveau d'outillage adapté à la taille de l'équipe et à la contrainte de souveraineté

Prérequis

Testé avec opentofu 1.13 (d'après la documentation) terraform 1.16.1 terragrunt documentation courante, non exécuté terramate documentation courante, non exécuté , vérifié le 5 octobre 2026

Pourquoi

La leçon 8 a découpé l'état de Signalements en couches. Le gain est réel : rayon d'impact réduit, droits séparés, plans rapides. La contrepartie arrive le lendemain. On avait un répertoire, on en a six : trois couches (reseau, donnees, application) fois deux environnements. Avant, une commande faisait tout. Maintenant, quelqu'un doit se souvenir que reseau passe avant donnees, que donnees publie un identifiant que application consomme, et que le bloc backend a été copié six fois avec une clé différente, dont une avec une coquille.

C'est le sujet de cette leçon : l'orchestration, c'est-à-dire tout ce qui se situe entre les états. Terraform ne la fournit pas : il sait appliquer une configuration, pas une famille de configurations. Chaque équipe finit par écrire quelque chose. La question est de savoir quoi, à quel moment, et à quel prix. On commence par nommer précisément les problèmes, puis on parcourt les solutions de la plus légère (un script) à la plus intégrée (une plateforme), sans en présenter aucune comme la bonne : le critère est la taille du problème à résoudre.

Cette leçon ne contient pas de démonstration des outils tiers : Terragrunt, Terramate et Atlantis ne sont pas installés dans l'environnement de rédaction. Ils sont décrits d'après leur documentation, et signalés comme tels. Seule la partie Makefile a été exécutée.

Les concepts

Trois problèmes

L'ordre. Les couches dépendent les unes des autres : l'application attache ses instances au réseau privé, qui doit exister. Pour un premier déploiement, l'ordre est celui des dépendances. Pour une destruction, c'est l'inverse. Pour un changement qui traverse trois couches (par exemple un nouveau sous-réseau, puis une règle de pare-feu, puis une instance qui l'utilise), il faut appliquer dans le bon ordre, et attendre que chaque étape ait réussi avant la suivante.

Les sorties partagées. La couche application a besoin de l'identifiant du réseau, publié en sortie par reseau. Les mécanismes de la leçon 4 existent (source de données terraform_remote_state, ou recherche par nom), mais quelqu'un doit les écrire dans chaque configuration, et la valeur doit exister quand on planifie. Un plan de application avant le premier apply de reseau échoue, parce que la sortie n'existe pas encore.

Le code répété. Le bloc backend ne change que par sa key. Les fichiers versions.tf, les blocs provider, les étiquettes communes sont identiques d'une couche à l'autre. Terraform interdit d'utiliser des variables dans un bloc backend : la clé doit être écrite en dur, ou passée par -backend-config. Résultat : du copier-coller, et la dérive habituelle du copier-coller.

À ces trois s'en ajoute un quatrième quand le nombre de répertoires dépasse une dizaine : le déclenchement. Dans une demande de fusion qui modifie modules/reseau, quelles couches faut-il planifier ? Toutes celles qui l'utilisent. Savoir lesquelles, et ne planifier que celles-là, est un problème de graphe.

Un spectre de solutions

NiveauOutilCe qu'il résoutCe qu'il ajoute
0scripts, Makel'ordre, un peu la répétitiondu code à maintenir
1Terragruntordre, sorties, backend, run --allun second langage de configuration (HCL de Terragrunt)
2Terramateordre, détection de changements, génération de codeun outil et ses conventions de stacks
3Atlantisle déclenchement par demande de fusionun service à héberger
4HCP Terraform (Stacks)tout, intégré à la plateformel'abonnement et la dépendance à la plateforme

On peut empiler les niveaux : Terragrunt exécuté par Atlantis, par exemple. Chaque niveau se justifie par une douleur précise, que la section suivante cherche à faire reconnaître.

En pratique

Niveau 0 : un Makefile

C'est la bonne première réponse, et elle suffit longtemps. Pour deux couches, on boucle dans l'ordre et l'on passe la sortie de la première à la seconde par une variable d'environnement TF_VAR_... :

COUCHES := reseau application

.PHONY: plan apply
plan apply:
	@set -e; for c in $(COUCHES); do \
	  echo "== $$c"; \
	  terraform -chdir=$$c init -input=false -no-color >/dev/null; \
	  if [ "$$c" = application ]; then export TF_VAR_cidr_reseau=$$(terraform -chdir=reseau output -raw cidr); fi; \
	  terraform -chdir=$$c $@ -input=false -no-color $(if $(filter apply,$@),-auto-approve) | grep -E "Plan:|Apply complete|No changes"; \
	done

-chdir change de répertoire pour toute la commande, ce qui évite les cd. set -e arrête la boucle à la première erreur. Voici l'exécution réelle, avec deux couches sans coût (terraform_data) :

$ make apply
== reseau
Plan: 1 to add, 0 to change, 0 to destroy.
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
== application
Plan: 1 to add, 0 to change, 0 to destroy.
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
$ make plan
== reseau
No changes. Your infrastructure matches the configuration.
== application
No changes. Your infrastructure matches the configuration.

C'est utile, c'est compréhensible, et cela montre aussi les limites. Le Makefile ci-dessus ne sait pas détruire (il faudrait l'ordre inverse), ne parallélise pas les couches indépendantes, ne sait pas planifier application avant que reseau ait été appliqué (la sortie n'existe pas), et applique sans relire : il convient à un poste, pas à un pipeline où l'on applique un plan enregistré. À mesure que ces besoins apparaissent, le script grossit, et l'équipe se retrouve à maintenir un orchestrateur maison. Le moment de passer au niveau suivant est celui où le script devient plus difficile à maintenir que l'outil qu'il remplace.

Niveau 1 : Terragrunt

Terragrunt (Gruntwork, logiciel libre) est un enrobage autour de Terraform et d'OpenTofu. Un répertoire qui contient un fichier terragrunt.hcl est une unité (unit), la plus petite chose déployable : elle désigne un module à appliquer (terraform { source = ... }), ses entrées (inputs), et ses dépendances. Un ensemble d'unités forme une stack (implicite, par l'arborescence, ou explicite, par un fichier terragrunt.stack.hcl).

Voici, d'après la documentation, à quoi ressemble Signalements (non exécuté ici). La racine du dépôt porte le backend, généré pour chaque unité :

# live/root.hcl
remote_state {
  backend = "s3"

  generate = {
    path      = "backend.tf"
    if_exists = "overwrite_terragrunt"
  }

  config = {
    bucket       = "signalements-tfstate-<suffixe>"
    key          = "${path_relative_to_include()}/terraform.tfstate"
    region       = "fr-par"
    use_lockfile = true

    endpoints = {
      s3 = "https://s3.fr-par.scw.cloud"
    }

    skip_credentials_validation = true
    skip_region_validation      = true
    skip_requesting_account_id  = true
  }
}

La key se calcule à partir du chemin de l'unité (prod/donnees/terraform.tfstate), ce qui supprime la coquille de copier-coller. Chaque unité hérite de cette racine et déclare ses dépendances :

# live/prod/donnees/terragrunt.hcl
include "racine" {
  path = find_in_parent_folders("root.hcl")
}

terraform {
  source = "git::https://example.org/lyneko/modules.git//donnees?ref=v1.4.0"
}

dependency "reseau" {
  config_path = "../reseau"

  mock_outputs = {
    reseau_id = "00000000-0000-0000-0000-000000000000"
  }
  mock_outputs_allowed_terraform_commands = ["validate", "plan"]
}

inputs = {
  reseau_id = dependency.reseau.outputs.reseau_id
}

Ce que chaque morceau fait :

  • include reprend la configuration racine (backend, fournisseurs) : le code n'est écrit qu'une fois.
  • terraform { source } désigne le module, avec une version (?ref=v1.4.0) : c'est le mécanisme de la leçon 3, utilisé par un dépôt « live » qui ne contient plus que des paramètres.
  • dependency déclare que l'unité dépend de ../reseau, lit ses sorties, et fixe l'ordre. Les mock_outputs fournissent des valeurs factices quand la dépendance n'a pas encore été appliquée, pour que validate et plan fonctionnent avant le premier apply ; ils ne sont autorisés que pour les commandes listées, jamais pour apply.
  • inputs passe les valeurs au module, sans passer par des fichiers .tfvars ni des variables d'environnement.

Et la commande qui remplace le Makefile :

terragrunt run --all plan
terragrunt run --all apply

run --all construit le graphe des dépendances entre unités, applique dans l'ordre (le réseau, les données, l'application), en parallèle quand c'est possible, et en sens inverse pour une destruction. Il existe des options pour filtrer les unités visées. Les anciennes formes (run-all) ont existé ; utilisez la syntaxe de la version que vous installez, que terragrunt --help indique.

Note

Terragrunt évolue vite, y compris dans sa ligne de commande. L'exemple ci-dessus est écrit d'après la documentation courante au 5 octobre 2026 et n'a pas été exécuté. Avant de l'adopter, fixez sa version (voir la leçon 10) et relisez les notes de version à chaque mise à jour.

Le coût de Terragrunt est celui de tout enrobage : un second niveau d'abstraction. Un incident se diagnostique d'abord dans Terragrunt (« quelle configuration a été générée, quel cache ? »), puis dans Terraform. Un cache .terragrunt-cache contient la copie de travail de chaque unité. Les nouveaux venus doivent apprendre deux outils. En échange, la répétition disparaît et l'ordre est déclaré.

Niveau 2 : Terramate

Terramate (CLI libre, avec un service commercial optionnel) aborde le problème autrement : plutôt que d'envelopper les commandes, il organise le dépôt en stacks (un répertoire avec un fichier de configuration stack) et fournit trois choses :

  • une détection de changements : terramate run --changed -- terraform plan n'exécute que les stacks dont les fichiers (ou ceux des modules locaux qu'elles utilisent) ont changé depuis une référence Git, ce qui répond au problème du déclenchement ;
  • l'ordonnancement : les directives before, after et wants dans la configuration d'une stack fixent l'ordre de terramate run ;
  • la génération de code (generate_hcl) : le backend et le fournisseur sont produits à partir de variables globales (globals), plutôt que recopiés.

La différence de philosophie avec Terragrunt : Terramate génère du Terraform ordinaire et laisse le code lisible ; Terragrunt remplace le point d'entrée par ses propres fichiers. Les deux sont des choix défendables : le premier garde une sortie standard que n'importe qui peut lire sans l'outil, le second offre un langage de configuration complet au prix de la dépendance.

Niveau 3 : Atlantis, en rappel

La leçon 12 du premier cours l'a présenté : Atlantis, auto-hébergé, exécute plan et apply quand on commente la demande de fusion, verrouille le répertoire pendant la demande, et publie la sortie du plan en commentaire. Son fichier atlantis.yaml déclare des projets (un par répertoire) et propose des mécanismes pour ordonner l'exécution entre projets (à vérifier dans la documentation de votre version). Il résout donc le déclenchement et le flux de relecture, pas le code répété : on l'associe volontiers à Terragrunt ou à un autre générateur, plutôt que de l'y opposer.

Niveau 4 : les Stacks de HCP Terraform

HashiCorp a répondu au même problème avec les Stacks, une fonctionnalité de HCP Terraform : on décrit des composants (fichiers .tfcomponent.hcl, chacun référence un module avec ses entrées) et des déploiements (fichiers .tfdeploy.hcl, chacun duplique l'ensemble pour un environnement, une région ou un compte). La plateforme comprend les dépendances entre composants et gère les ordres d'application. Les Stacks ne s'exécutent pas hors de HCP Terraform, et la page consultée mentionne des limites par stack (20 déploiements, 100 composants, 10 000 ressources à la date de lecture) et l'indisponibilité sur d'anciennes offres.

Le raisonnement à tenir est celui de toute dépendance à une plateforme propriétaire : l'intégration est forte, la sortie est coûteuse. Pour les clients de Lyneko qui exigent un hébergement souverain, c'est souvent éliminatoire. Voyez-le comme un point de comparaison : les Stacks montrent la direction que prend l'orchestration (composants, déploiements, dépendances déclarées), une direction que Terragrunt et Terramate ont prise avant, hors plateforme.

OpenTofu : ce qui réduit le besoin d'outil

OpenTofu a levé plusieurs des frictions à l'origine de Terragrunt. La plus importante : depuis la version 1.8, on peut utiliser des variables et des valeurs locales dans le bloc backend et dans les sources et versions de modules, par une évaluation statique (les valeurs doivent être connues dès tofu init, avant tout état). Le backend de chaque couche peut alors s'écrire une fois :

variable "couche" {
  type = string
}

terraform {
  backend "s3" {
    bucket       = "signalements-tfstate-<suffixe>"
    key          = "${var.couche}/terraform.tfstate"
    region       = "fr-par"
    use_lockfile = true
    # endpoints et options skip_* comme dans le premier cours
  }
}

(d'après la documentation et les notes de version d'OpenTofu 1.8 ; non exécuté, OpenTofu n'étant pas installé). Terraform n'autorise pas cela dans le backend : sa clé s'écrit en dur, ou se passe par -backend-config à init, par exemple à partir d'un script. Un tableau honnête des écarts :

BesoinTerraform 1.16OpenTofu 1.8 et plus
Variables dans le backendnon (configuration partielle -backend-config)oui, évaluation statique
Variables dans la source d'un moduleoui depuis 1.15 (variables et locals)oui
Chiffrement de l'étatnonoui (leçon 7)

Cela ne remplace pas un orchestrateur : l'ordre et les sorties restent à résoudre. Mais cela supprime la répétition du backend sans générer de fichier.

Sous le capot

Le graphe entre états. Terraform construit un graphe de dépendances à l'intérieur d'une configuration. Entre configurations, il n'y a rien : chaque état est une île, et seul terraform_remote_state (ou une source de données) ose lire ailleurs. Un orchestrateur ajoute un second graphe, de niveau supérieur, dont les nœuds sont des configurations entières. Terragrunt le construit à partir des blocs dependency, Terramate des directives before et after, les Stacks des références entre composants. Les trois appliquent ensuite l'algorithme habituel : tri topologique, parallélisme sur les nœuds sans dépendance, arrêt à la première erreur.

Pourquoi des sorties factices. Un plan de l'application, avant le premier apply du réseau, ne peut pas lire une sortie qui n'existe pas. Soit on interdit ce plan (le pipeline applique le réseau d'abord), soit on lui donne des valeurs de remplacement pour qu'il passe la phase de validation, au prix d'un plan qui n'est pas fiable pour les ressources qui en dépendent. D'où la restriction des mock_outputs aux commandes validate et plan : sur apply, la sortie doit être réelle.

Génération de fichiers. Terragrunt et Terramate écrivent des fichiers (backend.tf, provider.tf) dans un répertoire de travail ; Terraform les lit comme n'importe quel fichier .tf. Un incident se diagnostique donc en regardant ce qui a été généré, pas seulement ce qui a été écrit.

Pièges courants

Orchestrer avant d'en avoir besoin. Un état unique de cinquante ressources n'a pas besoin de Terragrunt. L'outil ajoute de la complexité à une équipe qui n'avait pas le problème. Commencez par Make, et passez à l'outil quand une douleur précise l'impose.

Des sorties de couches comme contrat non écrit. Un renommage de sortie dans reseau casse application à son prochain plan. Traitez les sorties publiées comme une interface versionnée (leçon 2), avec des tests (leçon 5).

mock_outputs mal bornés. Des valeurs factices autorisées pour apply aboutissent à des ressources créées avec un identifiant bidon. Limitez-les à validate et plan.

Le cache de l'orchestrateur. Un cache périmé (.terragrunt-cache) fait exécuter une version de module qui n'est plus celle du code. Vider le cache, ou fixer la source à une version, est le premier réflexe quand « ça marche chez moi ».

Le parallélisme. run --all applique plusieurs unités à la fois, ce qui épuise les quotas de l'API ou entre en collision sur une ressource partagée. Limitez le parallélisme au besoin.

Une dépendance circulaire cachée. reseau qui lit une sortie de application pour ouvrir un port, alors que application lit reseau. Le graphe n'a plus d'ordre. La solution est dans la conception des couches : les dépendances ne vont que dans un sens.

Sécurité

  • Un orchestrateur a les droits de toutes les couches. run --all apply applique réseau, données et application avec une identité. C'est exactement ce que le découpage voulait éviter. Soit l'orchestrateur choisit l'identité par unité (un rôle par couche, injecté par la CI), soit l'orchestration n'est exécutée que pour plan, et chaque apply passe par son propre travail, avec son identité.
  • Les sorties de dépendances traversent les frontières. Un dependency lit toutes les sorties de l'état voisin, et l'état entier doit être lisible pour cela. Même enjeu que pour terraform_remote_state (leçon 7 du premier cours) : n'exposez pas de secret en sortie (voir la leçon 7 de ce cours).
  • Un outil de plus est une chaîne d'approvisionnement de plus. Épinglez la version de l'outil, vérifiez la somme de contrôle du binaire, et traitez ses mises à jour comme celles de Terraform (leçon 10).
  • Les fichiers générés ne sont pas relus. Si la CI génère le backend, une modification du générateur change tous les états d'un coup. Le dépôt de configuration racine se protège comme le dépôt de politiques de la leçon 6 : propriétaires de code, revue obligatoire.

En production

Les critères de choix. Cinq questions, dans cet ordre :

  1. Combien d'états ? Moins de dix, un Makefile et une CI bien faite suffisent. Au-delà, les copier-coller et l'ordre deviennent un risque.
  2. Combien de personnes et d'équipes ? Une seule équipe peut garder un outil léger ; plusieurs équipes ont besoin de conventions imposées (stacks, gabarits).
  3. Quel flux de relecture ? Si les plans passent déjà par la CI du forge, un orchestrateur de ligne de commande suffit ; sinon, Atlantis ou une plateforme.
  4. Quelle contrainte de souveraineté ? Un client qui interdit un service hébergé hors de l'Union européenne exclut HCP Terraform ; Terragrunt, Terramate et Atlantis s'exécutent chez vous.
  5. Terraform ou OpenTofu ? OpenTofu résout une partie de la répétition (backend) et le chiffrement de l'état ; Terragrunt et Terramate fonctionnent avec les deux.

Une trajectoire raisonnable pour Signalements. Un état d'abord ; un découpage en trois couches quand les droits l'exigent (leçon 8) ; un Makefile et la CI pour l'ordre ; Terragrunt ou Terramate quand le nombre d'environnements et de couches rend le Makefile pénible ; Atlantis si l'équipe veut le flux « commentaire dans la demande de fusion ». Chaque marche répond à une douleur observée.

Garder l'issue de secours. Une configuration qui reste du Terraform ordinaire (modules, variables, backend) se déplace d'un orchestrateur à l'autre. Une configuration qui s'est écrite dans le langage d'un orchestrateur (blocs dependency, generate) est plus coûteuse à quitter. Gardez les modules sans connaissance de l'outil qui les appelle.

Observer. Quand une orchestration applique dix couches en parallèle, on veut voir laquelle a échoué, avec le plan et le journal. Sortie structurée (-json), journaux par couche, et alerte sur une exécution planifiée qui échoue : sinon, une couche cesse d'être appliquée sans que personne le sache.

Exercices

Exercice 1 : identifier la douleur

Pour chaque situation, nommez le problème (ordre, sorties partagées, code répété, déclenchement) et l'outil le plus léger qui le résout : (a) la clé du backend de prod/donnees a été copiée de preprod/donnees et écrase son état ; (b) une demande de fusion modifie modules/reseau, la CI planifie les quarante répertoires ; (c) le plan de application échoue : « Unsupported attribute » sur la sortie de reseau, qui n'a pas encore été appliquée ; (d) la destruction de preprod a échoué car reseau a été détruit avant application.

Solution

(a) Code répété : génération du backend (Terragrunt remote_state avec generate, Terramate generate_hcl), ou variables dans le backend avec OpenTofu 1.8, ou -backend-config calculé par un script. (b) Déclenchement : détection de changements de Terramate (--changed), ou règles de chemins dans la CI (au minimum). (c) Ordre et sorties partagées : appliquer reseau d'abord (Makefile ordonné), mock_outputs limités à validate et plan avec Terragrunt. (d) Ordre : un orchestrateur qui détruit à l'envers (Terragrunt run --all destroy, Terramate dans l'ordre inverse), ou un second Makefile qui boucle sur les couches dans l'autre sens.

Exercice 2 : étendre le Makefile

Modifiez le Makefile de la leçon pour ajouter une cible destroy qui détruit dans l'ordre inverse, et dites ce qui reste impossible avec ce Makefile.

Solution
COUCHES_INVERSE := application reseau

.PHONY: destroy
destroy:
	@set -e; for c in $(COUCHES_INVERSE); do \
	  echo "== $$c"; \
	  if [ "$$c" = application ]; then export TF_VAR_cidr_reseau=$$(terraform -chdir=reseau output -raw cidr); fi; \
	  terraform -chdir=$$c destroy -input=false -no-color -auto-approve | grep -E "Destroy complete|No changes"; \
	done

On garde l'ordre inversé et la même variable pour que application trouve sa valeur. Il reste impossible, ou pénible : appliquer un plan enregistré couche par couche (le plan de application dépend d'une sortie qui n'existe pas avant l'apply de reseau), paralléliser les couches indépendantes, ne traiter que les couches touchées par une modification, et gérer des identités distinctes par couche. Ce sont les points où un outil dédié commence à se justifier.

Exercice 3 : un choix argumenté

Lyneko gère Signalements (trois couches, deux environnements) et un second client (quatre couches, trois environnements, hébergement exigé en France, équipe de quatre personnes). Recommandez une approche pour le second client, en citant au moins deux critères de la leçon.

Solution

Douze états au total pour le second client : le nombre dépasse ce qu'un Makefile gère confortablement, et la répétition du backend est un risque. Terragrunt ou Terramate (libres, exécutables chez le client) apportent la génération du backend et l'ordre déclaré ; avec OpenTofu 1.8 ou plus, la clé de backend peut aussi se paramétrer sans générateur. Le critère de souveraineté exclut les Stacks de HCP Terraform. L'équipe de quatre personnes plaide pour un outil léger et lisible : Terramate, qui génère du Terraform ordinaire, ou Terragrunt si l'équipe accepte un second niveau de configuration. Le flux de relecture peut rester la CI du forge ; Atlantis est une option si le client veut le plan commenté dans les demandes de fusion. On écrit la décision et ses raisons, et on garde les modules indépendants de l'outil choisi.

Récapitulatif

  • Découper en états crée trois problèmes : l'ordre, les sorties partagées et le code répété (le backend ne peut pas utiliser de variable avec Terraform), plus le déclenchement quand les répertoires se multiplient.
  • Un Makefile ou un script suffit longtemps ; il ne détruit pas à l'envers, ne parallélise pas, ne sait pas planifier avant l'apply d'une dépendance.
  • Terragrunt : unités, dependency avec mock_outputs limités à validate et plan, backend généré, run --all. Terramate : stacks, détection de changements, génération de Terraform ordinaire. Atlantis : flux de relecture par commentaire. Stacks de HCP Terraform : composants et déploiements, dans la plateforme.
  • OpenTofu autorise les variables dans le backend (1.8) et chiffre l'état (leçon 7) ; cela réduit la répétition, pas l'ordre.
  • Le choix se fait sur le nombre d'états, la taille de l'équipe, le flux de relecture, la souveraineté et Terraform ou OpenTofu ; on n'adopte l'outil que face à une douleur précise.
  • Un orchestrateur concentre les droits et la chaîne d'approvisionnement : identités par couche, versions épinglées, fichiers de configuration relus.

Pour aller plus loin

  • La documentation de Terragrunt (unités, stacks, dependency, remote_state, run --all) et son catalogue d'exemples d'infrastructure.
  • La documentation de la CLI de Terramate (détection de changements, génération de code, ordonnancement).
  • La documentation des Stacks de HCP Terraform, comme point de comparaison.
  • Les notes de version d'OpenTofu 1.8 sur l'évaluation statique et le chapitre 8 de Terraform: Up & Running sur le flux d'équipe.
  • La leçon 8 pour le découpage lui-même, et la leçon 10 pour mettre à jour l'outil d'orchestration avec le reste. Un cours sur la plateforme d'ingénierie interne (à venir) reprendra l'orchestration du point de vue des équipes.
Voir ma constellation →

Sources