Pourquoi nous utilisons Terraform et non Chef, Puppet, Ansible, SaltStack ou CloudFormation

Mise à jour, 17 novembre 2016: Nous avons pris cette série d’articles de blog, l’avons étendue et l’avons transformée en un livre intitulé Terraform:Up&En cours d’exécution!

Mise à jour, 8 juillet 2019: Nous avons mis à jour cette série d’articles de blog pour Terraform 0.12 et publié la 2ème édition de Terraform:Up& En cours d’exécution!

Ceci est la partie 1 du Guide complet de la série Terraform. Dans l’introduction à la série, nous avons discuté des raisons pour lesquelles chaque entreprise devrait utiliser l’infrastructure en tant que code (IAC). Dans cet article, nous allons discuter des raisons pour lesquelles nous avons choisi Terraform comme notre outil IAC de choix.

Si vous recherchez sur Internet « infrastructure-as-code », il est assez facile de trouver une liste des outils les plus populaires:

  • Chef
  • Puppet
  • Ansible
  • SaltStack
  • CloudFormation
  • Terraform

Ce qui n’est pas facile, c’est de déterminer lequel de ceux-ci vous devez utiliser. Tous ces outils peuvent être utilisés pour gérer l’infrastructure sous forme de code. Tous sont open source, soutenus par de grandes communautés de contributeurs, et travaillent avec de nombreux fournisseurs de cloud (à l’exception notable de CloudFormation, qui est source fermée et AWS uniquement). Tous offrent un soutien aux entreprises. Tous sont bien documentés, à la fois en termes de documentation officielle et de ressources communautaires telles que les articles de blog et les questions StackOverflow. Alors, comment décidez-vous?

Ce qui rend cela encore plus difficile, c’est que la plupart des comparaisons que vous trouvez en ligne entre ces outils ne font guère plus que répertorier les propriétés générales de chaque outil et donner l’impression que vous pourriez réussir avec n’importe lequel d’entre eux. Et bien que ce soit techniquement vrai, ce n’est pas utile. C’est un peu comme dire à un débutant en programmation que vous pourriez réussir à créer un site Web avec PHP, C ou Assembly — une déclaration techniquement vraie, mais qui omet une énorme quantité d’informations qui seraient incroyablement utiles pour prendre une bonne décision.

Dans cet article, nous allons nous plonger dans des raisons très spécifiques pour lesquelles nous avons choisi Terraform par rapport aux autres outils IAC. Comme pour toutes les décisions technologiques, il s’agit de compromis et de priorités, et même si vos priorités particulières peuvent être différentes des nôtres, nous espérons que le partage de notre processus de réflexion vous aidera à prendre votre propre décision. Voici les principaux compromis que nous avons considérés:

  • Gestion de la configuration vs Provisioning
  • Infrastructure Mutable vs Infrastructure Immuable
  • Procédural vs Déclaratif
  • Master vs Masterless
  • Agent vs Sans Agent
  • Grande Communauté vs Petite Communauté
  • Mature vs Tranchant
  • Utilisant plusieurs outils ensemble

Chef, Puppet, Ansible et SaltStack sont tous des outils de gestion de la configuration, qui signifie qu’ils sont conçus pour installer et gérer des logiciels sur des serveurs existants. CloudFormation et Terraform sont des outils de provisionnement, ce qui signifie qu’ils sont conçus pour provisionner les serveurs eux-mêmes (ainsi que le reste de votre infrastructure, comme les équilibreurs de charge, les bases de données, la configuration réseau, etc.), laissant la tâche de configurer ces serveurs à d’autres outils. Ces deux catégories ne s’excluent pas mutuellement, car la plupart des outils de gestion de la configuration peuvent effectuer un certain degré de provisionnement et la plupart des outils de provisionnement peuvent effectuer un certain degré de gestion de la configuration. Mais l’accent mis sur la gestion de la configuration ou le provisionnement signifie que certains outils seront mieux adaptés à certains types de tâches.

En particulier, nous avons constaté que si vous utilisez Docker ou Packer, la grande majorité de vos besoins en gestion de configuration sont déjà pris en charge. Avec Docker et Packer, vous pouvez créer des images (telles que des conteneurs ou des images de machines virtuelles) sur lesquelles tous les logiciels dont votre serveur a besoin sont déjà installés et configurés. Une fois que vous avez une telle image, tout ce dont vous avez besoin est un serveur pour l’exécuter. Et si tout ce que vous avez à faire est de provisionner un tas de serveurs, un outil de provisionnement comme Terraform conviendra généralement mieux qu’un outil de gestion de configuration (voici un exemple d’utilisation de Terraform pour déployer Docker sur AWS).

