On my first introducition to infrastructure as code I was intrigued but confused. I didn’t fully understand the concept and its capabilities, that is, until now. I’ve since toyed with the idea of learning terraform (no particular reason for choosing terraform, this was what I was first introduced to). In this article I’ll take you along my journey of learning the basics of terraforming in azure.

I only vaguely followed the microsoft examples as I eventually just started using them as a guide to deploy my own infrastructure.
Here’s what I did:

  • Install the latest version terraform
  • Deployed resource groups (closely following microsoft documentation)
  • Deployed azure container instances
  • Deployed Virtual machines

Installing the latest version of terraform

For all of my experimenting I only used the Azure CLI however I will try installing terraforn locally and using it alongside the azure powershell module in the future

Installing terraform in the azure cli is simple, worth noting that terraform is already installed in the cli however microsoft recommends to intstall the latest terraform packge.
The install is done by using curl to download the appropriate zip file from the terraform website
unzipping the terraform package
moving the contents of the unzipped archive to a directory called bin/terraform
see Microsoft docs

terraform version
curl -O <terraform_download_url>
unzip <zip_file_downloaded_in_previous_step>
mkdir bin
mv terraform bin/
terraform version

Deploying resource groups

We’ll mostly be working with 4 main files, however terraform does create additional files:

provider.tf - used to specific which providers we’re working with; in this case its azurerm

main.tf - used to call the azure resource providers and define the resources we want to deploy

variables.tf - variables can be used in the main.tf file any variable used in the main.tf file must be declared in this file which also hold the arguments for the variables

output.tf - we can use this file to specify which resources/resource properties we want to get information on after deployment. eg A resource group name after deployment

I first started by deploying a single resource group then trying to make sense of the different files and the syntax used by terraform. Closely following this article.

I then moved onto trying to deploy two resource groups, worth noting that I didn’t get this on my first try and this did help me develop my understanding of the azurerm resource providers.

provider.tf

terraform {
  required_version = ">=0.12"
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
      version = "~>2.0"
    }
  }
}
provider "azurerm" {
  features {}
}

main.tf

# Generating name for resource group
resource "random_pet" "rg-name" {
  prefix    = var.resource_group_name_prefix
}

# Generating name for resource group
resource "random_pet" "rg-name-two" {
  prefix    = var.resource_group_name_prefix
 }

# Creating resource group
resource "azurerm_resource_group" "rg" {
  name      = random_pet.rg-name.id
  location  = var.resource_group_location
  tags      = var.rg_tags
}

# Creating resource group
resource "azurerm_resource_group" "rg_two" {
  name      = random_pet.rg-name-two.id
  location  = var.resource_group_location
  tags      = var.rg_tags
}

variables.tf

variable "resource_group_name_prefix" {
  default       = "rg"
  description   = "Prefix of the resource group name that's combined with a random ID so name is unique in your Azure subscription."
}

variable "resource_group_location" {
  default = "uksouth"
  description   = "Location of the resource group."
}

variable "rg_tags" {
  default = {Provisioner = "Terraform"}
  description = "Test adding tag via terraform"
}

output.tf

output "resource_group_name" {
     value = azurerm_resource_group.rg.name
}
output "resource_group_tags" {
     value = azurerm_resource_group.rg.tags
}
output "resource_group_name_two" {
    value = azurerm_resource_group.rg_two.name
}

To actually deploy in azure we then run the following commands

terraform plan -out main.tfplan

output:

Terraform used the selected providers to generate the following execution

plan. Resource actions are indicated with the following symbols:
   create

Terraform will perform the following actions:

# azurerm_resource_group.rg will be created
	resource "azurerm_resource_group" "rg" {
      id       = (known after apply)
      location = "uksouth"
      name     = (known after apply)
      tags     = {
          "Provisioner" = "Terraform"
        }
    }
# azurerm_resource_group.rg_two will be created
resource "azurerm_resource_group" "rg_two" {
      id       = (known after apply)
      location = "uksouth"
      name     = (known after apply)
      tags     = {
        	"Provisioner" = "Terraform"
        }
    }

# random_pet.rg-name will be created
resource "random_pet" "rg-name" {
	id        = (known after apply)
    length    = 2
    prefix    = "rg"
    separator = "-"
    }

 # random_pet.rg-name-two will be created
