top of page
  • Writer's pictureChristoffer Windahl Madsen

Terraform weekly tips, Terraform best practices (8) - 'Seperating concerns'

Updated: Jul 6, 2023


Hi all and welcome to yet another terraform weekly tips, terraform best practice Monday! Today is #8 in the series, and we will focus on the file structure of Terraform and how it behaves during compile-time. This is important as we can utilize the separation of files to make the overall configuration more readable and maintainable. If you havent read any other blog posts before this one, I suggest looking at -> Build a Demo environment with RDP connectivity in just 3 minutes using Terraform (codeterraform.com) As this post gives inside into how a Terraform configuration can look when only creating the following 3 files: main.tf, variables.tf and outputs.tf. In reality, we can actually create a way more seperated configuration.


Fun fact to the above - You do not even need one of the files to be called 'main.tf' And the reason is simple: When Terraform compiles our configuration, it scans the root directory from where Terraform is initialized and looks for files with various extension formats. However, for today's purposes, we will only be using the '.tf' extension. The reason that you can completly ommit both the 'variables.tf' and 'outputs.tf' Is due to the fact the files are only there to further help us structure our code. As stated we can instead simply create all our variables and outputs directly in our 'any number' Of Terraform script files.


Lets dig into some source code - To start lets explore what the above means for the Terraform configuration files in practice.


As always you can follow directly along either by copying code from below or simply clone the repo at -> ChristofferWin/codeterraform: Repo build to support the blog residing at https://codeterraform.com (github.com) This specific blog posts source code reside in folder: terraform projects / weekly tips / week 8 26-06-2023


Lets get started - First of, lets create the following file in any given folder and call it 'main.tf' (If the repo is cloned instead, delete all other files, we will recover them later)


Now lets play with the 1 file - What happens if we BOTH define resources / providers + variables together?


Define:

terraform {
  required_providers {
    azurerm = {
        source = "hashicorp/azurerm"
    }
  }
}

provider "azurerm" {
  features {
  }
}

variable "my_resource_group_name" {
  description = "the name of the resource group"
  type = string
  default = "my-rg"
}

resource "azurerm_resource_group" "rg_object" {
  name = var.my_resource_group_name
  location = "westeurope"
}

Be sure to be authenticated using 'az cli' Before continuing - If in any doubt of how to create a Terraform context use this blog post -> Terraform weekly tips (1) (codeterraform.com)


Run terraform init and then apply:

terraform init
terraform apply --auto-approve=true

What happens? Success!

terraform apply with auto approve

We just created a variable even without the designated variables.tf file with no issues. To this, we can also add all the output statements that we want, also in this 1 file as seen below:

output "my_rg" {
  value = azurerm_resource_group.rg_object
}

Run terraform apply and see:

terraform output

So... As just seen above, we can always cramp all 3 different components of Terraform into 1 big file. We can even rename it to... Lets say 'rg.tf' And rerun terraform apply:


It succeeds once again. We did not even have to re-initialize the config, delete any of the auto-generated files, or anything else. This is simply one of the great powers of Terraform: The ability to define a file structure that matches you and your team.


Now, before we move on to discussing a good way of structuring our Terraform configurations, let's consider what happens if we create 'variables.tf' and 'outputs.tf' files. If we simply create both files without changing any code in 'rg.tf' And then rerun terraform apply, what will happen? Will it work? If not, why?


Result:

terraform apply output

Of-course it does! Remember - Terraform will gather all 3 files together during compile-time, even if we begin to define new variables inside the 'varibles.tf' File. Lets define the variable 'location' Inside the new variables file and let the other variable stay in the 'rg.tf' File:

variable "location" {
  description = "the location of the resources"
  type = string
  default = "westeurope"
}

(If repo is cloned down, simply restore all the files now which can be done via GIT)

Lets also add the newly defined variable to the 'rg.tf' File to define the location of the resource group that we created:

resource "azurerm_resource_group" "rg_object" {
  name = var.my_resource_group_name
  location = var.location
}

Run terraform apply:

terraform apply

Again, it succeeds. However, I do not recommend building any Terraform configuration like this. It is not optimal because the code within the file will quickly grow to a size where it becomes harder and harder to follow everything that Terraform is configured to do.


What we need to do instead to achieve readabillity and structure in our Terraform configration, is to split up the 1 configuration file from above into multiple subfiles with descriptive names.


Now - We already changed the name of 1 of the tf files to 'rg.tf' Lets keep this name for now, but move the variable definition & output statement into their seperate files like so:


In variables.tf:

variable "location" {
  description = "the location of the resources"
  type = string
  default = "westeurope"
}

variable "my_resource_group_name" {
  description = "the name of the resource group"
  type = string
  default = "my-rg"
}

outputs.tf:

output "my_rg" {
  value = azurerm_resource_group.rg_object
}

Now create a new file in the directory called 'providers.tf' And put in the 'terraform' And 'provider' Blocks:


providers.tf:

terraform {
  required_providers {
    azurerm = {
        source = "hashicorp/azurerm"
    }
  }
}

provider "azurerm" {
  features {
  }
}

Now... With all this seperation:

filestructure of terraform

Can we still run terraform apply from the terminal?

terraform apply --auto-approve=true

The result repeats the above success. We have just successfully defined "Separation of Concerns" by splitting up the configuration file into individuals, each containing only relevant code for a specific 'category' Of the Terraform configuration. Now, the above becomes more and more powerful as the configuration grows larger. To this, I challenge you to take the configuration from the following folder in Github -> codeterraform/terraform projects/weekly tips/weeks 1-4-05-2023 at main · ChristofferWin/codeterraform · GitHub - It creates multiple Azure resources and it can surely become cleaner, if we use the above approach to seperate out our resource and other management definitions. Try it out & run your code to see the results!


So to summarize: By seperating our configuration into subfiles we are able to utilize the principle of 'Seperating concerns' which is terraform best practice.


That's all for today. In a later blog post, we will discuss the use of modules as a more advanced and generic way of structuring any Terraform configuration. Thank you so much for reading along. I post frequently, and a new Terraform tip is published weekly, every Monday. Stay tuned!


Cheers!

PS. Want to learn more about Terraform? Click here -> terraform (codeterraform.com)

Want to learn more about other cool stuff like Automation or Powershell -> powershell (codeterraform.com) / automation (codeterraform.com)

11 views0 comments

Comments

Rated 0 out of 5 stars.
No ratings yet

Add a rating
bottom of page