Before we start, let me talk briefly about each tools and what is it used for:
- Terraform is Infrastructure as Code(IaC) tool from HashiCorp that automates the provisioning, updating, and destruction of infrastructure resources.
- Azure is a cloud computing platform. Azure offers a wide range of cloud services, including compute, storage, networking, analytics, and AI.
In this article, we will cover:
- Variable
- Input
- Output
- Locals
- File and Directory Structure
- Meta Arguments
- Data Sources
- Module
- Dynamic Block
- Override files
- Function
We will continue from Setup Terraform for Azure
Variable
There are 3 types of variables in terraform: Input, Output, Local
Input
Input Variables allow you to customize aspects of Terraform modules without altering the module's own source code, just like function arguments.
To use variable in terraform, first you need to declare it like below:
variable "environment" {
type = string
description = "value of the environment to deploy to"
default = "dev"
}
After that, you can call it by using the key word var
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "Southeast Asia"
tags = {
environment = var.environment
}
}
There are also different ways to declare variables by passing it as argument
terraform plan -var=environment=staging
Or put it in .tfvar
file
# terraform.tfvars
environment = "dev"
Only terraform.tfvars
and *.auto.tfvars
are loaded automatically, otherwise you need to pass it as argument -var-file="environment .tfvars"
Or declare it the environment itself
export environment = dev
Priority:
-var= and -var-file=
> *.auto.tfvars
> terraform.tfvars
> Environment variables
> variable.tf
Check the official document
Output
Out Values make information about your infrastructure available on the command line, and can expose information for other Terraform configurations to use, just like function return values.
Output is easy to create by using output block with value variables.
output "resource_group_id" {
value = azurerm_resource_group.example.id
description = "The ID of the resource group"
}
You can use terraform output
to show only output
Check the official document
Local
A local value assigns a name to an expression, so you can use the name multiple times within a module instead of repeating the expression. just like a function's temporary local variables.
You can declare it in single block or multiple
locals {
env = var.environment
location= "Southeast Asia"
}
locals {
tags = {
environment = local.env
created_by = "Terraform"
}
}
# Create a resource group
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = local.location
tags = local.tags
}
Check the official document
File and Directory Structure
I separate blocks into smaller file, so it will be easier to maintain.
# local.tf
locals {
tags = {
environment = var.environment
created_by = "Terraform"
}
}
# output.tf
output "resource_group_id" {
value = azurerm_resource_group.example.id
description = "The ID of the resource group"
}
# provider.tf
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=3.0.0"
}
}
}
provider "azurerm" {
features {}
}
# rg.tf
# Create a resource group
resource "azurerm_resource_group" "example" {
name = "example-resources"
location = "Southeast Asia"
tags = local.tags
}
# terraform.tfvars
environment = "prod"
# variables.tf
variable "environment" {
type = string
description = "value of the environment to deploy to"
default = "dev"
}
Meta Arguments
There are 5 meta arguments: depends_on, count, for_each, provider, lifecycle.
depends_on
Use the depends_on
meta-argument to handle hidden resource or module dependencies that Terraform cannot automatically infer.
resource "azurerm_private_dns_zone_group" "example" {
name = "example-dns-zone-group"
private_endpoint_id = azurerm_private_endpoint.example.id
private_dns_zone_configs {
name = "example"
private_dns_zone_id = azurerm_private_dns_zone.example.id
}
depends_on = [
azurerm_private_endpoint.example,
azurerm_storage_account.example
]
}
count
The count
meta-argument accepts a whole number, and creates that many instances of the resource or module.
resource "azurerm_resource_group" "example" {
count = 2
name = "example-resources-${count.index}"
location = "Southeast Asia"
tags = {
tags = local.tags
}
}
for_each
The for_each
meta-argument accepts a map or a set of strings, and creates an instance for each item in that map or set.
resource "azurerm_resource_group" "rg" {
for_each = tomap({
a_group = "eastus"
another_group = "westus2"
})
name = each.key
location = each.value
}
or
resource "azurerm_resource_group" "rg" {
for_each = toset(["rg1", "rg1", "rg1", "rg1"])
name = each.key
}
provider
The provider meta-argument specifies which provider configuration to use for a resource, overriding Terraform's default behavior of selecting one based on the resource type name.
provider "azurerm" {
features {}
}
lifecycle
lifecycle
is a nested block that can appear within a resource block. The lifecycle block and its contents are meta-arguments, available for all resource blocks regardless of type.
The arguments available within a lifecycle block are create_before_destroy
, prevent_destroy
, ignore_changes
, and replace_triggered_by
.
resource "azurerm_resource_group" "example" {
count = 2
name = "example-resources-${count.index}"
location = "Southeast Asia"
tags = {
tags = local.tags
}
lifecycle {
create_before_destroy = true
prevent_destroy = true
ignore_changes = [
tags,
]
replace_triggered_by = [
local.tags.environment
]
}
}
Check the official document
Data Sources
A data
block requests data source from resources that already are created by external resource.
# Get Resources from a Resource Group
data "azurerm_resources" "example" {
resource_group_name = "example-resources"
}
output "rg_id" {
value = data.azurerm_resources.example.id
}
Module
A Terraform module is a set of Terraform configuration files in a single directory. Even a simple configuration consisting of a single directory with one or more .tf files is a module.
- Root module is the entry point of your infrastructure configuration, typically located in the main working directory.
- Child modules are reusable components called from the root module or other child modules. Here is a example of the module with a root modules and two child modules
See the example here
Dynamic Block
A dynamic block acts much like a for expression, but produces nested blocks instead of a complex typed value. It iterates over a given complex value, and generates a nested block for each element of that complex value.
# main.tf
data "azurerm_subnet" "example" {
name = "subnetname"
virtual_network_name = "vnetname"
resource_group_name = "resourcegroupname"
}
resource "azurerm_storage_account" "example" {
name = "storageaccountname"
resource_group_name = "rgname"
location = "West Europe"
account_tier = "Standard"
account_replication_type = "LRS"
dynamic "network_rules" {
for_each = var.network_rules
content {
default_action = network_rules.value["default_action"]
ip_rules = network_rules.value["ip_rules"]
virtual_network_subnet_ids = data.azurerm_subnet.example.id
}
}
}
# variable.tf
variable "network_rules" {
type = list(object({
default_action = string
ip_rules = list(string)
}))
description = "values for the network rules block in the storage account resource."
}
# terraform.tfvars
network_rules = [
{
default_action = "Deny"
ip_rules = ["100.0.0.1"]
},
{
default_action = "Allow"
ip_rules = ["100.0.0.2"]
}
]
Override files
Terraform normally loads all of the .tf and .tf.json files within a directory and expects each one to define a distinct set of configuration objects. If two files attempt to define the same object, Terraform returns an error.
In some rare cases, it is convenient to be able to override specific portions of an existing configuration object in a separate file.
# example.tf
resource "azurerm_resource_group" "example" {
name = "example-resources1"
location = "Southeast Asia"
}
# override.tf
resource "azurerm_resource_group" "example" {
location = "West Europe"
}
merge result
resource "azurerm_resource_group" "example" {
name = "example-resources1"
location = "Wast Europe"
}
Function
The Terraform language includes a number of built-in functions that you can call from within expressions to transform and combine values.
> max(5, 12, 9)
12
> ceil(5)
5
> ceil(5.1)
6
> split(",", "foo,bar,baz")
[
"foo",
"bar",
"baz",
]
> split(",", "foo")
[
"foo",
]
> split(",", "")
[
"",
]
...
Check the official document
Leave a comment if you have any questions.
===========
Please keep in touch
Portfolio
Linkedin
Github
Youtube
Hey everyone! We’re launching your special Dev.to drop for all verified Dev.to authors. Click here here to see if you qualify (no gas fees). – Admin