Search code examples
amazon-web-servicesterraformterraform-provider-aws

How to organize Terraform modules for multiple environments?


Every Terraform guide on the web provides a partial solution that is almost always not the real picture. I get that not everyone has the same infrastructure needs, but what worries me is that the common scenario, including:

  1. Multiple environments (e.g. dev, stage)
  2. Remote backend (e.g. AWS S3)
  3. Some basic resources (e.g. S3 buckets or EC2 instances)

isn't presented anywhere on a real example project. I'm looking for just that.

In the meantime, I have researched and concluded that apart from those needs, I also want:

  1. To utilize modules.
  2. To NOT use workspaces, but rather a distinct directory-per-environment approach.
  3. To NOT use a terragrunt wrapper.

This is my current structure, which does not utilize modules - only a root module:

infra/ --------------- 'terraform init', 'terraform apply' inside here*  
     main.tf --------- Sets up AWS provider, backend, backend bucket, DynamoDB table   
     terraform.tfvars   
     variables.tf ---- Holds few variables such as aws_region, project_name...

I think my desired structure folder tree (for a simple dev & staging simulation of a single bucket resource) would look something like this:

infra/  
     dev/  
        s3/  
            modules.tf ------ References s3 module from local/remote folder with dev inputs   
     stage/  
        s3/  
            modules.tf ------ References s3 module from local/remote folder with stage inputs   

But what about the files from my previous root module? I still want to have a remote backend in the same way as before - just that now I want to have two state files (dev.tfstate and stage.tfstate) in the same backend bucket? What would the backend.tf files look like in each sub-directory, and where would they be? In s3/ folder or dev/ folder?

It's kind of confusing since I'm transitioning from a root module terraform init approach, to a specific sub-directory terraform init. It's not clear to me whether I should still have a root-module or another prerequisite folder (for example: global/), which I should init at the beginning of the project, and which is basically left alone from that point on (since it created the buckets which dev/ and staging/ reference).

One more question: if I have s3/, ec2/, and ecr/ sub-directories inside each environment, where do I execute the terraform plan command? Does it traverse all sub-directories?

When I have the answers and a clear picture of this above, it would be great to improve it by DRYing it up, but for now, I value a more practical solution through example rather than just a theoretic DRY explanation.


Solution

  • I realized as @MarkB suggested, that terraform workspaces are actually a solution to multi-env projects.

    So my project structure looks something like this:

    infra/
      dev/
        dev.tfvars
      stage/
        stage.tfvars 
      provider.tf
      main.tf
      variables.tf
    

    main.tf references modules, provider.tf set's up the provider, backend.tf would set up the remote backend (yet to add), etc.

    The 'terraform plan' in this configuration becomes 'terraform plan -var-file dev/dev.tfvars' where I specify the file with a specific configuration for that environment.