Part 7: Terraform with Azure – Deploy a variables file in Terraform

Reading Time: 8 minutes

My journey learning Terraform to allow me to deploy workloads into Microsoft Azure continues. If you missed the previous posts, please visit the links below.

Part 1: Terraform with Azure – How to install Terraform
Part 2: Terraform with Azure – How to install Azure cli
Part 3: Terraform with Azure – How to Install Visual Studio Code
Part 4: Terraform with Azure – How to install Azure Terraform Plugin in Visual Studio Code
Part 5: Terraform with Azure – Install Git and initialise repository
Part 6: Terraform with Azure – Deploy resources in Azure

Did you know;
1. Terraform is natively available for you to use in the Azure Cloud shell, no installation required.

2.There is a strong relationship between Microsoft and Harshicorp. Microsoft have their own terraform dev team who work closely with Hashicorp.

3. The Terraform registry website includes documentation with sample code so you can get started with deploying resources into Azure quickly.

Part 6 of this blog series involved the deployment of a resource group into Azure using Terraform. In this blog post I go through the process of compiling a variables file.

What is a terraform variables file?

A variables file allows you to write configuration that is easier to re-use as variables can replace hard coded values. It’s ok to use hard coded values if you’re only going to deploy a resource once, however if you wish to deploy a template into different platforms, such as dev, test and production platforms, a variables file would save you the time going through and changing your code. Instead, amending the code in the variables file would be much more convenient.

Example,
If i specified the location of UK South throughout my main.tf file and then decided to deploy the same resources to a different location using the same code in the future, I would have to replace the location throughout my code. The advantage of the variables file is that I only replace the location once as the main.tf file is referencing the variable specified in the variables file.

Below is the code I compiled and deployed to create a resource group in Part 6 of this blog series.

# Create a resource group
resource "azurerm_resource_group" "demo" {
  name     = "CloudBuild-RG1"
  location = "UK South"
}

For now, I will create a variables file including parameters for the location “UK South” and the name of the resource group “CloudBuild-RG1”. I will then replace these default names in my main.tf file, with the name of the variables. Let’s get started.

  1. Create a new file named variables.tf (The file doesn’t have to be named variables.tf). Terraform scans all files, therefore, will pick up a variables file with a different name.

Note: Notice the green letter “U” by the side of the new file I created? This indicates the file is untracked as I have not committed this version to Git. You’ll also come across the letter “M” which means modified.

2. I now input two variables, my resource group (“CloudBuild-RG1”) and the location of the resource group (“UK South”) as seen in the code below, click save.

When there is a requirement to specify CloudBuild-RG1 in my code, I will instead input the variable name of var.resource_group_name and var.resource_group_location for the resource group location.

variable "resource_group_name" {
  default = "CloudBuild-RG1"
  type = string
  description = "Azure Resource Group Name"
}

variable "resource_group_location" {
  default = "UK South"
  type = string
  description = "Azure Resource Group location"
}

Note:
There are various options available when specifying a ‘type’ value. Further details can be located at the following Terraform link, Types and Values – Configuration Language | Terraform by HashiCorp

3. Next I access the main.tf file and replace location “UK South” with the new variable name var.resource_group_location (var = variable). I also replace the resource group “CloudBuild-RG1” to var.resource_group_name.

Below is a copy of my variables file,

variable "resource_group_name" {
  default = "CloudBuild-RG1"
  type = string
  description = "Azure Resource Group Name"
}

variable "resource_group_location" {
  default = "uksouth"
  type = string
  description = "Azure Resource Group location"
}

and below is a copy of my main.tf file. Variable names highlighted below.

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

# Configure the Microsoft Azure Provider
provider "azurerm" {
  features {}
}

# Create a resource group
resource "azurerm_resource_group" "demo" {
  name     = var.resource_group_name
  location = var.resource_group_location
}

4. Next, i run terraform plan and the results are as expected, no changes will be deployed to Azure as there is nothing further to deploy.

5. Next, as an experiment, I amend my variables.tf file as per the below. I rename RG1 to RG2, and save. I am not amending the code included in file main.tf

 Before: default = “CloudBuild-RG1
 After: default = “CloudBuild-RG2

What do you think the result will be when I run terraform plan?

The resource group can not be renamed, therefore, if the changes were executed, Terraform would destroy resource CloudBuild-RG1 and create a new resource group CloudBuild-RG2.

As you can see from the terraform plan output below, one resource will be added and one destroyed. Not something you would want to perform in production without prior planning/testing!

6. Next, I apply the changes by running terraform apply

Before running terraform apply, I have resource group CloudBuild-RG1 which I deployed via Terraform in part 6 of this blog series. See image below.

After running terraform apply, RG1 has been deleted and a new group ending RG2 deployed. Terraform warns me of the changes I am about to execute, giving me another opportunity to review what will change.

Note: it may take up to 30 seconds before the changes appear in the Azure portal. Click the refresh button.