Infrastructure Mutable vs Infrastructure immuable

Les outils de gestion de configuration tels que Chef, Puppet, Ansible et SaltStack utilisent généralement par défaut un paradigme d’infrastructure mutable. Par exemple, si vous demandez à Chef d’installer une nouvelle version d’OpenSSL, il exécutera la mise à jour logicielle sur vos serveurs existants et les modifications se produiront sur place. Au fil du temps, à mesure que vous appliquez de plus en plus de mises à jour, chaque serveur construit un historique unique de modifications. Cela conduit souvent à un phénomène appelé dérive de configuration, où chaque serveur devient légèrement différent de tous les autres, conduisant à de subtils bugs de configuration difficiles à diagnostiquer et presque impossibles à reproduire.

Si vous utilisez un outil de provisionnement tel que Terraform pour déployer des images de machine créées par Docker ou Packer, chaque « modification » est en fait un déploiement d’un nouveau serveur (tout comme chaque ”modification » d’une variable dans la programmation fonctionnelle renvoie en fait une nouvelle variable). Par exemple, pour déployer une nouvelle version d’OpenSSL, vous devez créer une nouvelle image à l’aide de Packer ou Docker avec la nouvelle version d’OpenSSL déjà installée, déployer cette image sur un ensemble de serveurs totalement nouveaux, puis annuler la destruction des anciens serveurs. Cette approche réduit la probabilité de bogues de dérive de configuration, permet de savoir plus facilement quel logiciel s’exécute sur un serveur et vous permet de déployer de manière triviale n’importe quelle version précédente du logiciel à tout moment. Bien sûr, il est possible de forcer les outils de gestion de configuration à effectuer des déploiements immuables, mais ce n’est pas l’approche idiomatique de ces outils, alors que c’est un moyen naturel d’utiliser les outils de provisionnement.

Procédural vs Déclaratif

Chef et Ansible encouragent un style procédural où vous écrivez du code qui spécifie, étape par étape, comment atteindre l’état final souhaité. Terraform, CloudFormation, SaltStack et Puppet encouragent tous un style plus déclaratif où vous écrivez du code qui spécifie l’état final souhaité, et l’outil IAC lui-même est responsable de déterminer comment atteindre cet état.

Par exemple, supposons que vous vouliez déployer 10 serveurs ( » instances EC2 ” dans AWS lingo) pour exécuter la version 1 d’une application. Voici un exemple simplifié d’un modèle Ansible qui le fait avec une approche procédurale:

- ec2:
count: 10
image: ami-v1
instance_type: t2.micro

Et voici un exemple simplifié d’un modèle Terraform qui fait la même chose en utilisant une approche déclarative:

resource "aws_instance" "example" {
count = 10
ami = "ami-v1"
instance_type = "t2.micro"
}

Maintenant à la surface, ces deux approches peuvent sembler similaires, et lorsque vous les exécutez initialement avec Ansible ou Terraform, ils produiront des résultats similaires. Ce qui est intéressant, c’est ce qui se passe lorsque vous voulez faire un changement.

Par exemple, imaginez que le trafic a augmenté et que vous souhaitez augmenter le nombre de serveurs à 15. Avec Ansible, le code de procédure que vous avez écrit plus tôt n’est plus utile ; si vous venez de mettre à jour le nombre de serveurs à 15 et de réexaminer ce code, il déploierait 15 nouveaux serveurs, ce qui vous donnerait un total de 25 ! Donc, à la place, vous devez être conscient de ce qui est déjà déployé et écrire un script procédural totalement nouveau pour ajouter les 5 nouveaux serveurs:

- ec2:
count: 5
image: ami-v1
instance_type: t2.micro

Avec un code déclaratif, puisque tout ce que vous faites est de déclarer l’état final que vous voulez et que Terraform détermine comment atteindre cet état final, Terraform sera également au courant de tout état qu’il a créé dans le passé. Par conséquent, pour déployer 5 serveurs supplémentaires, il vous suffit de revenir au même modèle Terraform et de mettre à jour le nombre de 10 à 15 :

resource "aws_instance" "example" {
count = 15
ami = "ami-v1"
instance_type = "t2.micro"
}

