1
votes

Enviornment Isolation: Dirs v. Workspaces v. Modules

The Terraform docs Separate Development and Production Environments seem to take two major approaches for handling a "dev/test/stage" type of CI enviornment, i.e.

  1. Directory seperation - Seems messy especially when you potentially have multiple repos
  2. Workspaces + Different Var Files

Except when you lookup workspaces it seems to imply workspaces are NOT a correct solution for isolating enviornments.

In particular, organizations commonly want to create a strong separation between multiple deployments of the same infrastructure serving different development stages (e.g. staging vs. production) or different internal teams. In this case, the backend used for each deployment often belongs to that deployment, with different credentials and access controls. Named workspaces are not a suitable isolation mechanism for this scenario.

Instead, use one or more re-usable modules to represent the common elements, and then represent each instance as a separate configuration that instantiates those common elements in the context of a different backend. In that case, the root module of each configuration will consist only of a backend configuration and a small number of module blocks whose arguments describe any small differences between the deployments.

I would also like to consider using remote state -- e.g. azurerm backend

Best Practice Questions

  1. When the docs refer to using a "re-usable" module, what would this look like if say I had na existing configuration folder? Would I still need to create a sepreate folder for dev/test/stage?
  2. When using remote backends, should the state file be shared across repos by default or separated by repo and enviornment?

e.g.

terraform {
  backend "azurerm" {
    storage_account_name = "tfstorageaccount"
    container_name       = "tfstate"
    key                  = "${var.enviornment}.terraform.tfstate"
  }
}

vs.

terraform {
  backend "azurerm" {
    storage_account_name = "tfstorageaccount"
    container_name       = "tfstate"
    key                  = "cache_cluster_${var.enviornment}.terraform.tfstate"
  }
}
1
This question is likely going to be closed for both being too broad and opinion based, so I recommend redoing this question. As for the learn Hashicorp website, it is worth noting the exercises there are for instructional purposes, and should not be taken as an indication of best practices.Matt Schuchard

1 Answers

1
votes
  1. When the docs refer to using a "re-usable" module, what would this look like if say I had na existing configuration folder? Would I still need to create a sepreate folder for dev/test/stage?

A re-usable module for your infrastructure would essentially encapsulate the part of your infrastructure that is common to all your "dev/test/stage" environments. So no, you wouldn't have any "dev/test/stage" folders in there.

If, for example, you have an infrastructure that consists of a Kubernetes cluster and a MySQL database, you could have two modules - a 'compute' module that handles the k8s cluster, and a 'storage' module that would handle the DB. These modules go into a /modules subfolder. Your root module (main.tf file in the root of your repo) would then instantiate these modules and pass the appropriate input variables to customize them for each of the "dev/test/stage" environments.

Normally it would be a bit more complex:

  • Any shared VPC or firewall config might go into a networking module.
  • Any service accounts that you might automatically create might go into a credentials or iam module.
  • Any DNS mappings for API endpoints might go into a dns module.

You can then easily pass in variables to customize the behavior for "dev/test/stage" as needed.


  1. When using remote backends, should the state file be shared across repos by default or separated by repo and enviornment?

Going off the Terraform docs and their recommended separation:

In this case, the backend used for each deployment often belongs to that deployment, with different credentials and access controls.

You would not share tfstorageaccount. Now take this with a grain of salt and determine your own needs - essentially what you need to take into account is the security and data integrity implications of sharing backends/credentials. For example:

  • How sensitive is your state? If you have sensitive variables being output to your state, then you might not want your "production" state sitting in the same security perimeter as your "test" state.

  • Will you ever need to wipe your state or perform destructive actions? If, for example, your state storage provider only versions by folder, then you probably don't want your "dev/test/stage" states sitting next to each other.