🐶
Terraform

Terraform Looping: Create Multiple Resources

By Filip on 11/11/2024

Learn how to efficiently provision and manage multiple cloud resources using Terraform's powerful for loop functionality.

Terraform Looping: Create Multiple Resources

Table of Contents

Introduction

Terraform's for_each meta-argument provides a powerful way to create multiple resources with varying configurations without repetitive code. This approach leverages data structures like maps or lists to define the configuration for each resource instance.

Step-by-Step Guide

To create multiple resources in Terraform using a loop, you can use the for_each meta-argument.

First, define a data structure like a map or a list to hold the configuration for each resource:

variable "servers" {
  default = {
    "server1" = {
      instance_type = "t2.micro"
      ami           = "ami-0c55b159bfd0c7bd0"
    },
    "server2" = {
      instance_type = "t2.small"
      ami           = "ami-0c55b159bfd0c7bd0"
    }
  }
}

Then, in your resource block, use for_each to iterate over the data structure:

resource "aws_instance" "app_server" {
  for_each = var.servers

  name            = each.key
  instance_type = each.value.instance_type
  ami             = each.value.ami
}

Within the resource block, you can access the current element's key and value using each.key and each.value, respectively.

This approach allows you to create multiple instances of a resource with different configurations based on the provided data structure.

Code Example

This Terraform code defines infrastructure on AWS. It sets up two EC2 instances (virtual servers) with different types and a shared AMI. The code uses a variable to define server configurations, making it easy to manage multiple instances. Each instance is tagged for identification.

# Configure the AWS Provider
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
}

# Configure the AWS Region
provider "aws" {
  region = "us-west-2" # Replace with your desired region
}

# Define a variable to hold server configurations
variable "servers" {
  default = {
    "server1" = {
      instance_type = "t2.micro"
      ami           = "ami-0c55b159bfd0c7bd0" # Replace with your desired AMI ID
    },
    "server2" = {
      instance_type = "t2.small"
      ami           = "ami-0c55b159bfd0c7bd0" # Replace with your desired AMI ID
    }
  }
}

# Create AWS instances using the for_each loop
resource "aws_instance" "app_server" {
  for_each = var.servers

  ami           = each.value.ami
  instance_type = each.value.instance_type
  name            = each.key

  tags = {
    Name = "App Server - ${each.key}"
  }
}

Explanation:

  1. Variable servers: This variable defines a map where each key represents a server name and the value is an object containing the instance type and AMI ID for that server.
  2. Resource aws_instance:
    • for_each = var.servers: This line iterates over the servers map.
    • ami = each.value.ami: Sets the AMI ID for each instance based on the ami value in the servers map.
    • instance_type = each.value.instance_type: Sets the instance type for each instance based on the instance_type value in the servers map.
    • name = each.key: Assigns a unique name to each instance using the key from the servers map.
    • tags: Adds a tag "Name" to each instance for easy identification.

How to run:

  1. Save the code as a .tf file (e.g., main.tf).
  2. Run terraform init to initialize the Terraform working directory.
  3. Run terraform apply to create the resources.

This code will create two EC2 instances on AWS, one named "server1" with type "t2.micro" and another named "server2" with type "t2.small", both using the specified AMI.

Additional Notes

General:

  • Purpose: The primary use case for for_each is to avoid code repetition when creating multiple resources with similar configurations but varying parameters.
  • Alternatives: Before using for_each, consider if count would be a simpler solution. Use count for creating multiple instances of a resource with identical configurations.
  • Dynamic File Naming: Combine for_each with template interpolation to dynamically generate unique names for files, scripts, or other resources.
  • Error Handling: If an error occurs within a for_each loop, Terraform will halt the execution. Consider using the try() function within the loop for more robust error handling.

Data Structures:

  • Maps vs. Lists: Use maps when you need to access elements by a specific key (like server names in the example). Use lists when the order of elements is important.
  • Nested Structures: You can use for_each with nested data structures to create complex resource relationships.
  • Dynamic Data Sources: Populate the data structure used in for_each with outputs from other resources or data sources for more dynamic configurations.

Best Practices:

  • Clear Naming: Use descriptive names for keys in your data structures to improve code readability.
  • Modularity: For complex scenarios, consider encapsulating the for_each logic within a Terraform module for better organization and reusability.
  • Testing: Thoroughly test your Terraform code with different input values to ensure the for_each loop behaves as expected.

Beyond the Basics:

  • Conditional Creation: Combine for_each with conditional expressions to create resources selectively based on specific criteria.
  • Iteration over Multiple Resources: While not directly supported, you can achieve iteration over multiple resources by combining for_each with other Terraform features like flatten() and nested loops. However, this can lead to complex code and should be used with caution.

By understanding these nuances and best practices, you can leverage the full potential of for_each to write efficient and maintainable Terraform code.

Summary

This article explains how to create multiple resources in Terraform using the for_each meta-argument and a loop.

Key Points:

  • Data Structure: Define a map or list (e.g., variable "servers") to store the configuration for each resource you want to create. Each element in the data structure represents a single resource.
  • for_each Meta-Argument: In your resource block (e.g., resource "aws_instance" "app_server"), use for_each and assign it to your data structure variable (e.g., for_each = var.servers).
  • Accessing Values: Within the resource block, use each.key to access the current element's key (e.g., "server1") and each.value to access its corresponding value (e.g., {instance_type = "t2.micro", ami = "ami-0c55b159bfd0c7bd0"}).
  • Dynamic Resource Creation: This approach allows you to create multiple instances of a resource (e.g., AWS instances) with different configurations based on the data provided in your defined structure.

Example:

The provided code snippet demonstrates creating two AWS instances ("server1" and "server2") with different instance types ("t2.micro" and "t2.small") using a map variable and the for_each loop.

Conclusion

By combining the for_each meta-argument with data structures, Terraform empowers you to manage infrastructure as code more efficiently. This approach reduces code duplication, enhances readability, and allows for flexible resource provisioning based on your specific needs. Understanding the nuances of for_each, such as its use with different data structures and its interaction with other Terraform features, will significantly enhance your ability to write clean, maintainable, and powerful infrastructure code.

References

Were You Able to Follow the Instructions?

😍Love it!
😊Yes
😐Meh-gical
😞No
🤮Clickbait