Si vous exécutiez ce modèle, Terraform se rendrait compte qu’il avait déjà créé 10 serveurs et donc qu’il ne restait plus qu’à créer 5 nouveaux serveurs. En fait, avant d’exécuter ce modèle, vous pouvez utiliser la commande plan de Terraform pour prévisualiser les modifications qu’il apporterait :

$ terraform plan+ aws_instance.example.11
ami: "ami-v1"
instance_type: "t2.micro"+ aws_instance.example.12
ami: "ami-v1"
instance_type: "t2.micro"+ aws_instance.example.13
ami: "ami-v1"
instance_type: "t2.micro"+ aws_instance.example.14
ami: "ami-v1"
instance_type: "t2.micro"+ aws_instance.example.15
ami: "ami-v1"
instance_type: "t2.micro"Plan: 5 to add, 0 to change, 0 to destroy.

Que se passe-t-il maintenant lorsque vous souhaitez déployer v2 le service ? Avec l’approche procédurale, vos deux modèles Ansible précédents ne sont à nouveau pas utiles, vous devez donc écrire un autre modèle pour retrouver les 10 serveurs que vous avez déployés précédemment (ou était-ce 15 maintenant?) et mettez soigneusement chacun à jour vers la nouvelle version. Avec l’approche déclarative de Terraform, vous revenez exactement au même modèle et changez simplement le numéro de version de l’ami en v2:

resource "aws_instance" "example" {
count = 15
ami = "ami-v2"
instance_type = "t2.micro"
}

Évidemment, les exemples ci-dessus sont simplifiés. Ansible vous permet d’utiliser des balises pour rechercher des instances EC2 existantes avant d’en déployer de nouvelles (par exemple, en utilisant les paramètres instance_tags et count_tag), mais avoir à comprendre manuellement ce type de logique pour chaque ressource que vous gérez avec Ansible, en fonction de l’historique passé de chaque ressource, peut être étonnamment compliqué (par exemple recherche d’instances existantes non seulement par balise, mais aussi par version d’image, zone de disponibilité, etc.). Cela met en évidence deux problèmes majeurs avec les outils IAC procéduraux:

  1. Lorsqu’il s’agit de code procédural, l’état de l’infrastructure n’est pas entièrement capturé dans le code. La lecture des trois modèles Ansible que nous avons créés ci-dessus ne suffit pas pour savoir ce qui est déployé. Vous devez également connaître l’ordre dans lequel nous avons appliqué ces modèles. Si nous les avions appliqués dans un ordre différent, nous pourrions nous retrouver avec une infrastructure différente, et ce n’est pas quelque chose que vous pouvez voir dans la base de code elle-même. En d’autres termes, pour raisonner sur une base de code Ansible ou Chef, vous devez connaître l’historique complet de chaque changement qui s’est produit.
  2. La réutilisabilité du code procédural est intrinsèquement limitée car vous devez tenir compte manuellement de l’état actuel de la base de code. Comme cet état est en constante évolution, le code que vous avez utilisé il y a une semaine peut ne plus être utilisable car il a été conçu pour modifier un état de votre infrastructure qui n’existe plus. En conséquence, les bases du code de procédure ont tendance à devenir volumineuses et compliquées avec le temps.

D’autre part, avec le type d’approche déclarative utilisée dans Terraform, le code représente toujours le dernier état de votre infrastructure. En un coup d’œil, vous pouvez savoir ce qui est actuellement déployé et comment il est configuré, sans avoir à vous soucier de l’historique ou du calendrier. Cela facilite également la création de code réutilisable, car vous n’avez pas à tenir compte manuellement de l’état actuel du monde. Au lieu de cela, vous vous concentrez simplement sur la description de l’état souhaité et Terraform détermine comment passer automatiquement d’un état à l’autre. En conséquence, les bases de code Terraform ont tendance à rester petites et faciles à comprendre.

Bien sûr, il y a aussi des inconvénients aux langages déclaratifs. Sans accès à un langage de programmation complet, votre puissance expressive est limitée. Par exemple, certains types de changements d’infrastructure, tels qu’un déploiement continu sans temps d’arrêt, sont difficiles à exprimer en termes purement déclaratifs. De même, sans la possibilité de faire de la « logique” (par exemple, des instructions if, des boucles), la création de code générique réutilisable peut être délicate (en particulier dans CloudFormation). Heureusement, Terraform fournit un certain nombre de primitives puissantes, telles que les variables d’entrée, les variables de sortie, les modules, create_before_destroy, et count, qui permettent de créer du code propre, configurable et modulaire, même dans un langage déclaratif. Nous discuterons plus en détail de ces outils dans la partie 4, Comment créer une infrastructure réutilisable avec des modules Terraform et dans la partie 5, Astuces de Terraform &: boucles, instructions if et pièges.

