Ideal terraform workspace project structure
Asked Answered
D

3

10

I'd like to setup Terraform to manage dev/stage/prod environments. The infrastructure is the same in all environments, but there are differences in the variables in every environment.

What does an ideal Terraform project structure look like now that workspaces have been introduced in Terraform 0.10? How do I reference the workspace when naming/tagging infrastructure?

Diecious answered 16/8, 2017 at 15:33 Comment(1)
Terraform configurations * environments = workspaces: terraform.io/docs/enterprise/guides/recommended-practices/…Stretch
C
10

I wouldn't recommend using workspaces (previously 'environments') for static environments because they add a fair bit of complexity and are harder to keep track of.

You could get away with using a single folder structure for all environments, use workspaces to separate the environments and then use conditional values based on the workspace to set the differences. In practice (and especially with more than 2 environments leading to nested ternary statements) you'll probably find this difficult to manage.

Instead I'd still advocate for separate folders for every static environment and using symlinks to keep all your .tf files the same across all environments and a terraform.tfvars file to provide any differences at each environment.

I would recommend workspaces for dynamic environments such as short lived review/lab environments as this allows for a lot of flexibility. I'm currently using them to create review environments in Gitlab CI so every branch can have an optionally deployed review environment that can be used for manual integration or exploratory testing.

Customer answered 17/8, 2017 at 7:38 Comment(0)
I
3

In the old world you might have passed in the var 'environment' when running terraform, which you would interpolate in your .tf files as "${var.environment}".

When using workspaces, there is no need to pass in an environment variable, you just make sure you are in the correct workspace and then interpolate inside your .tf files with "${terraform.workspace}"

As for how you'd manage all of the variables, i'd recommend using a varmap, like so:

variable "vpc_cidr" {
  type = "map"

  default = {
    dev = "172.0.0.0/24"
    preprod = "172.0.0.0/24"
    prod = "172.0.0.0/24"
  }
}

This would then be referenced in a aws_vpc resource using a lookup

"${lookup(var.vpc_cidr, terraform.workspace)}"

The process of creating and selecting workspaces is pretty easy:

terraform workspace
Usage: terraform workspace

  Create, change and delete Terraform workspaces.


Subcommands:

    show      Show the current workspace name.
    list      List workspaces.
    select    Select a workspace.
    new       Create a new workspace.
    delete    Delete an existing workspace.

so to create a new workspace for pre production you'd do the following: terraform workspace new preprod

and if you ran a plan, you'd see that there should be no resources. What this will do in the backend is create a new folder to manage the state for 'preprod'.

Intercellular answered 25/8, 2017 at 14:52 Comment(2)
On a previous project, we used folders to differentiate between environments. So there was a folder called modules with all the modules and then in the providers-folder, we made separate folders per environment (DEV, TEST, PREPRD, ...). Does workspaces mean that this is not necessary anymore? Because the explanation on the TF website is a bit ambiguous in my opinion.Assignable
@Assignable This is what I'm trying to find out, the documentation on their website seems to say this is still recommended from what I understand. Their best practices repo is also outdated. Have you found it out yet?Courbet
O
-1

You should follow Terraform official style guide。It talks about module structure, multiple environment and their branching strategy

https://developer.hashicorp.com/terraform/language/style

Multiple environments

that your repository's main branch be the source of truth for all environments. For Terraform Cloud and Terraform Enterprise users, we recommend that you use separate workspaces for each environment. For larger codebases, we recommend that you split your resources across multiple workspaces to prevent large state files and limit unintended consequences from changes. For example, you could structure your code as follows:

.
├── compute
│   ├── main.tf
│   ├── outputs.tf
│   └── variables.tf
├── database
│   ├── main.tf
│   ├── outputs.tf
│   └── variables.tf
└── networking
    ├── main.tf
    ├── outputs.tf
    └── variables.tf

In this scenario, you would create three workspaces per environment. For example, your production environment would have a prod-compute, prod-database, and prod-networking workspace.

Refs: https://developer.hashicorp.com/terraform/language/style#multiple-environments

Repository structure

Organize your infrastructure configuration in repositories that group together logically-related resources. For example, a single repository for a web application that requires compute, networking, and database resources . By separating your resources into groups, you limit the number of resources that may be impacted by failures for any operation.

Another approach is to group all modules and infrastructure configuration into a single monolithic repository, or monorepo. For example, a monorepo may define a collection of local modules for each component of the infrastructure stack, and deploy them in the root module.

.
├── modules
│   ├── function
│   │   ├── main.tf      # contains aws_iam_role, aws_lambda_function
│   │   ├── outputs.tf
│   │   └── variables.tf
│   ├── queue
│   │   ├── main.tf      # contains aws_sqs_queue
│   │   ├── outputs.tf
│   │   └── variables.tf
│   └── vpc
│       ├── main.tf      # contains aws_vpc, aws_subnet
│       ├── outputs.tf
│       └── variables.tf
├── main.tf
├── outputs.tf
└── variables.tf

Refs: https://developer.hashicorp.com/terraform/language/style#repository-structure

Module repository names

The Terraform registry requires that repositories match a naming convention for all modules that you publish to the registry. Module repositories must use this three-part name terraform--, where reflects the type of infrastructure the module manages and is the main provider the module uses. The segment can contain additional hyphens, for example, terraform-google-vault or terraform-aws-ec2-instance.

Refs: https://developer.hashicorp.com/terraform/language/style#module-repository-names

Other Important links to consider

https://developer.hashicorp.com/terraform/language/style#branching-strategy

Olly answered 3/4 at 6:21 Comment(4)
I would like to disagree. As this answer is based on technical guide which is very detailed so summarising it all will not make sense. Even if linked page changes at least OP can find it using official style guide from terraform as it is now officially released and then maybe at that time we can update the links. Having said that I have updated the answer with main sections which may helpOlly
I deleted my comment since it appears you have edited your answer into an acceptable state.Consubstantial
I am not the downvoter, but I am also hesitant to upvote this as I have no subject matter expertise and thus am not in a position to evaluate the actual usefulness of this answer. I am not saying your answer is bad, or good, I am just saying that I do not feel qualified to make that judgement by voting, as this topic is well out of my subject-matter expertise.Consubstantial
No worries but thank you for making this answer better.Olly

© 2022 - 2024 — McMap. All rights reserved.