web-dev-qa-db-fra.com

Différents environnements pour Terraform (Hashicorp)

J'utilise Terraform pour créer ma pile AWS et j'en profite. Si elle devait être utilisée dans un cadre commercial, la configuration devrait être réutilisée pour différents environnements (par exemple QA, STAGING, PROD).

Comment pourrais-je y parvenir? Aurais-je besoin de créer un script d'encapsuleur qui appelle la cli de terraform tout en passant dans différents fichiers d'état par environnement comme ci-dessous? Je me demande s'il existe une solution plus native fournie par Terraform.

terraform apply -state=qa.tfstate
42
n00b

Je vous suggère de jeter un œil au repo des meilleures pratiques de hashicorp , qui a une configuration assez agréable pour gérer différents environnements (similaire à ce que James Woolfenden a suggéré).

Nous utilisons une configuration similaire, et cela fonctionne très bien. Cependant, ce référentiel de bonnes pratiques suppose que vous utilisez Atlas, ce qui n'est pas le cas. Nous avons créé un Rakefile assez élaboré qui, en gros (en reprenant le repo des meilleures pratiques) obtient tous les sous-dossiers de /terraform/providers/aws, et les expose en tant que versions différentes à l'aide d'espaces de noms. Donc notre rake -T la sortie répertorierait les tâches suivantes:

us_east_1_prod:init
us_east_1_prod:plan
us_east_1_prod:apply

us_east_1_staging:init
us_east_1_staging:plan
us_east_1_staging:apply

Cette séparation empêche les modifications qui pourraient être exclusives à dev d'affecter accidentellement (ou pire, de détruire) quelque chose dans prod, car il s'agit d'un fichier d'état différent. Il permet également de tester un changement de dev/staging avant de l'appliquer réellement à prod.

De plus, je suis récemment tombé sur cette petite écriture, qui montre essentiellement ce qui pourrait arriver si vous gardez tout ensemble: https://charity.wtf/2016/03/30/terraform-vpc-and-why-you -want-a-tfstate-file-per-env /

20
Erik van Brakel

La solution de Paul avec modules est la bonne idée. Cependant, je recommande fortement contre de définir tous vos environnements (par exemple QA, staging, production) dans le même fichier Terraform. Si vous le faites, à chaque fois que vous modifiez la mise en scène, vous risquez également de casser accidentellement la production, ce qui défait partiellement le point de garder ces environnements isolés en premier lieu! Voir Terraform, VPC, et pourquoi vous voulez un fichier tfstate par env pour une discussion colorée de ce qui peut mal tourner.

Je recommande toujours de stocker le code Terraform pour chaque environnement dans un dossier séparé. En fait, vous pouvez même vouloir stocker le code Terraform pour chaque "composant" (par exemple une base de données, un VPC, une seule application) dans des dossiers séparés. Encore une fois, la raison est l'isolement: lorsque vous apportez des modifications à une seule application (ce que vous pourriez faire 10 fois par jour), vous ne voulez pas mettre votre VPC entier en danger (que vous ne modifiez probablement jamais).

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

stage
  └ vpc
     └ main.tf
     └ vars.tf
     └ outputs.tf
  └ app
  └ db
prod
  └ vpc
  └ app
  └ db
global
  └ s3
  └ iam

Tout le code Terraform pour l'environnement de transfert va dans le dossier stage, tout le code de l'environnement prod va dans le dossier prod et tout le code qui vit en dehors d'un environnement (par exemple IAM utilisateurs, compartiments S3) va dans le dossier global.

Pour plus d'informations, consultez Comment gérer l'état Terraform . Pour un examen plus approfondi des meilleures pratiques Terraform, consultez le livre Terraform: Up & Running.

15
Yevgeniy Brikman

Veuillez noter qu'à partir de la version 0.10.0, Terraform prend désormais en charge le concept des espaces de travail (environnements en 0.9.x).

Un espace de travail est un conteneur nommé pour l'état Terraform. Avec plusieurs espaces de travail, un seul répertoire de configuration Terraform peut être utilisé pour gérer plusieurs ensembles distincts de ressources d'infrastructure.

Voir plus d'informations ici: https://www.terraform.io/docs/state/workspaces.html

14
Ronny López