The result as per the image below. Resource group ending RG1 has gone and RG2 deployed.

You can add new variables to your variables.tf file as and when required. We’ll continue making use of variables as we move on and deploy resources in Azure.

7. Before moving to the next task, I run command terraform destroy which will remove what I have deployed so far, that’s the resource group CloudBuild-RG2.

Reminder: you can always validate your code for errors by using command terraform validate so I would recommend making use of this command as your code grows.

Another quick note, you may have noticed a file named .terraform.tfstate.lock.info appear for a short while as you execute Terraform code.

What is .terraform.tfstate.lock.info?
“If supported by your backend, Terraform will lock your state for all operations that could write state. This prevents others from acquiring the lock and potentially corrupting your state. State locking happens automatically on all operations that could write state. You won’t see any message that it is happening.” Source: Terraform

Back to the command terraform destroy, I run this command and as expected Terraform prompts the changes which will be carried as per the image below. My resource group will be deleted.

8. Type ‘Yes’ to confirm, and after a few seconds, the result.

9. Back to the Azure Portal, browse to resource groups, and a couple of clicks of the refresh button, the resource group has gone. The tfstate file is automatically updated to reflect the changes so if I was to run terraform apply again, the resource group we just destroyed would be recreated.

10. Back to the variables.tf file, let’s perform another task, what if I did not create a default value in my variables file as shown in the code below? At the moment, I have default values, so for example, if I use the variable var.resource_group_name in my main.tf file, the default value of CloudBuild-RG1 will always apply as that’s what I specified in my variables file. The same would apply for the resource group location.

variable “resource_group_name” {
default = “CloudBuild-RG2”
type = string
description = “Azure Resource Group Name”
}

variable “resource_group_location” {
#default = “uksouth”
type = string
description = “Azure Resource Group location”
}

11. In the next task, I remove the default values so the variables file appears as the one below. I have removed the line that applies a default value.

variable "resource_group_name" {
  type = string
  description = "Azure Resource Group Name"
}

variable "resource_group_location" {
  type = string
  description = "Azure Resource Group location"
}

Note: you could also add a # to the beginning of the code so it’s ignore at the time of execution, for example, #default = “CloudBuild-RG2”

12. Save and run the command terraform validate. The configuration is valid.

13. Next, I run terraform plan (This command outputs what Terraform would execute if you were to apply the changes). Ensure you have saved your variables file. Again, as I execute the command, the terraform state lock file will appear temporarily and then disappear.

Tip: you can press the up arrow key on your keyboard to revisit previous commands you have executed.

Reminder: you can use command clear to empty your terminal of previous code.

After running terraform plan, Terraform is not able to locate a default value as I removed the value from my variables file. Terraform prompts for a value, the Azure Resource Group Location as shown below,

I enter uksouth as that’s the Azure region where I wish to deploy my resource group,

14. I am then prompted for a value for my resource group name, I enter, demo-RG1

Note: Terraform will not run the command in the order you specify, however, it will execute the code depending on what is required to be deployed first in Azure.

15. Terraform runs through the plan and provides an output,

Note:
A number of services in Azure require a unique name. For example, a storage account name has to be globally unique, therefore you will only be allowed to create that storage account once. Therefore, a variable would be ideal.

I hope this has been useful. Please feel free to comment below with feedback or any additional information you feel I may have missed out.

In the next blog post I go through the process of compiling a terraform.tfvars file – click the link below to continue,

Part 8: Terraform with Azure – Deploy a terraform.tfvars file

Don’t forget to subscribe to new posts and thank you for following.

Part 6: Terraform with Azure – Deploy resources in Azure

Reading Time: 7 minutes

My journey learning Terraform to allow me to deploy workloads into Microsoft Azure continues. If you missed the previous posts, please visit the links below.

Part 1: Terraform with Azure – How to install Terraform
Part 2: Terraform with Azure – How to install Azure cli
Part 3: Terraform with Azure – How to Install Visual Studio Code
Part 4: Terraform with Azure – How to install Azure Terraform Plugin in Visual Studio Code
Part 5: Terraform with Azure – Install Git and initialise repository

In this blog post I go through the process of initiating Terraform and start the process of deploying workloads in Azure.

  1. Launch VSCode
  2. Create a new file named main.tf

3. Next we need to configure the provider. In our case, the provider is Azure. I type the below code in the newly created file, main.tf. You can also locate the below code from the Terraform Registry website (At the time of writing this blog post the version was 2.95.0). Save the file

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

# Configure the Microsoft Azure Provider
provider "azurerm" {
  features {}
}

4. Next I add the code to create a new resource group named CloudBuild-RG1 in location UK South. Save the file

# Create a resource group
resource "azurerm_resource_group" "demo" {
  name     = "CloudBuild-RG1"
  location = "UK South"
}
  • Azurerm is the plugin name. RM stands for resource manager
  • CloudBuild-RG1 is the name of the resource
  • “demo” is the resource group name in Terraform and is what we will refer to when creating the resource group
  • Location is where we will be deploying the resource group. The region being UK South

