跳至主要内容

count 元参数

默认情况下,一个 资源块 配置一个真实的基础设施对象。(类似地,一个 模块块 将子模块的内容包含到配置中一次。)但是,有时您希望管理几个类似的对象(例如计算实例的固定池),而无需为每个对象编写一个单独的块。OpenTofu 有两种方法可以做到这一点:countfor_each

如果资源或模块块包含一个值为整数的 count 参数,OpenTofu 将创建多个实例。

基本语法

count 是由 OpenTofu 语言定义的元参数。它可以与模块和每种资源类型一起使用。

count 元参数接受一个整数,并创建该数量的资源或模块实例。每个实例都有一个与之关联的不同基础设施对象,并且在应用配置时,每个实例都会被分别创建、更新或销毁。

代码块
resource "aws_instance" "server" {
count = 4 # create four similar EC2 instances

ami = "ami-a1b2c3d4"
instance_type = "t2.micro"

tags = {
Name = "Server ${count.index}"
}
}

count 对象

在设置了 count 的块中,可以在表达式中使用额外的 count 对象,以便您可以修改每个实例的配置。此对象具有一个属性

  • count.index - 与此实例对应的不同的索引号(从 0 开始)。

count 中使用表达式

count 元参数接受数字 表达式。但是,与大多数参数不同,count 值必须在 OpenTofu 执行任何远程资源操作之前就知道。这意味着 count 不能引用在应用配置后才知道的任何资源属性(例如,在创建对象时由远程 API 生成的唯一 ID)。

引用实例

当设置 count 时,OpenTofu 区分块本身及其关联的多个资源或模块实例。实例由一个索引号标识,从 0 开始。

  • <TYPE>.<NAME>module.<NAME>(例如,aws_instance.server)引用资源块。
  • <TYPE>.<NAME>[<INDEX>]module.<NAME>[<INDEX>](例如,aws_instance.server[0]aws_instance.server[1] 等)引用单个实例。

这与没有 countfor_each 的资源和模块不同,后者无需索引或键即可引用。

类似地,来自具有多个实例的子模块的资源在计划输出和其他 UI 中显示时,前面会加上 module.<NAME>[<KEY>]。对于没有 countfor_each 的模块,地址将不包含模块索引,因为模块的名称足以引用该模块。

何时使用 for_each 而不是 count

如果您的实例几乎完全相同,则 count 是合适的。如果其中一些参数需要不同的值,而这些值不能直接从整数派生,则使用 for_each 更安全。

for_each 可用之前,通常从列表的长度派生 count 并使用 count.index 来查找原始列表值

代码块
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}"
}
}

这很脆弱,因为资源实例仍然由其索引而不是列表中的字符串值标识。如果从列表中间删除了一个元素,则该元素之后的每个实例都将看到其 subnet_id 值发生变化,从而导致比预期更多的远程对象更改。使用 for_each 可以提供相同的功能,而无需额外的更改。