HashiCorp Learn
Infrastructure
  • TerraformTerraformLearn terraformDocs
  • PackerPackerLearn packerDocs
  • VagrantVagrantLearn vagrantDocs
Security
  • VaultVaultLearn vaultDocs
  • BoundaryBoundaryLearn boundaryDocs
Networking
  • ConsulConsulLearn consulDocs
Applications
  • NomadNomadLearn nomadDocs
  • WaypointWaypointLearn waypointDocs
  • HashiCorp Cloud Platform (HCP) LogoHashiCorp Cloud Platform (HCP)HashiCorp Cloud Platform (HCP)Docs
Type '/' to Search
Loading account...
  • Bookmarks
  • Manage Account
  • Overview
  • Prerequisites
  • Apply initial configuration
  • Refactor the EC2 configuration
  • Declare a variable for instance number
  • Scale EC2 configuration with count
  • Update the load balancer
  • Apply scalable configuration
  • Clean up resources
  • Next steps
DocsForum
Back to terraform
Configuration LanguageView Collection
    Define Infrastructure with Terraform ResourcesCustomize Terraform Configuration with VariablesProtect Sensitive Input VariablesSimplify Terraform configuration with localsOutput Data From TerraformCreate Resource DependenciesManage Similar Resources with CountManage Similar Resources with For EachPerform Dynamic Operations with FunctionsCreate Dynamic ExpressionsLock and Upgrade Provider Versions

Manage Similar Resources with Count

  • 5 min
  • Products Usedterraform
  • This tutorial also appears in: 0.13 Release.

In this tutorial, you will use Terraform to provision a VPC, load balancer, and EC2 instances on AWS. Then you will use the count argument to provision multiple EC2 instances per private subnet with a single resource block.

The count argument replicates the given resource or module a specific number of times with an incrementing counter. It works best when resources will be identical, or nearly so.

Tip: Terraform 0.13 supports count on both resource and module blocks. Prior versions only supported it on resource blocks.

»Prerequisites

  • The Terraform CLI, version 0.13 or later.
  • AWS Credentials configured for use with Terraform.
  • The git CLI.

»Apply initial configuration

Clone the example GitHub repository.

$ git clone https://github.com/hashicorp/learn-terraform-count-foreach.git

Change into the new directory.

$ cd learn-terraform-count-foreach

Check out the initial configuration.

$ git checkout tags/count-initial-configuration -b count-initial-configuration

The configuration in main.tf will provision a new VPC with public and private subnets, a load balancer, and two EC2 instances, one 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.

Initialize Terraform in this directory. Terraform will install the AWS provider and the vpc, app_security_group, lb_security_group, and elb_http modules.

$ terraform init

Once your directory has been initialized, apply the configuration, and remember to confirm with a yes.

$ terraform apply

Note: The load balancer’s domain name is part of the output. It may take a few minutes after the apply step before you can visit this domain name. Be sure to connect via HTTP, not HTTPS.

This configuration has some limitations. Currently, each private subnet only contains one EC2 instance. If you increase the private_subnets_per_vpc variable, Terraform won’t automatically add EC2 instances, because the EC2 instance resources are hard coded.

Make this configuration more robust by adding a variable to control the number of EC2 instances in each private subnet with count.

Either make the following configuration changes manually, or check out the tag count-multiple-instances to review the new configuration.

$ git checkout tags/count-multiple-instances -b count-multiple-instances

»Refactor the EC2 configuration

Refactor the EC2 configuration to make it more generic. Remove or comment out the entire block defining the app_b EC2 instance from main.tf.

-resource "aws_instance" "app_b" {
-  ami           = data.aws_ami.amazon_linux.id
-  instance_type = var.instance_type
-
- # ...truncated...
-
-  tags = {
-    Terraform   = "true"
-    Project     = var.project_name
-    Environment = var.environment
-  }
-}

Next, rename the resource for the other EC2 instance from app_a to app.

-resource "aws_instance" "app_a" {
+resource "aws_instance" "app" {

»Declare a variable for instance number

Now, add the instances_per_subnet variable to variables.tf to define how many instances each private subnet will have.

variable instances_per_subnet {
  description = "Number of EC2 instances in each private subnet"
  type        = number
  default     = 2
}

»Scale EC2 configuration with count

Next, edit main.tf to use count to provision multiple EC2 instances with the app resource block, based on the value of the new instances_per_subnet variable and the number of private subnets.

resource "aws_instance" "app" {
+ count = var.instances_per_subnet * length(module.vpc.private_subnets)
+
  ami           = data.aws_ami.amazon_linux.id
  instance_type = var.instance_type

- subnet_id              = module.vpc.private_subnets[0]
+ subnet_id              = module.vpc.private_subnets[count.index % length(module.vpc.private_subnets)]
  vpc_security_group_ids = [module.app_security_group.this_security_group_id]

# ...truncated...

}

Each instance provisioned by the resource block with count will have a different incrementing value for count.index - starting with zero. This configuration uses count.index and modulo division to assign each instance to a private subnet.

Because the default value of instances_per_subnet is 2, Terraform will provision two EC2 instances per private subnet.

»Update the load balancer

Update the load balancer configuration in the elb_http block to attach the instances to the load balancer.

- number_of_instances = 2
- instances           = [aws_instance.app_a.id, aws_instance.app_b.id]
+ number_of_instances = length(aws_instance.app)
+ instances           = aws_instance.app.*.id

The name of resources or modules provisioned with count refers to the entire collection. In this example, aws_instance.app now refers to all of the EC2 instances. You can reference individual items in collections with the same notation as list indexing. For example, aws_instance.app[0] refers to the first instance Terraform provisions.

You can create a list of all of the values of a given attribute for the items in the collection with a star. For instance, aws_instance.app.*.id will be a list of all of the IDs of the instances.

Update outputs.tf to refer to the new aws_instance.app block instead of app_a and app_b.

output instance_ids {
  description = "IDs of EC2 instances"
- value       = [aws_instance.app_a.id, aws_instance.app_b.id]
+ value       = aws_instance.app.*.id
}

»Apply scalable configuration

Apply this configuration now.

$ terraform apply

Be sure to respond to the confirmation prompt with yes.

Terraform will output values for the VPC, load balancer, and instances.

# ...truncated...

Outputs:

instance_ids = [
  "i-0ae41b60b701e04b2",
  "i-09a9ee77a108effcd",
  "i-00a80976736aec7d0",
  "i-06b00b6352fdc1269",
]
public_dns_name = lb-2n32-client-webapp-dev-879083734.us-east-1.elb.amazonaws.com
vpc_arn = arn:aws:ec2:us-east-1:130490850807:vpc/vpc-077af8d1143193d7f

Now you have configured the number EC2 instances per private subnet using the instances_per_subnet variable and count. Terraform configured that many instances per subnet, assigned them to subnets, and attached them to the load balancer.

»Clean up resources

After verifying that the resources were deployed successfully, run terraform destroy to destroy them. Remember to respond to the confirmation prompt with yes.

$ terraform destroy

»Next steps

Now that you have used count in your configuration, explore the following resources.

  • Read the Terraform documentation for the count meta-argument.
  • Learn how to use for_each for more complex configurations.


Back to Collection
HashiCorp
  • System Status
  • Terms of Use
  • Security
  • Privacy
stdin: is not a tty