Master Versus Masterless

Par défaut, Chef, Puppet et SaltStack nécessitent tous d’exécuter un serveur maître pour stocker l’état de votre infrastructure et distribuer les mises à jour. Chaque fois que vous souhaitez mettre à jour quelque chose dans votre infrastructure, vous utilisez un client (par exemple, un outil de ligne de commande) pour émettre de nouvelles commandes au serveur maître, et le serveur maître envoie les mises à jour à tous les autres serveurs, ou ces serveurs extraient régulièrement les dernières mises à jour du serveur maître.

Un serveur maître offre quelques avantages. Tout d’abord, il s’agit d’un endroit unique et central où vous pouvez voir et gérer l’état de votre infrastructure. De nombreux outils de gestion de configuration fournissent même une interface Web (par exemple, la console Chef, la console Puppet Enterprise) pour le serveur maître afin de faciliter la visualisation de ce qui se passe. Deuxièmement, certains serveurs maîtres peuvent fonctionner en continu en arrière-plan et appliquer votre configuration. De cette façon, si quelqu’un effectue une modification manuelle sur un serveur, le serveur maître peut annuler cette modification pour éviter toute dérive de configuration.

Cependant, le fait de devoir exécuter un serveur maître présente de sérieux inconvénients:

  • Infrastructure supplémentaire : Vous devez déployer un serveur supplémentaire, voire un cluster de serveurs supplémentaires (pour une haute disponibilité et une évolutivité), juste pour exécuter le maître.
  • Maintenance : Vous devez maintenir, mettre à niveau, sauvegarder, surveiller et mettre à l’échelle le(s) serveur(s) maître(s).
  • Sécurité: Vous devez fournir au client un moyen de communiquer avec le (s) serveur(s) maître (s) et un moyen pour le (s) serveur (s) maître (s) de communiquer avec tous les autres serveurs, ce qui signifie généralement ouvrir des ports supplémentaires et configurer des systèmes d’authentification supplémentaires, ce qui augmente votre surface pour les attaquants.

Chef, Puppet et SaltStack ont différents niveaux de support pour les modes sans maître où vous exécutez simplement leur logiciel agent sur chacun de vos serveurs, généralement selon un calendrier périodique (par exemple, un travail cron qui s’exécute toutes les 5 minutes), et utilisez-le pour extraire les dernières mises à jour du contrôle de version (plutôt que d’un serveur maître). Cela réduit considérablement le nombre de pièces mobiles, mais, comme discuté dans la section suivante, cela laisse encore un certain nombre de questions
sans réponse, en particulier sur la façon de provisionner les serveurs et d’installer le logiciel de l’agent sur eux en premier lieu.

Ansible, CloudFormation, Heat et Terraform sont tous sans maître par défaut. Ou, pour être plus précis, certains d’entre eux peuvent s’appuyer sur un serveur maître, mais cela fait déjà partie de l’infrastructure que vous utilisez et non une pièce supplémentaire que vous devez gérer. Par exemple, Terraform communique avec les fournisseurs de cloud à l’aide des API du fournisseur de cloud, donc dans un certain sens, les serveurs d’API sont des serveurs maîtres, sauf qu’ils ne nécessitent aucune infrastructure supplémentaire ou aucun mécanisme d’authentification supplémentaire (c’est-à-dire, utilisez simplement vos clés d’API). Ansible fonctionne en se connectant directement à chaque serveur via SSH, donc encore une fois, vous n’avez pas à exécuter d’infrastructure supplémentaire ou à gérer des mécanismes d’authentification supplémentaires (c’est-à-dire, utilisez simplement vos clés SSH).

Agent Par rapport à Agentless

Chef, Puppet et SaltStack nécessitent tous l’installation d’un logiciel d’agent (par exemple, Client Chef, Agent Puppet, Salt Minion) sur chaque serveur que vous souhaitez configurer. L’agent s’exécute généralement en arrière-plan sur chaque serveur et est responsable de l’installation des dernières mises à jour de gestion de la configuration.