Au fur et à mesure que vous augmentez l'utilisation de votre terraform, vous devrez partager l'état (entre les développeurs, les processus de construction et les différents projets), prendre en charge plusieurs environnements et régions. Pour cela, vous devez utiliser l'état distant. Avant d'exécuter votre terraform, vous devez configurer votre état. (J'utilise PowerShell)

$environment="devtestexample"
$region     ="eu-west-1"
$remote_state_bucket = "${environment}-terraform-state"
$bucket_key = "yoursharedobject.$region.tfstate"

aws s3 ls "s3://$remote_state_bucket"|out-null
if ($lastexitcode)
{
   aws s3 mb "s3://$remote_state_bucket"
}

terraform remote config -backend S3 -backend-config="bucket=$remote_state_bucket"  -backend-config="key=$bucket_key" -backend-config="region=$region"
#(see here: https://www.terraform.io/docs/commands/remote-config.html)

terraform apply -var='environment=$environment' -var='region=$region'

Votre état est maintenant stocké dans S3, par région, par environnement, et vous pouvez ensuite accéder à cet état dans d'autres projets tf.

6
James Woolfenden

Pas besoin de faire un script wrapper. Ce que nous faisons est de diviser notre env en un module, puis d'avoir un fichier terraform de niveau supérieur où nous importons simplement ce module pour chaque environnement. Tant que vous avez la configuration de votre module pour prendre suffisamment de variables, généralement env_name et quelques autres, vous êtes bon. Par exemple

# project/main.tf
module "dev" {
    source "./env"

    env = "dev"
    aws_ssh_keyname = "dev_ssh"
}

module "stage" {
    source "./env"

    env = "stage"
    aws_ssh_keyname = "stage_ssh"
}

# Then in project/env/main.tf
# All the resources would be defined in here
# along with variables for env and aws_ssh_keyname, etc.

Modifier 2020/03/01

Cette réponse est assez ancienne à ce stade, mais elle mérite d'être mise à jour. La critique selon laquelle dev et stage partageant le même fichier d'état sont mauvais est une question de perspective. Pour le code exact fourni ci-dessus, c'est complètement valide parce que dev et stage partagent également le même code. Ainsi, "briser le dev va détruire votre scène" est correct. La chose critique que je n'ai pas notée en écrivant cette réponse était le source "./env" pourrait également s'écrire source "git::https://example.com/network.git//modules/vpc?ref=v1.2.0"

Faire cela fait que votre repo entier devient quelque chose d'un sous-module pour les scripts TF vous permettant de diviser une branche en branche QA, puis de marquer les références en tant qu'envs de production. Cela évite le problème de détruire votre env de mise en scène avec un changement de dev.

Prochain partage de fichiers d'état. Je dis que c'est une question de perspective car avec une seule exécution, il est possible de mettre à jour tous vos environnements. Dans une petite entreprise, il peut être utile de gagner du temps lors de la promotion des changements, une astuce avec --target est généralement suffisant pour accélérer le processus si vous faites attention, si c'est vraiment nécessaire. Nous avons trouvé qu'il était moins sujet aux erreurs de tout gérer à partir d'un seul endroit et d'une seule exécution de terraform, plutôt que d'avoir plusieurs configurations différentes pouvant être appliquées légèrement différemment dans les environnements. Les avoir tous dans un fichier d'état nous a obligés à être plus disciplinés sur ce qui devait vraiment être une variable vs. ce qui était juste exagéré pour nos besoins. Cela nous a également très fortement empêché de laisser nos environnements trop éloignés les uns des autres. Lorsque vous terraform plan les sorties affichent 2k lignes, et les différences sont principalement dues au fait que le développement et la scène ne ressemblent en rien au fait que le facteur de frustration à lui seul a encouragé notre équipe à ramener cela à la raison.

Un contre-argument très fort à cela est si vous êtes dans une grande entreprise où diverses règles de conformité vous empêchent de toucher en même temps à dev/stage/prod. Dans ce scénario, il est préférable de diviser vos fichiers d'état, assurez-vous simplement que comment vous exécutez terraform apply est scripté. Sinon, vous courez le risque très réel que ces fichiers d’état s’écartent lorsque quelqu'un dit "Oh, je dois juste --target juste cette seule chose dans la mise en scène. Nous allons le réparer au prochain sprint, promis. "J'ai vu cette spirale rapidement plusieurs fois maintenant, ce qui rend au mieux toute comparaison entre les environnements discutable.

2
Paul

Il y a beaucoup de bonnes réponses dans ce fil. Permettez-moi également de contribuer avec une idée qui a fonctionné pour moi et certaines autres équipes.

L'idée est d'avoir un seul projet "parapluie" qui contient tout le code d'infrastructure.

Le fichier terraform de chaque environnement comprend un seul module - le "principal".

Ensuite, "main" comprendra des ressources et d'autres modules

- terraform_project
- env
  - dev01        <-- Terraform home, run from here 
    - .terraform    <-- git ignored of course
    - dev01.tf  <-- backend, env config, includes always _only_ the main module
  - dev02
    - .terraform
    - dev02.tf 
  - stg01
    - .terraform
    - stg01.tf
  - prd01
    - .terraform
    - prd01.tf 
- main        <-- main umbrella module
   - main.tf
   - variables.tf         
- modules         <-- submodules of the main module
  - module_a
  - module_b
  - module_c

Et un exemple de fichier d'accueil d'environnement (par exemple dev01.tf) ressemblera à ceci

provider "azurerm" {
  version = "~>1.42.0"
}

terraform {
  backend "azurerm" {
    resource_group_name  = "tradelens-Host-rg"
    storage_account_name = "stterraformstate001"
    container_name       = "terraformstate"
    key                  = "dev.terraform.terraformstate"
  }
}

module "main" {
  source               = "../../main"
  subscription_id      = "000000000-0000-0000-0000-00000000000"
  project_name         = "tlens"
  environment_name     = "dev"
  resource_group_name  = "tradelens-main-dev"
  tenant_id            = "790fd69f-41a3-4b51-8a42-685767c7d8zz"
  location             = "West Europe"
  developers_object_id = "58968a05-dc52-4b69-a7df-ff99f01e12zz"
  terraform_sp_app_id  = "8afb2166-9168-4919-ba27-6f3f9dfad3ff"

  kubernetes_version      = "1.14.8"
  kuberenetes_vm_size     = "Standard_B2ms"
  kuberenetes_nodes_count = 4

  enable_ddos_protection = false
  enable_waf             = false
}

Grâce à cela, vous:

  • Peut avoir des backends séparés pour les fichiers d'état distants Terraform par environnement
  • Être en mesure d'utiliser des comptes système distincts pour différents environnements
  • Être capable d'utiliser différentes versions de fournisseurs et Terraform lui-même par environnement (et mettre à niveau un par un)
  • Assurez-vous que toutes les propriétés requises sont fournies par environnement (la validation Terraform ne passera pas si une propriété environnementale est manquante)
  • Assurez-vous que toutes les ressources/modules sont toujours ajoutés à tous les environnements. Il n'est pas possible "d'oublier" un module entier car il n'y en a qu'un.

Vérifiez un article de blog source

0
Piotr Gwiazda