web-dev-qa-db-fra.com

Meilleures pratiques lors de l'utilisation de Terraform

Je suis en train de permuter notre infrastructure en terraform .. Quelle est la meilleure pratique pour gérer réellement les fichiers terraform et leur état? Je réalise que c'est une infrastructure en tant que code et je vais valider mes fichiers .tf git, mais est-ce que je commets aussi tfstate? Cela devrait-il résider quelque part comme S3? Je souhaiterais éventuellement que CI gère tout cela, mais c’est très difficile et cela me demande de trouver les pièces en mouvement pour les fichiers.

Je cherche vraiment à voir comment les gens utilisent réellement ce genre de choses dans la production

68
Marc Young

Nous utilisons beaucoup Terraform et notre configuration recommandée est la suivante:

Disposition du fichier

Nous vous recommandons vivement de stocker le code Terraform pour chacun de vos environnements (par exemple, stage, prod, qa) dans des ensembles distincts de modèles (et par conséquent, des fichiers .tfstate séparés). Cela est important pour que vos environnements distincts soient réellement isolés les uns des autres lors de modifications. Sinon, tout en jouant avec du code dans la mise en scène, il est trop facile de faire sauter quelque chose en prod. Voir Terraform, VPC et pourquoi vous voulez un fichier tfstate par env pour une discussion en couleur de pourquoi.

Par conséquent, notre disposition de fichier typique ressemble à ceci:

stage
  └ main.tf
  └ vars.tf
  └ outputs.tf
prod
  └ main.tf
  └ vars.tf
  └ outputs.tf
global
  └ main.tf
  └ vars.tf
  └ outputs.tf

Tout le code Terraform du VPC de scène est placé dans le dossier stage, tout le code du VPC prod est placé dans le dossier prod et tout le code qui réside en dehors d’un VPC (utilisateurs IAM, sujets SNS, compartiments S3, par exemple) le dossier global.

Notez que, par convention, nous divisons généralement notre code Terraform en 3 fichiers:

  • vars.tf: variables d'entrée.
  • outputs.tf: variables de sortie.
  • main.tf: les ressources réelles.

Modules

En règle générale, nous définissons notre infrastructure dans deux dossiers: 

  1. infrastructure-modules: Ce dossier contient de petits modules versionnés réutilisables. Considérez chaque module comme un modèle de création d’un élément d’infrastructure unique, tel qu’un VPC ou une base de données.
  2. infrastructure-live: ce dossier contient l’infrastructure réelle et en cours d’exécution qu’il crée en combinant les modules dans infrastructure-modules. Pensez au code de ce dossier comme aux maisons que vous avez construites à partir de vos plans.

Un module Terraform correspond à n’importe quel jeu de modèles Terraform dans un dossier. Par exemple, nous pourrions avoir un dossier appelé vpc dans infrastructure-modules qui définit toutes les tables de routage, sous-réseaux, passerelles, ACL, etc. pour un seul VPC:

infrastructure-modules
  └ vpc
    └ main.tf
    └ vars.tf
    └ outputs.tf

Nous pouvons ensuite utiliser ce module dans infrastructure-live/stage et infrastructure-live/prod pour créer la scène et produire des VPC. Par exemple, voici à quoi pourrait ressembler infrastructure-live/stage/main.tf:

module "stage_vpc" {
  source = "git::[email protected]:gruntwork-io/module-vpc.git//modules/vpc-app?ref=v0.0.4"

  vpc_name         = "stage"
  aws_region       = "us-east-1"
  num_nat_gateways = 3
  cidr_block       = "10.2.0.0/18"
}

Pour utiliser un module, vous utilisez la ressource module et pointez son champ source sur un chemin local de votre disque dur (par exemple source = "../infrastructure-modules/vpc") ou, comme dans l'exemple ci-dessus, sur une URL Git (voir sources du module ). L’avantage de l’URL Git est que nous pouvons spécifier un git sha1 ou une balise spécifique (ref=v0.0.4). Désormais, non seulement nous définissons notre infrastructure comme un ensemble de petits modules, mais nous pouvons également les mettre à la version et les mettre à jour ou les restaurer avec précaution selon les besoins.

Nous avons créé un certain nombre de Packages d'infrastructure réutilisables, testés et documentés, permettant de créer des VPC, des clusters Docker, des bases de données, etc.

Etat

Lorsque vous utilisez Terraform pour créer des ressources (par exemple, instances EC2, bases de données, VPC), il enregistre des informations sur ce qu'il a créé dans un fichier .tfstate. Pour modifier ces ressources, tous les membres de votre équipe doivent avoir accès à ce même fichier .tfstate, mais vous ne devez PAS l'archiver dans Git (voir ici pour une explication de la raison ). 