Ceci présente quelques inconvénients :

  • Amorçage: Comment provisionnez-vous vos serveurs et installez-vous le logiciel agent sur eux en premier lieu? Certains outils de gestion de la configuration donnent le coup d’envoi, en supposant qu’un processus externe s’en chargera pour eux (par exemple, vous utilisez d’abord Terraform pour déployer un groupe de serveurs avec une image de machine virtuelle sur laquelle l’agent est déjà installé) ; d’autres outils de gestion de la configuration ont un processus d’amorçage spécial dans lequel vous exécutez des commandes uniques pour provisionner les serveurs à l’aide des API du fournisseur de cloud et installer le logiciel de l’agent sur ces serveurs via SSH.
  • Entretien: Vous devez soigneusement mettre à jour le logiciel de l’agent sur une base périodique, en prenant soin de le garder synchronisé avec le serveur maître s’il y en a un. Vous devez également surveiller le logiciel de l’agent et le redémarrer s’il se bloque.
  • Sécurité : Si le logiciel de l’agent supprime la configuration d’un serveur maître (ou d’un autre serveur si vous n’utilisez pas de serveur maître), vous devez ouvrir les ports sortants sur chaque serveur. Si le serveur maître transmet la configuration à l’agent, vous devez ouvrir les ports entrants sur chaque serveur. Dans les deux cas, vous devez trouver comment authentifier l’agent auprès du serveur auquel il parle. Tout cela augmente votre surface pour les attaquants.

Une fois de plus, Chef, Puppet et SaltStack ont différents niveaux de support pour les modes sans agent (par exemple, salt-ssh), mais ceux-ci ont souvent l’impression d’avoir été utilisés après coup et ne prennent pas toujours en charge l’ensemble des fonctionnalités de l’outil de gestion de la configuration. C’est pourquoi dans la nature, la configuration par défaut ou idiomatique pour Chef, Puppet et SaltStack comprend presque toujours un agent, et généralement un maître aussi.

Toutes ces pièces mobiles supplémentaires introduisent un grand nombre de nouveaux modes de défaillance dans votre infrastructure. Chaque fois que vous recevez un rapport de bogue à 3 heures du matin, vous devrez déterminer s’il s’agit d’un bogue dans votre code d’application, ou votre code IAC, ou le client de gestion de la configuration, ou le(s) serveur(s) maître(s), ou la façon dont le client parle au(x) serveur(s) maître(s), ou la façon dont les autres serveurs parlent au(x) serveur(s) maître(s), ouAn

Ansible, CloudFormation, Heat et Terraform ne nécessitent pas l’installation d’agents supplémentaires. Ou, pour être plus précis, certains d’entre eux nécessitent des agents, mais ceux-ci sont généralement déjà installés dans le cadre de l’infrastructure que vous utilisez. Par exemple, AWS, Azure, Google Cloud et tous les autres fournisseurs de cloud s’occupent de l’installation, de la gestion et de l’authentification des logiciels d’agent sur chacun de leurs serveurs physiques. En tant qu’utilisateur de Terraform, vous n’avez pas à vous soucier de tout cela : vous émettez simplement des commandes et les agents du fournisseur de cloud les exécutent pour vous sur tous vos serveurs. Avec Ansible, vos serveurs doivent exécuter
le démon SSH, qui est de toute façon courant sur la plupart des serveurs.

Grande Communauté vs Petite Communauté

Chaque fois que vous choisissez une technologie, vous choisissez également une communauté. Dans de nombreux cas, l’écosystème autour du projet peut avoir un impact plus important sur votre expérience que la qualité inhérente à la technologie elle-même. La communauté détermine combien de personnes contribuent au projet, combien de plug-ins, d’intégrations et d’extensions sont disponibles, à quel point il est facile de trouver de l’aide en ligne (par exemple, des articles de blog, des questions sur StackOverflow) et à quel point il est facile d’embaucher quelqu’un pour vous aider (par exemple, un employé, un consultant ou une entreprise de support).

Il est difficile de faire une comparaison précise entre les communautés, mais vous pouvez repérer certaines tendances en effectuant une recherche en ligne. Le tableau ci-dessous montre une comparaison des outils IAC populaires, avec les données que j’ai recueillies en mai 2019, notamment si l’outil IAC est open source ou open source, quels fournisseurs de cloud il prend en charge, le nombre total de contributeurs et d’étoiles sur GitHub, le nombre de commits et de problèmes actifs sur une période d’un mois de mi-avril à mi-mai, le nombre de bibliothèques open source disponibles pour l’outil, le nombre de questions répertoriées pour cet outil sur StackOverflow et le nombre de tâches qui mentionnent l’outil sur Indeed.com .

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *