🚀 DevOps & SRE Certification Program 📅 Starting: 1st of Every Month 🤝 +91 8409492687 🔍 Contact@DevOpsSchool.com

Upgrade & Secure Your Future with DevOps, SRE, DevSecOps, MLOps!

We spend hours on Instagram and YouTube and waste money on coffee and fast food, but won’t spend 30 minutes a day learning skills to boost our careers.
Master in DevOps, SRE, DevSecOps & MLOps!

Learn from Guru Rajesh Kumar and double your salary in just one year.


Get Started Now!

Terraform Tutorials: How to do Loop / Iterate in Terraform?

Resources
Resources are the most important element in the Terraform language. Each resource block describes one or more infrastructure objects, such as virtual networks, compute instances, or higher-level components such as DNS records supported by providers.

Resources type
Each resource is associated with a single resource type, which determines the kind of infrastructure object it manages and what arguments and other attributes the resource supports.

Provider
Each resource type in turn belongs to a provider, which is a plugin for Terraform that offers a collection of resource types. A provider usually provides resources to manage a single cloud or on-premises infrastructure platform.

Resource Behavior by Meta-Arguments
Resource Behavior by Meta-Arguments, which can be used with any resource type to change the behavior of resources:

  • depends_on, for specifying hidden dependencies
  • count, for creating multiple resource instances according to a count
  • for_each, to create multiple instances according to a map, or set of strings
  • provider, for selecting a non-default provider configuration
    lifecycle, for lifecycle customizations
  • provisioner and connection, for taking extra actions after resource creation

count: which allows Multiple Resource Instances By Count

Out of these, count: which allows Multiple Resource Instances By Count and this Meta-Arguments can be used to Multiply resources which can be used as an alternative to Looping and Interators in Terraform.


resource "aws_instance" "example" {
  ami = "ami-2d39803a"
  instance_type = "t2.micro"
}

###### WRONG WAY ###### 
for i = 0; i < 3; i++ {
  resource "aws_instance" "example" {
    ami = "ami-2d39803a"
    instance_type = "t2.micro"
  }  
}

###### RIGHT WAY ###### 
resource "aws_instance" "example" {
  count = 3
  ami = "ami-2d39803a"
  instance_type = "t2.micro"
}

for_each: Multiple Resource Instances Defined By a Map, or Set of Strings.

If your resource instances are almost identical, count is appropriate. If some of their arguments need distinct values that can’t be directly derived from an integer, it’s safer to use for_each.

Before for_each was available, it was common to derive count from the length of a list and use count.index to look up the original list value:


variable "subnet_ids" {
  type = list(string)
}

resource "aws_instance" "server" {
  # Create one instance for each subnet
  count = length(var.subnet_ids)

  ami           = "ami-a1b2c3d4"
  instance_type = "t2.micro"
  subnet_id     = var.subnet_ids[count.index]

  tags {
    Name = "Server ${count.index}"
  }
}

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. Each instance has a distinct infrastructure object associated with it (as described above in Resource Behavior), and each is separately created, updated, or destroyed when the configuration is applied.


resource "azurerm_resource_group" "rg" {
  for_each = {
    a_group = "eastus"
    another_group = "westus2"
  }
  name     = each.key
  location = each.value
}
provider "github" {
token = ""
organization = "devopsschool-demo-temporary"
}
variable "repo-name" {
type = map
default = {
"repo1" = "devops1"
"repo2" = "devops2"
"repo3" = "devops3"
}
}
resource "github_repository" "repogithub" {
for_each = var.repo-name
name = "${each.value}-devopsschool"
}
# Use Case of for_each
variable "account_name" {
type = map
default = {
"account1" = "devops1"
"account2" = "devops2"
"account3" = "devops3"
}
}
resource "aws_iam_user" "iamuser" {
for_each = var.account_name
name = "${each.value}-iam"
}
terraform {
required_version = ">= 0.12.0"
}
# List of letters
variable "letters" {
description = "a list of letters"
default = ["a", "b", "c"]
}
# Convert letters to upper-case as list
output "upper-case-list" {
value = [for l in var.letters: upper(l)]
}
# Convert letters to upper-case as map
output "upper-case-map" {
value = {for l in var.letters: l => upper(l)}
}
variable "vm_name_pfx" {
description = "VM Names"
default = "test-vm-"
type = string
}
variable "vm_count" {
description = "Number of Virtual Machines"
default = 3
type = string
}
resource "azurerm_windows_virtual_machine" "vm" {
count = var.vm_count # Count Value read from variable
name = "${var.vm_name_pfx}-${count.index}" # Name constructed using count and pfx
resource_group_name = azurerm_resource_group.rg.name
location = var.location
size = "Standard_F2"
admin_username = var.vm_admin_login
admin_password = var.vm_admin_password
tags = var.tags
network_interface_ids = [
azurerm_network_interface.nic[count.index].id,
]
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter"
version = "latest"
}
}
terraform {
required_version = ">= 0.12.0"
}
provider "aws" {
region = "us-east-1"
}
resource "aws_vpc" "my_vpc" {
cidr_block = "172.16.0.0/16"
tags = {
Name = "tf-0.12-for-example"
}
}
resource "aws_subnet" "my_subnet" {
vpc_id = aws_vpc.my_vpc.id
cidr_block = "172.16.10.0/24"
tags = {
Name = "tf-0.12-for-example"
}
}
data "aws_ami" "ubuntu_14_04" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm/ubuntu-trusty-14.04-amd64-server-*"]
}
owners = ["099720109477"]
}
resource "aws_instance" "ubuntu" {
count = 3
ami = data.aws_ami.ubuntu_14_04.image_id
instance_type = "t2.micro"
associate_public_ip_address = ( count.index == 1 ? true : false)
subnet_id = aws_subnet.my_subnet.id
tags = {
Name = format("terraform-0.12-for-demo-%d", count.index)
}
}
# This uses the old splat expression
output "private_addresses_old" {
value = aws_instance.ubuntu.*.private_dns
}
# This uses the new full splat operator (*)
output "private_addresses_full_splat" {
value = [ aws_instance.ubuntu[*].private_dns ]
}
# This uses the new for expression
output "private_addresses_new" {
value = [
for instance in aws_instance.ubuntu:
instance.private_dns
]
}
# This uses the new conditional expression
# that can work with lists
# This uses the list interpolation function
output "ips_with_list_interpolation" {
value = [
for instance in aws_instance.ubuntu:
(instance.public_ip != "" ? list(instance.private_ip, instance.public_ip) : list(instance.private_ip))
]
}
# It also works with lists in [x, y, z] form
output "ips_with_list_in_brackets" {
value = [
for instance in aws_instance.ubuntu:
(instance.public_ip != "" ? [instance.private_ip, instance.public_ip] : [instance.private_ip])
]
}

More reading can be done here

https://www.terraform.io/docs/configuration/resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings

Certification Courses

DevOpsSchool has introduced a series of professional certification courses designed to enhance your skills and expertise in cutting-edge technologies and methodologies. Whether you are aiming to excel in development, security, or operations, these certifications provide a comprehensive learning experience. Explore the following programs:

DevOps Certification, SRE Certification, and DevSecOps Certification by DevOpsSchool

Explore our DevOps Certification, SRE Certification, and DevSecOps Certification programs at DevOpsSchool. Gain the expertise needed to excel in your career with hands-on training and globally recognized certifications.