Au lieu de cela, nous vous recommandons de stocker les fichiers .tfstate dans S3 en activant Terraform Remote State , qui enverra/extraira automatiquement les fichiers les plus récents à chaque exécution de Terraform. Assurez-vous de activer le contrôle de version dans votre compartiment S3 afin de pouvoir restaurer les fichiers .tfstate plus anciens au cas où vous corrompriez la dernière version. Cependant, une remarque importante: Terraform ne fournit pas de verrouillage. Ainsi, si deux membres de l'équipe exécutent terraform apply en même temps sur le même fichier .tfstate, ils risquent de remplacer les modifications apportées.

Pour résoudre ce problème, nous avons créé un outil open source appelé Terragrunt , qui est un wrapper fin pour Terraform qui utilise Amazon DynamoDB pour fournir un verrouillage (qui devrait être totalement gratuit pour la plupart des équipes). Check out Ajoutez le verrouillage et la configuration automatiques de l'état à distance à Terraform avec Terragrunt pour plus d'informations.

Lectures complémentaires

Nous venons de commencer une série de billets de blog intitulée Un guide complet de Terraform qui décrit en détail toutes les meilleures pratiques que nous avons apprises lors de l’utilisation de Terraform dans le monde réel.

Mise à jour: la série d'articles sur le guide complet de Terraform est devenue si populaire que nous l'avons développée dans un livre intitulé Terraform: Up & Running!

68
Yevgeniy Brikman

Auparavant, remote config autorisait cela, mais a maintenant été remplacé par " backends ", donc terraform remote n'est plus disponible.

terraform remote config -backend-config="bucket=<s3_bucket_to_store_tfstate>" -backend-config="key=terraform.tfstate" -backend=s3
terraform remote pull
terraform apply
terraform remote Push

Voir le docs pour plus de détails.

9
Shantanu

Couvert de manière plus approfondie par @Yevgeny Brikman mais répondant spécifiquement aux questions du PO:

Quelle est la meilleure pratique pour gérer réellement les fichiers et l'état terraform?

Utilisez git pour les fichiers TF. Mais ne pas archiver les fichiers d’État (c’est-à-dire tfstate). Utilisez plutôt Terragrunt pour synchroniser/verrouiller les fichiers d’état vers S3.

mais est-ce que je commets aussi tfstate? 

Non. 

Cela devrait-il résider quelque part comme S3?

Oui

4
Snowcrash

Je sais qu’il ya beaucoup de réponses ici, mais mon approche est très différente. 

⁃   Modules
⁃   Environment management 
⁃   Separation of duties

Modules

  1. Créez des modules pour des collections logiques de ressources. Exemple: Si votre objectif est de déployer une API, qui requiert une base de données, des machines virtuelles haute disponibilité, une mise à l'échelle automatique, DNS, PubSub et un stockage d'objet, toutes ces ressources doivent être modélisées dans un seul module. 
  2. Évitez de créer des modules qui utilisent une seule ressource. Cela peut et a été fait et de nombreux modules du registre le font, mais c’est une pratique qui facilite l’accès aux ressources plutôt que l’infrastructure orchestration. Exemple: Un module pour AWS EC2 aide l'utilisateur à accéder à EC2 en simplifiant l'appel de configurations complexes, mais un module similaire à l'exemple de 1. aide l'utilisateur à orchestrer une infrastructure pilotée par une application, un composant ou un service.
    1. Évitez les déclarations de ressources dans votre espace de travail. Il s’agit plus de garder votre code bien rangé et organisé. Comme les modules sont facilement versionnés, vous avez plus de contrôle sur vos versions. 

Gestion de l'environnement

IaC a rendu le processus SDLC pertinent pour la gestion de l’infrastructure et il n’est pas normal de s’attendre à disposer d’une infrastructure de développement ainsi que d’environnements d’applications de développement. 

  1. N’utilisez pas de dossiers pour gérer vos environnements IaC. Cela conduit à la dérive car il n'y a pas de modèle commun pour votre infrastructure. 
  2. Utilisez un seul espace de travail et des variables pour contrôler les spécifications de l'environnement. Exemple: écrivez vos modules de manière à ce que, lorsque vous modifiez la variable d'environnement (var.stage est populaire), le plan s'adapte à vos besoins. En règle générale, les environnements doivent varier le moins possible avec la quantité, l'exposition et la capacité étant généralement des configurations variables. Dev peut déployer 1 VM avec 1 cœur et 1 Go RAM dans une topologie privée, mais la production peut être constituée de 3 machines virtuelles à 2 cœurs et de 4 Go RAM avec une topologie publique supplémentaire. Vous pouvez bien sûr avoir plus de variations: dev peut exécuter le processus de base de données sur le même serveur que l'application pour réduire les coûts, mais la production peut disposer d'une instance de base de données dédiée. Tout cela peut être géré en modifiant une seule variable, des instructions ternaires et une interpolation. 

Séparation des tâches