5. Let’s run the newly created code. But before executing the code, we need to login to Azure. In powershell or the command terminal type the below command and press enter,

az login

6. The above code launches a web page requesting you login to your azure tenant.

Useful commands,
Terraform version – outputs the version of Terraform installed
Clear – Clears the command window
Terraform validate – validates the code and checks for errors
Terraform apply – this command will read your .tf files and apply the changes. Prior to applying Terraform will output the changes and request confirmation before applying.
Terraform plan – this command outputs the changes Terraform will apply and safer to use compared to command Terraform apply
Terraform init – You would run this command the first time you used Terraform within a new directory/project folder, add a new provider or a module.
Terraform destroy – will remove all resources
Terraform fmt – this command will fix the layout of your file so it’s well presented and easy to read.
Terraform help – outputs a full list of commands


7. Next, we need to initialise Terraform. The below command will read from main.tf file and load the version of Terraform as specified in the file,

terraform init

A terraform folder is populated in the working folder. This folder contains the required config to allow Terraform to deploy resources in Azure.

8. Before deploying the first resource group via Terraform in Azure, I run a command to confirm what will be deployed (added/destroyed) in Azure. Run the command below and press enter. The output below displays that one resource group will be created in Azure.

terraform plan

9. We’re ready to deploy our resource group in Azure. Type the command below and press enter,

terraform apply

10. Before committing, Terraform will prompt you to check and type ‘yes’ to confirm,

Do you want to perform these actions?
Terraform will perform the actions described above.
Only ‘yes’ will be accepted to approve.

Enter a value:

Note: if you wish to bypass the above prompt, you could add -auto -approve after terraform apply, i.e. terraform apply -auto -approve

11. Review, type yes if all looks good, and press enter. The process to create our new resource group is under way. When complete, you’ll receive an Apply complete message as shown below.

12. Login to the Azure Portal, access resource groups. Click the refresh button if the resource group does not appear.

And here is our newly created resource group in Azure

You may have noticed that Terraform has created a new file name ‘terraform.tfstate, as shown in the screenshot below.

This state is used by Terraform to map real world resources to your configuration, keep track of metadata, and to improve performance for large infrastructures. This state is stored by default in a local file named “terraform. tfstate”, but it can also be stored remotely, which works better in a team environment. Source: Terraform

In simple words, this is a very important file because it includes the state of what you have already deployed into Azure. Note that the state file will only know what you have deployed via Terraform, it has no idea what you may have already deployed manually within the Azure Portal or via any other provider, so it’s recommended that once you start using Terraform, stick to it to avoid potential issues and confusion in the future.

What if there are a couple of you working on the same project, how does the state file work in this scenario? You could use an Azure storage account as a central location for the state file, or a jump box (a central server) from where the team always run Terraform. This server would hold the state file. However, for larger teams it’s recommended to use Terraform Enterprise for advanced features and collaboration.

Note, you can not rename a resource, for example, if I was to rename the resource group name in my main.tf file, from CloudBuild-RG1 to CloudBuild-RG2, Terraform would delete CloudBuild-RG1 and create CloudBuild-RG2, so one to watch out for. Give it a try in your lab and don’t forget to run terraform plan to confirm what changes will be performed before applying.

Committing to Git

You may recall we installed Git in part 5 of this series. I will be committing the current version/changes up to now. Note that each time you commit, git takes a snap shot of what the files look like at the time and stores a reference to that snapshot. As additional changes are made to your code, you can continue to commit the changes to Git. To commit to git,

  1. Type the below command and press enter. This will stage all files in the current folder. You can also specify filenames if you don’t wish to commit the complete folder/project, for example git stage index.html
git stage .

2. To confirm the files have been staged, type the command below and press enter,

git status

Note: if you wish to remove the files or a file from the staging area, you can run command, git rm –cached filename (replace filename with the file you wish to unstage or type . to unstage all files.

3. Now it’s time to make our first commit in Git. Type the below command and press enter, (the message in brackets should be short but useful for tracking purposes)

git commit -m "Initial Commit"

4. And here is the result

Note, you can add files you would like Git to ignore by specifying them in the .gitignore file we created in part 5

5. Type git status again and confirm that the output displays nothing to commit.

6. Type the below command to check the history of your current log,

git log

The above output explained: The long number is the unique identifier for the commit. Each commit is associated with a unique identifier. The author name, date and time of the commit is specified. HEAD indicates that this is the latest commit, and master is the branch name. Finally, the description of the commit was ‘initial commit’.

As additional commits are added, the logs may become difficult to read, so a useful command to shorten the logs is,

git log --oneline

There is so much more to learn about Git, so I recommend you pick up a training course and study Git and GitHub further. I will however continue to work with Git, and GitHub in further blog posts.

In the next blog post (Part 7) I compile and explain the purpose of a terraform variables file.

Part 7: Terraform with Azure – Deploy a variables file in Terraform