123 lines
4.7 KiB
Markdown
123 lines
4.7 KiB
Markdown
|
---
|
|||
|
layout: "language"
|
|||
|
page_title: "The count Meta-Argument - Configuration Language"
|
|||
|
---
|
|||
|
|
|||
|
# The `count` Meta-Argument
|
|||
|
|
|||
|
-> **Version note:** Module support for `count` was added in Terraform 0.13, and
|
|||
|
previous versions can only use it with resources.
|
|||
|
|
|||
|
-> **Note:** A given resource or module block cannot use both `count` and `for_each`.
|
|||
|
|
|||
|
> **Hands-on:** Try the [Manage Similar Resources With Count](https://learn.hashicorp.com/tutorials/terraform/count?in=terraform/0-13&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) tutorial on HashiCorp Learn.
|
|||
|
|
|||
|
By default, a [resource block](/docs/configuration/blocks/resources/syntax.html) configures one real
|
|||
|
infrastructure object. (Similarly, a
|
|||
|
[module block](/docs/configuration/blocks/modules/syntax.html) includes a
|
|||
|
child module's contents into the configuration one time.)
|
|||
|
However, sometimes you want to manage several similar objects (like a fixed
|
|||
|
pool of compute instances) without writing a separate block for each one.
|
|||
|
Terraform has two ways to do this:
|
|||
|
`count` and [`for_each`](/docs/configuration/meta-arguments/for_each.html).
|
|||
|
|
|||
|
If a resource or module block includes a `count` argument whose value is a whole number,
|
|||
|
Terraform will create that many instances.
|
|||
|
|
|||
|
## Basic Syntax
|
|||
|
|
|||
|
`count` is a meta-argument defined by the Terraform language. It can be used
|
|||
|
with modules and with every resource type.
|
|||
|
|
|||
|
The `count` meta-argument accepts a whole number, and creates that many
|
|||
|
instances of the resource or module. Each instance has a distinct infrastructure object
|
|||
|
associated with it, and each is separately created,
|
|||
|
updated, or destroyed when the configuration is applied.
|
|||
|
|
|||
|
```hcl
|
|||
|
resource "aws_instance" "server" {
|
|||
|
count = 4 # create four similar EC2 instances
|
|||
|
|
|||
|
ami = "ami-a1b2c3d4"
|
|||
|
instance_type = "t2.micro"
|
|||
|
|
|||
|
tags = {
|
|||
|
Name = "Server ${count.index}"
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
## The `count` Object
|
|||
|
|
|||
|
In blocks where `count` is set, an additional `count` object is
|
|||
|
available in expressions, so you can modify the configuration of each instance.
|
|||
|
This object has one attribute:
|
|||
|
|
|||
|
- `count.index` — The distinct index number (starting with `0`) corresponding
|
|||
|
to this instance.
|
|||
|
|
|||
|
## Using Expressions in `count`
|
|||
|
|
|||
|
The `count` meta-argument accepts numeric [expressions](/docs/configuration/expressions/index.html).
|
|||
|
However, unlike most arguments, the `count` value must be known
|
|||
|
_before_ Terraform performs any remote resource actions. This means `count`
|
|||
|
can't refer to any resource attributes that aren't known until after a
|
|||
|
configuration is applied (such as a unique ID generated by the remote API when
|
|||
|
an object is created).
|
|||
|
|
|||
|
## Referring to Instances
|
|||
|
|
|||
|
When `count` is set, Terraform distinguishes between the block itself
|
|||
|
and the multiple _resource or module instances_ associated with it. Instances are
|
|||
|
identified by an index number, starting with `0`.
|
|||
|
|
|||
|
- `<TYPE>.<NAME>` or `module.<NAME>` (for example, `aws_instance.server`) refers to the resource block.
|
|||
|
- `<TYPE>.<NAME>[<INDEX>]` or `module.<NAME>[<INDEX>]` (for example, `aws_instance.server[0]`,
|
|||
|
`aws_instance.server[1]`, etc.) refers to individual instances.
|
|||
|
|
|||
|
This is different from resources and modules without `count` or `for_each`, which can be
|
|||
|
referenced without an index or key.
|
|||
|
|
|||
|
Similarly, resources from child modules with multiple instances are prefixed
|
|||
|
with `module.<NAME>[<KEY>]` when displayed in plan output and elsewhere in the UI.
|
|||
|
For a module without `count` or `for_each`, the address will not contain
|
|||
|
the module index as the module's name suffices to reference the module.
|
|||
|
|
|||
|
-> **Note:** Within nested `provisioner` or `connection` blocks, the special
|
|||
|
`self` object refers to the current _resource instance,_ not the resource block
|
|||
|
as a whole.
|
|||
|
|
|||
|
## When to Use `for_each` Instead of `count`
|
|||
|
|
|||
|
If your 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:
|
|||
|
|
|||
|
```hcl
|
|||
|
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}"
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
This was fragile, because the resource instances were still identified by their
|
|||
|
_index_ instead of the string values in the list. If an element was removed from
|
|||
|
the middle of the list, every instance _after_ that element would see its
|
|||
|
`subnet_id` value change, resulting in more remote object changes than intended.
|
|||
|
Using `for_each` gives the same flexibility without the extra churn.
|