Manage similar resources with for each
Terraform's for_each
meta-argument allows you to configure a set of similar
resources by iterating over a data structure to configure a resource or module
for each item in the data structure. You can use for_each
to customize a set
of similar resources that share the same lifecycle.
In this tutorial, you will provision a VPC, load balancer, and EC2 instances on
AWS. Then you will refactor your configuration to provision multiple projects
with the for_each
argument and a data structure.
Prerequisites
You can complete this tutorial using the same workflow with either Terraform Community Edition or HCP Terraform. HCP Terraform is a platform that you can use to manage and execute your Terraform projects. It includes features like remote state and execution, structured plan output, workspace resource summaries, and more.
Select the Terraform Community Edition tab to complete this tutorial using Terraform Community Edition.
This tutorial assumes that you are familiar with the Terraform and HCP Terraform workflows. If you are new to Terraform, complete Get Started collection first. If you are new to HCP Terraform, complete the HCP Terraform Get Started tutorials first.
For this tutorial, you will need:
- Terraform v1.2+ installed locally.
- an HCP Terraform account and organization.
- HCP Terraform locally authenticated.
- the AWS CLI.
- an HCP Terraform variable set configured with your AWS credentials.
Apply initial configuration
Clone the example GitHub repository.
Change into the new directory.
The configuration in main.tf
provisions a VPC with public and private subnets,
a load balancer, and EC2 instances in each private subnet. The variables located
in variables.tf
allow you to configure the VPC. For instance, the
private_subnets_per_vpc
variable controls the number of private subnets the
configuration will create.
Set the TF_CLOUD_ORGANIZATION
environment variable to your HCP Terraform
organization name. This will configure your HCP Terraform integration.
Initialize your configuration. Terraform will automatically create the
learn-terraform-for-each
workspace in your HCP Terraform organization.
Note
This tutorial assumes that you are using a tutorial-specific HCP Terraform organization with a global variable set of your AWS credentials. Review the Create a Credential Variable Set for detailed guidance. If you are using a scoped variable set, assign it to your new workspace now.
Once your directory has been initialized, apply the configuration, and remember
to confirm with a yes
.
Refactor the VPC and related configuration so that Terraform can deploy multiple projects at the same time, each with their own VPC and related resources.
Note
Use separate Terraform projects or
workspaces instead of for_each
to manage resource lifecycles independently. For example, if production and
development environments share the same Terraform project running terraform
destroy
will destroy both.
Define a map to configure each project
Define a map for project configuration in variables.tf
that for_each
will
iterate over to configure each resource.
Note
The for_each
argument also supports lists and sets.
The project
variable replaces several of the variables defined in your
configuration. Remove these variable definitions from variables.tf
.
Add for_each
to the VPC
Now use for_each
to iterate over the project
map in the VPC module block of
main.tf
, which will create one VPC for each key/value pair in the map.
This Terraform configuration defines multiple VPCs, assigning each key/value
pair in the var.project
map to each.key
and each.value
respectively. When
you use for_each
with a list or set, each.key
is the index of the item in
the collection, and each.value
is the value of the item.
In this example, the project map includes values for the number of private and
public subnets in each VPC. Update the subnet configuration in the vpc
module
block in main.tf
to use each.value
to refer to these values.
Update the app_security_group
module to iterate over the project variable to
get the security group name, VPC ID, and CIDR blocks for each project.
You can differentiate between instances of resources and modules configured with
for_each
by using the keys of the map you use. In this example,
using module.vpc[each.key].vpc_id
to define the VPC means that the security
group for a given project will be assigned to the corresponding VPC.
Update the load balancer and its security group
Update the configuration for the load balancer security groups to iterate over
the project
variable to get their names and VPC IDs.
Update the elb_http
block so that each VPC's load balancer name will also include the name of the project, the
environment, and will use the corresponding security groups and subnets.
Move EC2 instance to a module
You will also need to update the instance resource block to assign EC2 instances
to each VPC. However, the block already uses count
. You cannot use both
count
and for_each
in the same block.
To solve this, you will move the aws_instance
resource into a module,
including the count
argument, and then use for_each
when referring to the
module in your main.tf
file. The example repository includes a module with
this configuration in the modules/aws-instance
directory. For a detailed example on how to move a configuration to a local module, try the Create a Terraform Module tutorial.
Remove the resource "aws_instance" "app"
and data "aws_ami" "amazon_linux"
blocks from your root module's main.tf
file, and replace them with a reference
to the aws-instance
module.
Note
You cannot include a provider block in modules that use count
or
for_each
. They must inherit provider configuration from the root module.
Resources created by the module will all use the same provider configuration.
Next, replace the references to the EC2 instances in the module "elb_http"
block with references to the new module.
Finally, replace the entire contents of outputs.tf
in your root module with
the following.
The for
expressions used here will map the project names to the corresponding
values in the Terraform output.
Note
for
and for_each
are different features. for_each
provisions
similar resources in module and resource blocks. for
creates a list or map
by iterating over a collection, such as another list or map. You can read more
about for
expressions in the Terraform
documentation.
Apply scalable configuration
Initialize the new module.
Now apply the changes. Remember to respond to the confirmation prompt with
yes
.
This configuration creates separate VPCs for each project defined in
variables.tf
. count
and for_each
allow you to create more flexible
configurations, and reduce duplicate resource and module blocks.
Clean up resources
After verifying that the projects deployed successfully, run terraform destroy
to destroy them. Remember to respond to the confirmation prompt with yes
.
If you used HCP Terraform for this tutorial, after destroying your resources,
delete the learn-terraform-for-each
workspace from your HCP Terraform
organization.
Next steps
Now that you have used for_each
in your configuration, explore the
following resources.
- Read the Terraform documentation for the for_each meta-argument.
- Learn how to use the
count
meta-argument. - Learn how to create and use Terraform modules.