Chapter 2: Fundamental Terraform Building Blocks
Terraform uses the HashiCorp Configuration Language (HCL) to define infrastructure as code (IAC) for various platforms, including Azure. HCL is a domain-specific language (DSL) designed to be easy to read and use. It allows you to define and configure infrastructure resources in a simple, predictable way, making it a great choice for defining your Azure infrastructure. HCL has a straightforward syntax that is easy to learn, even for those new to programming. It uses blocks, denoted by curly braces, to define resources and other elements in your configuration.
Here are the fundamental building blocks of Terraform:
Resources
A resource is a component of your infrastructure that you can manage with Terraform. Examples of resources include virtual machines, network switches, and DNS records.
To create an Azure resource group with Terraform, you can use the azurerm_resource_group
resource. Here is an example of how to use this resource to create a resource group:
resource "azurerm_resource_group" "example" {
name = "example-rg"
location = "North Europe"
}
This resource block creates a resource group called "example-rg" in the "North Europe" location.
Variables
Variables allow you to define values that can be reused throughout your configuration. You can also use variables to parameterize your configuration, making it more flexible and easier to maintain. You can set a default value and perform validation in a variable
block. For example, you can define a variable for the location and use it in the resource block like this:
variable "location" {
description = "The region where the resource will be deployed"
type = string
default = "North Europe"
validation {
condition = can(regex("^West Europe$|^North Europe$", var.location))
error_message = "Location can be either `West Europe` or `North Europe`."
}
}
resource "azurerm_resource_group" "example" {
name = "example-rg"
location = var.location
}
Outputs
Outputs allow you to display values after a Terraform run. They can be used to display important information about your infrastructure, such as IP addresses or resource IDs.
variable "location" {
description = "The region where the resource will be deployed"
type = string
default = "North Europe"
validation {
condition = can(regex("^West Europe$|^North Europe$", var.location))
error_message = "Location can be either `West Europe` or `North Europe`."
}
}
resource "azurerm_resource_group" "example" {
name = "example-rg"
location = var.location
}
output "resource_group_name" {
description = "Name of the resource group"
value = azurerm_resource_group.example.name
}
Modules
Modules are self-contained packages of Terraform configurations that can be shared and reused across multiple projects. Modules allow you to define reusable blocks of infrastructure that you can use in your configurations, making it easier to manage your infrastructure as code.
Modules can include resources, variables, outputs, and other elements that are required to create and manage your infrastructure. They can be used to define complex infrastructure architectures or to simplify the process of creating and managing resources. In Chapter 6, we will cover how to use modules in your code. However, here is an example of how to use a module in your Terraform configuration:
module "resource_group" {
# Source it locally
source = "path/to/module"
# Source it from registry
# source = "yasarlaro/resource-group/azurerm"
# version = "1.0.0"
resource_group_name = "example-rg"
location = "North Europe"
}
Providers
A provider is a plugin that Terraform uses to interact with a specific cloud or on-premises infrastructure. Providers must be configured in your configuration before you can use their resources. Providers are responsible for creating, updating, and deleting resources on the target platform.
The Azure Resource Manager (ARM) provider is used to interact with Azure resources. To use the ARM provider, you will need to specify it in your Terraform configuration. Here is an example of how to do this:
provider "azurerm" {
}
Data sources
Data sources allow you to fetch information about existing resources or external systems and use that information in your configurations. Data sources are read-only, which means that you cannot use them to create or modify resources.
Data sources are useful for retrieving information about existing resources or external systems that you want to use in your configuration. For example, you might use a data source to retrieve the ID of an existing Azure resource group, or to retrieve a list of available VM sizes in Azure.
Here is an example of how to use the azurerm_resource_group
data source to retrieve information about an existing Azure resource group:
data "azurerm_resource_group" "example" {
name = "example-rg"
}
output "resource_group_location" {
value = data.azurerm_resource_group.example.location
}
Provisioners
Provisioners are used to execute scripts or other actions after a resource is created, updated, or destroyed. Provisioners are typically used to configure or customize resources, or to perform other tasks that are required for the resource to be fully functional.
Provisioners are useful for performing tasks that cannot be accomplished using Terraform's built-in resources and data sources. For example, you might use a provisioner to install software on a virtual machine, or to configure a database with specific users and permissions.
There are several types of provisioners available in Terraform, including local-exec
, remote-exec
, and file
. Here is an example of how to use the local-exec
provisioner to execute a script on a local machine after creating an Azure virtual machine:
resource "azurerm_virtual_machine" "example" {
# ... other resource properties omitted for brevity
provisioner "local-exec" {
command = "./configure-vm.sh"
}
}
Terraform state
Terraform state is a record of your infrastructure and the resources that have been created as part of that infrastructure. Terraform stores the state in a file or in a remote storage location, such as Azure Storage or Terraform Cloud.
The state is an important part of the Terraform workflow, as it allows Terraform to know what resources exist and what their current properties are. When you make changes to your infrastructure using Terraform, the state is updated to reflect those changes.
Here is an example of how to use an existing Azure Storage account to store the state file:
terraform {
#... other properties omitted for brevity
backend "azurerm" {
resource_group_name = "rg-common-tf-state-neu"
storage_account_name = "onursa001"
container_name = "tfstate"
key = "dev.basic-infra.tfstate"
}
}
In this example, the terraform
block is used to specify that the state should be stored in the Azure Storage account using the Azure Resource Manager (ARM) backend. The resource_group_name
property specifies the resource group name of the storage account, storage_account_name
property specifies the name of the storage account, the container_name
property specifies the name of the container in the storage account where the state should be stored, and the key
property specifies the name of the state file.
You cannot use variables
, locals
, or data
resources in a backend block. If you try to do so, you will receive output similar to the example below:
Initializing the backend...
|
| Error: Variables not allowed
|
| on main.tf line 47, in terraform:
| 47: storage_account_name = azurerm_storage_account.example.name
|
| Variables may not be used here.
The state is an important part of the Terraform workflow and is used to track the resources that have been created as part of your infrastructure. By storing the state in a remote location, such as Azure Storage, you can ensure that the state is accessible.
When using an Azure Storage Account, Terraform will automatically lock your state file during any state-writing operations to prevent others from corrupting it. Details about this operation can be reviewed here.
You can also import existing resources into your state file by following the examples provided in the Terraform resource documentation. For example, the azurerm_resource_group resource definition includes instructions for importing an existing resource to a state file.
terraform import azurerm_resource_group.example <Azure Resource ID>
Last updated