Si vous êtes dans une petite organisation ou si vous utilisez une infrastructure personnelle, cela ne s'applique pas vraiment, mais cela vous aidera à gérer vos opérations. 

  1. Découpez votre infrastructure par fonctions, responsabilités ou équipes. Exemple: Contrôle informatique central des services partagés sous-jacents (réseaux virtuels, sous-réseaux, adresses IP publiques, groupes de journaux, ressources de gouvernance, bases de données multi-locataires, clés partagées, etc.), tandis que l’équipe API ne contrôle que les ressources nécessaires à leur service ( Machines virtuelles, LB, PubSub, etc.) et consomment des services informatiques centraux par le biais de recherches de sources de données et d’états distants.
    1. Gouverner l'accès de l'équipe. Exemple: le service informatique central peut disposer de droits d’administrateur, mais l’équipe des API n’a accès qu’à un ensemble restreint d’API de cloud public. 

Cela aide également à résoudre les problèmes de libération car vous constaterez que certaines ressources changent rarement tandis que d'autres changent tout le temps. La séparation élimine les risques et la complexité. 

Cette stratégie établit un parallèle avec la stratégie multi-comptes d’AWS. Ayez une lecture pour plus d'informations.

CI/CD

C'est un sujet en soi, mais Terraform fonctionne très bien dans un bon pipeline. L'erreur la plus courante est de traiter l'IC comme une solution miracle. Techniquement, Terraform ne devrait constituer une infrastructure d'approvisionnement que lors des étapes d'un pipeline d'assemblage. Cela serait distinct de ce qui se passe dans les étapes CI où l'on valide et teste généralement les modèles. 

N.B. Écrit sur mobile, veuillez donc excuser les erreurs. 

1
Henry Dobson

Si vous recherchez toujours la meilleure solution, examinez les espaces de travail qui peuvent remplacer le maintien de la structure de dossiers d'environnement différente. Ces variables peuvent avoir des variables spécifiques à un espace de travail.

En tant que { Yevgeniy Brikman } _ _ { mentionné il est préférable d'avoir une structure de modules.

0
Rajendra

Avant que les réponses ne soient très solides et instructives, je vais essayer d’ajouter mes 2 centimes ici

Recommandations communes pour la structuration du code

  1. Il est plus facile et plus rapide de travailler avec un plus petit nombre de ressources:

    • Cmdsterraform plan et terraform appliquent tous les deux des appels d'API cloud pour vérifier l'état des ressources.
    • Si vous avez toute l'infrastructure dans une même composition, cela peut prendre plusieurs minutes (même si vous avez plusieurs fichiers dans le même dossier).
  2. Le rayon de souffle est plus petit avec moins de ressources:

    • Isoler les ressources non liées les unes des autres en les plaçant dans des compositions distinctes (dossiers) réduit le risque en cas de problème.
  3. Démarrez votre projet en utilisant l'état distant:

  4. Essayez de pratiquer une structure et une convention de nommage cohérentes:

    • Comme le code de procédure, le code de Terraform doit être écrit pour que les personnes puissent le lire en premier, la cohérence sera utile lorsque des changements se produiront dans six mois.
    • Il est possible de déplacer des ressources dans le fichier d'état de Terraform , mais cela peut s'avérer plus difficile si vous avez une structure et une dénomination incohérentes.
  5. Gardez les modules de ressources aussi clairs que possible.

  6. Ne pas coder en dur les valeurs pouvant être transmises en tant que variables ou découvertes à l'aide de sources de données.

  7. Utilisez data sources et terraform_remote_state spécifiquement comme liant entre les modules d’infrastructure de la composition.

( article de référence: https://www.terraform-best-practices.com/code-structure )


Exemple:

Il est plus facile et plus rapide de travailler avec un plus petit nombre de ressources, nous présentons donc ci-dessous un code recommandé.

NOTE: juste comme référence à ne pas suivre à la lettre car chaque projet a ses propres caractéristiques

.
├── 1_tf-backend #remote AWS S3 + Dynamo Lock tfstate 
│   ├── main.tf
│   ├── ...
├── 2_secrets
│   ├── main.tf
│   ├── ...
├── 3_identities
│   ├── account.tf
│   ├── roles.tf
│   ├── group.tf
│   ├── users.tf
│   ├── ...
├── 4_security
│   ├── awscloudtrail.tf
│   ├── awsconfig.tf
│   ├── awsinspector.tf
│   ├── awsguarduty.tf
│   ├── awswaf.tf
│   └── ...
├── 5_network
│   ├── account.tf
│   ├── dns_remote_zone_auth.tf
│   ├── dns.tf
│   ├── network.tf
│   ├── network_vpc_peering_dev.tf
│   ├── ...
├── 6_notifications
│   ├── ...
├── 7_containers
│   ├── account.tf
│   ├── container_registry.tf
│   ├── ...
├── config
│   ├── backend.config
│   └── main.config
└── readme.md
0
Exequiel Barrirero