resource "random_pet" "rg-name-two" {
      id        = (known after apply)
      length    = 2
      prefix    = "rg"
      separator = "-"
    }
Plan: 4 to add, 0 to change, 0 to destroy.
	Changes to Outputs:
  		resource_group_name     = (known after apply)
		resource_group_name_two = (known after apply)
		resource_group_tags     = {
      		"Provisioner" = "Terraform"
    }

Saved the plan to: main.tfplan

To perform exactly these actions, run the following command to apply:

    terraform apply "main.tfplan"

We then need to apply the terraform plan file we just created.

terraform apply main.tfplan

output:

	random_pet.rg-name-two: Creating...
	random_pet.rg-name: Creating...
    random_pet.rg-name-two: Creation complete after 0s [id=rg-tolerant-pelican]
    random_pet.rg-name: Creation complete after 0s [id=rg-peaceful-rattler]
	azurerm_resource_group.rg: Creating...
	azurerm_resource_group.rg_two: Creating...
	azurerm_resource_group.rg: Creation complete after 1s [id=/subscriptions/cff2c421-5594-4219-9863-f9566429966a/resourceGroups/rg-peaceful-rattler]
    azurerm_resource_group.rg_two: Creation complete after 1s [id=/subscriptions/cff2c421-5594-4219-9863-f9566429966a/resourceGroups/rg-tolerant-pelican]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Outputs:
	resource_group_name = "rg-peaceful-rattler"
	resource_group_name_two = "rg-tolerant-pelican"
	resource_group_tags = tomap({
  "Provisioner" = "Terraform"
})

After executing these commands we can see the output is what we’ve defined in the output.tf file. We can also see the resources appear in our azure portal!

Here’s the two resource groups created by terraform.

We see here that out tags have been also been added!

Cleaning up after ourselves is also very easy

terraform plan -destroy -out main.destroy.tfplan
terraform apply main.destroy.tfplan

Deploying an azure container group

For this I followed the terraform documentation. My knowledge of containerization and docker was a limiting factor in me being able to set up a properly functioning environment.

For my full code implemenation please see my Github

main.tf

resource "random_pet" "rg-name" {
  prefix    = var.resource_group_name_prefix
}

resource "azurerm_resource_group" "example" {
  name      = random_pet.rg-name.id
  location  = var.resource_group_location
  tags      = var.rg_tags
}

resource "azurerm_container_group" "example" {
  name      = "example-continst"
  resource_group_name = azurerm_resource_group.example.name
  location  = azurerm_resource_group.example.location
  ip_address_type = "public"
  dns_name_label  = "tf-containerinst-ra"
  os_type         = "Linux"
  container {
   name		= "testvwcontainer"
   image	= "vaultwarden/server:latest"
   cpu		= "0.5"
   memory 	= "1.5"

   ports {
    port 	= 80
    protocol	= "TCP"
   }
}
tags = var.rg_tags

}

Resource group with container group

Container group with container Instance

Deploying the virtual machines
Following both microsoft and terraform documentation, I definitely learnt the most from this exercise. Initially starting with deploying a single vm I got a better understanding of the resources that surround an azure vm. It was a simple enough task once I broke down the main.tf file into the individual resources that terraform will be deploying. Also trying to understand every line of code helped a lot with seeing how the different resources are linked and how they work in combination with each other.

That being said there were two different versions of my I environment. The first being where I just duplicated the VM and NIC.

In my second version I tidied up the networking and only associated the subnet to the network security group.

The azure resources remained the same across the two versions

For my full code implemenation please see my Github

Overall this was very exciting for me and I enjoyed learning and using terraform. The real moment of magic sets in after hitting enter on the terraform apply command, then seeing all your infrastructure automagically appear. It was very helpful in developing my understanding of azure on the whole. I understand that I have a long way to go if I want to do any real work with terraform like tidying up my .tf files and using modules to simplify deployment.

Future things to learn:

Storing my state file in a storage account to follow Microsoft’s best practises.
Deployment of management groups
Vnet peering (pre-cursor to deploying hub and spoke topology)
Terraforming across differrent azure subscriptions