A Beginner's Guide to Terraform Loops: Deploying Multiple Resources and Using Conditional Logic

·

5 min read

Introuduction

Terraform provides powerful constructs for automating and scaling your infrastructure. Among these, loops and conditionals help you avoid repetition by programmatically managing resources. In this guide, we'll dive into Terraform loops, covering the count and for_each parameters, conditional deployments, and advanced looping techniques.

Why Use Loops in Terraform?

  • Efficiency: Automate repetitive tasks by deploying multiple instances of a resource with just a few lines of code.

  • Flexibility: Dynamically deploy resources based on input variables or environment configurations.

  • Simplification: Reduce boilerplate code by looping over lists or maps and iterating over infrastructure resources.

Terraform Loops: count vs. for_each

Terraform provides two main constructs for looping over resources: count and for_each. Let's explore both.

1. Loops with the count Parameter

The count parameter allows you to deploy multiple instances of the same resource. For example, you can create multiple EC2 instances with a single resource block by specifying how many instances should be deployed.

Example: Deploying Multiple EC2 Instances with count

resource "aws_instance" "web" {
  count         = 3
  ami           = "ami-12345678"
  instance_type = "t2.micro"
  tags = {
    Name = "web-${count.index}"
  }
}

In this example:

  • Terraform will deploy 3 EC2 instances.

  • The count.index is used to name each instance uniquely.

2. Loops with the for_each Parameter

The for_each parameter allows you to loop over a list or map, deploying a unique resource for each element in the collection. This is especially useful when you want to manage a variable number of resources based on dynamic input.

Example: Deploying S3 Buckets with for_each

resource "aws_s3_bucket" "buckets" {
  for_each = {
    dev  = "dev-bucket"
    prod = "prod-bucket"
    test = "test-bucket"
  }

  bucket = each.value
  tags = {
    Name        = each.value
    Environment = each.key
  }
}

In this example:

  • Terraform deploys three S3 buckets (for dev, prod, and test).

  • The bucket name and environment are dynamically set based on the map.

Advanced Looping in Terraform

Beyond count and for_each, Terraform offers additional looping constructs, such as for expressions and the for string directive.

1. Loops with for Expressions

for expressions are used to transform and filter lists and maps in Terraform. They allow you to iterate over a collection and produce a new collection based on the results.

Example: Filtering a List with a for Expression

variable "instance_types" {
  type    = list(string)
  default = ["t2.micro", "t2.small", "t2.medium", "t2.large"]
}

output "filtered_instance_types" {
  value = [for instance in var.instance_types : instance if instance != "t2.large"]
}

In this example:

  • Terraform filters out t2.large from the list of instance types and outputs the remaining types.
2. Loops with the for String Directive

Terraform also supports looping over strings with the for directive, which can be useful for constructing strings dynamically.

Example: Constructing a Comma-Separated String with for

variable "regions" {
  type    = list(string)
  default = ["us-west-1", "us-east-1", "eu-west-1"]
}

output "regions_string" {
  value = join(", ", [for region in var.regions : region])
}

In this example:

  • Terraform joins the list of regions into a single comma-separated string.

Conditional Deployments in Terraform

In addition to loops, Terraform allows you to control the deployment of resources conditionally based on input variables or other criteria. Conditional logic helps you manage different environments or configurations dynamically.

1. Using Conditionals with count

You can use conditionals with the count parameter to decide whether to deploy a resource.

Example: Conditional Resource Deployment with count

variable "create_bucket" {
  type    = bool
  default = true
}

resource "aws_s3_bucket" "example" {
  count  = var.create_bucket ? 1 : 0
  bucket = "conditional-bucket"
}

In this example:

  • The S3 bucket will only be deployed if the create_bucket variable is set to true.
2. Using Conditionals with for_each

You can also apply conditionals with for_each to control resource deployment based on dynamic criteria.

Example: Deploying Resources Based on Environment with for_each

variable "environments" {
  type = list(string)
  default = ["dev", "prod"]
}

resource "aws_instance" "web" {
  for_each = { for env in var.environments : env => env if env != "dev" }

  ami           = "ami-12345678"
  instance_type = "t2.micro"
  tags = {
    Name = "web-${each.key}"
  }
}

In this example:

  • Terraform deploys an EC2 instance for each environment, but skips the dev environment.

Putting It All Together

Here's a complete Terraform configuration that demonstrates various loops and conditionals in action.

provider "aws" {
  region = "us-west-2"
}

variable "instance_types" {
  type    = list(string)
  default = ["t2.micro", "t2.small", "t2.medium"]
}

variable "deploy_in_prod" {
  type    = bool
  default = false
}

resource "aws_instance" "web" {
  count         = var.deploy_in_prod ? length(var.instance_types) : 0
  instance_type = var.instance_types[count.index]
  ami           = "ami-12345678"

  tags = {
    Name = "web-instance-${count.index}"
  }
}

resource "aws_s3_bucket" "buckets" {
  for_each = { for type in var.instance_types : type => type if type != "t2.medium" }

  bucket = "${each.value}-bucket"
  tags = {
    Name = "${each.value}-bucket"
  }
}

output "instance_tags" {
  value = [for instance in aws_instance.web : instance.tags["Name"]]
}

In this configuration:

  • EC2 instances are only deployed if deploy_in_prod is set to true.

  • The S3 bucket is deployed for all instance types except t2.medium.

  • The output block returns the names of the deployed EC2 instances.

Conclusion

Terraform's looping constructs—count, for_each, for expressions, and string directives—enable you to write cleaner, more scalable infrastructure code. Combined with conditionals, they allow you to manage dynamic infrastructure configurations based on your specific needs.

By understanding how to effectively use loops and conditionals, you can simplify your Terraform configurations, making them more maintainable and adaptable to different environments. With this knowledge, you're now ready to start automating repetitive tasks and deploying scalable infrastructure with Terraform.