跳至主要内容

输入变量

输入变量允许您自定义模块的各个方面,而无需更改模块自身的源代码。此功能使您可以跨不同的 OpenTofu 配置共享模块,从而使您的模块可组合和可重用。

在配置的根模块中声明变量时,可以使用 CLI 选项和环境变量设置它们的值。在 子模块 中声明变量时,调用模块应在 module 块中传递值。

如果您熟悉传统的编程语言,将模块与函数定义进行比较可能会有用。

  • 输入变量就像函数参数。
  • 输出值 就像函数返回值。
  • 本地值 就像函数的临时本地变量。

声明输入变量

模块接受的每个输入变量都必须使用 variable 块声明。

代码块
variable "image_id" {
type = string
}

variable "availability_zone_names" {
type = list(string)
default = ["us-west-1a"]
}

variable "docker_ports" {
type = list(object({
internal = number
external = number
protocol = string
}))
default = [
{
internal = 8300
external = 8300
protocol = "tcp"
}
]
}

variable 关键字后的标签是变量的名称,在同一模块中的所有变量中必须是唯一的。此名称用于从外部为变量分配值,以及从模块内部引用变量的值。

变量的名称可以是任何有效的 标识符,*除了*以下内容:sourceversionproviderscountfor_eachlifecycledepends_onlocals

这些名称是 模块配置块 中元参数的保留名称,不能声明为变量名称。

参数

OpenTofu CLI 为变量声明定义了以下可选参数。

  • default - 一个默认值,然后使变量变为可选。
  • type - 此参数指定变量接受哪些值类型。
  • description - 这指定了输入变量的文档。
  • validation - 用于定义验证规则的块,通常除了类型约束之外。
  • sensitive - 当在配置中使用变量时,限制 OpenTofu UI 输出。
  • nullable - 指定变量在模块中是否可以为 null

默认值

变量声明还可以包含 default 参数。如果存在,则变量被认为是*可选*的,如果在调用模块或运行 OpenTofu 时未设置任何值,则将使用默认值。default 参数需要一个字面值,不能引用配置中的其他对象。

类型约束

variable 块中的 type 参数允许您限制将被接受为变量值的 值类型。如果没有设置类型约束,则接受任何类型的值。

虽然类型约束是可选的,但我们建议您指定它们;它们可以作为模块用户的有用提醒,并且允许 OpenTofu 在使用错误类型时返回有用的错误消息。

类型约束是使用类型关键字和类型构造函数组合创建的。支持的类型关键字是

  • string
  • number
  • bool

类型构造函数允许您指定复杂类型,例如集合。

  • list(<TYPE>)
  • set(<TYPE>)
  • map(<TYPE>)
  • object({<ATTR NAME> = <TYPE>, ... })
  • tuple([<TYPE>, ...])

关键字 any 可用于指示接受任何类型。有关这些不同类型的含义和行为以及有关自动转换复杂类型的详细信息,请参阅 类型约束

如果同时指定了 typedefault 参数,则给定的默认值必须可转换为指定的类型。

输入变量文档

由于模块的输入变量是其用户界面的一部分,因此您可以使用可选的 description 参数简要描述每个变量的用途。

代码块
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
}

描述应简洁地解释变量的用途以及预期值的类型。此描述字符串可能包含在有关模块的文档中,因此应从模块用户的角度而不是维护者的角度编写。对于模块维护者的注释,请使用注释。

自定义验证规则

您可以通过在相应的variable块中添加validation块来为特定变量指定自定义验证规则。下面的示例检查 AMI ID 是否具有正确的语法。

代码块
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."

validation {
condition = length(var.image_id) > 4 && substr(var.image_id, 0, 4) == "ami-"
error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
}
}

有关更多详细信息,请参阅自定义条件检查

在 CLI 输出中抑制值

将变量设置为sensitive可防止 OpenTofu 在使用该变量配置中的其他位置时,在planapply输出中显示其值。

OpenTofu 仍将在状态中记录敏感值,因此任何可以访问状态数据的人员都可以访问明文中的敏感值。有关更多信息,请参阅状态中的敏感数据

通过将sensitive参数设置为true来声明变量为敏感变量。

代码块
variable "user_information" {
type = object({
name = string
address = string
})
sensitive = true
}

resource "some_resource" "a" {
name = var.user_information.name
address = var.user_information.address
}

任何结果取决于敏感变量的表达式本身也将被视为敏感的,因此在上面的示例中,resource "some_resource" "a"的两个参数也将隐藏在计划输出中。

代码块
OpenTofu will perform the following actions:

# some_resource.a will be created
+ resource "some_resource" "a" {
+ name = (sensitive value)
+ address = (sensitive value)
}

Plan: 1 to add, 0 to change, 0 to destroy.

在某些情况下,当您在嵌套块中使用敏感变量时,OpenTofu 可能会将整个块视为删除。这种情况发生在资源类型的所有特定类型块都必须是唯一的,因此公开一个块的内容可能会暗示兄弟块的内容。

代码块
  # some_resource.a will be updated in-place
~ resource "some_resource" "a" {
~ nested_block {
# At least one attribute in this block is (or was) sensitive,
# so its contents will not be displayed.
}
}

提供程序还可以声明属性为敏感属性,这会导致 OpenTofu 隐藏它,而不管您如何为其赋值。有关更多信息,请参阅敏感资源属性

如果您使用敏感值作为输出值的一部分,那么 OpenTofu 将要求您也将输出值本身标记为敏感,以确认您有意导出它。

OpenTofu 可能披露敏感变量的情况

sensitive变量是面向配置的概念,值被发送到提供程序时不会进行任何混淆。如果该值包含在错误消息中,提供程序错误可能会公开该值。例如,即使“foo”是一个敏感值,提供程序也可能会返回以下错误:"Invalid value 'foo' for field"

如果资源属性用作或作为提供程序定义的资源 ID 的一部分,则apply将公开该值。在下面的示例中,prefix属性已设置为敏感变量,但该值(“jae”)随后作为资源 ID 的一部分被公开。

代码块
  # random_pet.animal will be created
+ resource "random_pet" "animal" {
+ id = (known after apply)
+ length = 2
+ prefix = (sensitive value)
+ separator = "-"
}

Plan: 1 to add, 0 to change, 0 to destroy.

...

random_pet.animal: Creating...
random_pet.animal: Creation complete after 0s [id=jae-known-mongoose]

禁止空输入值

变量块中的nullable参数控制模块调用者是否可以为变量分配null值。

代码块
variable "example" {
type = string
nullable = false
}

nullable的默认值为true。当nullabletrue时,null是变量的有效值,模块配置必须始终考虑变量值为null的可能性。传递null值作为模块输入参数将覆盖任何default值。

nullable设置为false可确保变量值在模块中永远不会为null。如果nullablefalse并且变量具有default值,则当模块输入参数为null时,OpenTofu 会使用默认值。

nullable参数仅控制变量的直接值在哪里可以为null。对于集合或结构类型(例如列表或对象)的变量,调用者仍可以在嵌套元素或属性中使用null,只要集合或结构本身不为空。

使用输入变量值

在声明变量的模块内,可以通过表达式中的var.<NAME>访问其值,其中<NAME>与声明块中给出的标签匹配。

代码块
resource "aws_instance" "example" {
instance_type = "t2.micro"
ami = var.image_id
}

分配给变量的值只能在声明该变量的模块内的表达式中访问。

将值分配给根模块变量

当变量在配置的根模块中声明时,可以使用多种方法设置它们。

  • 单独使用-var命令行选项。
  • 在变量定义(.tfvars)文件中,这些文件是在命令行上指定还是自动加载的。
  • 作为环境变量。

以下部分将更详细地描述这些选项。本节不适用于模块,子模块中输入变量的值是在其父模块的配置中分配的,如模块中所述。

命令行上的变量

要在命令行上指定单个变量,请在运行tofu plantofu apply命令时使用-var选项。

代码块
tofu apply -var="image_id=ami-abc123"
tofu apply -var='image_id_list=["ami-abc123","ami-def456"]' -var="instance_type=t2.micro"
tofu apply -var='image_id_map={"us-east-1":"ami-abc123","us-east-2":"ami-def456"}'

以上示例显示了适用于 Unix 风格的 shell(例如 Linux 或 macOS 上的 shell)的语法。有关 shell 引用的更多信息,包括 Windows 命令提示符的其他示例,请参阅命令行上的输入变量

您可以在单个命令中多次使用-var选项来设置多个不同的变量。

变量定义(.tfvars)文件

要设置大量变量,更方便的做法是将它们的定义放在一个变量定义文件中(文件名以.tfvars.tfvars.json结尾),然后在命令行上使用-var-file指定该文件。

代码块
tofu apply -var-file="testing.tfvars"

变量定义文件使用与 OpenTofu 语言文件相同的基本语法,但只包含变量名赋值。

代码块
image_id = "ami-abc123"
availability_zone_names = [
"us-east-1a",
"us-west-1c",
]

OpenTofu 还自动加载一些变量定义文件(如果存在)。

  • 名为terraform.tfvarsterraform.tfvars.json的文件。
  • 任何以.auto.tfvars.auto.tfvars.json结尾的文件。

文件名以.json结尾的文件将被解析为 JSON 对象,根对象属性对应于变量名。

代码块
{
"image_id": "ami-abc123",
"availability_zone_names": ["us-west-1a", "us-west-1c"]
}

环境变量

作为定义变量的其他方法的备用方案,OpenTofu 会在其自身进程的环境中搜索名为TF_VAR_的環境变量,后跟已声明变量的名称。

这在自动化运行 OpenTofu 或在连续运行一系列 OpenTofu 命令时使用相同的变量时很有用。例如,在 Unix 系统上的bash提示符下。

代码块
$ export TF_VAR_image_id=ami-abc123
$ tofu plan
...

在环境变量名称区分大小写的操作系统上,OpenTofu 会精确匹配配置中给出的变量名,因此所需的環境变量名通常会像上面的示例一样包含大小写字母的混合。

复杂类型的值

当变量值在变量定义文件中提供时,您可以使用 OpenTofu 通常的语法来文字表达式来分配复杂类型的值,例如列表和映射。

-var命令行选项和环境变量有一些特殊规则适用。为了方便起见,OpenTofu 默认将-var和环境变量值解释为文字字符串,这些字符串只需要 shell 引号,而无需 OpenTofu 的特殊引号。例如,在 Unix 风格的 shell 中。

代码块
$ export TF_VAR_image_id='ami-abc123'

但是,如果根模块变量使用类型约束来要求复杂值(列表、集合、映射、对象或元组),OpenTofu 将尝试使用与变量定义文件中使用的语法相同的语法来解析其值,这需要仔细注意 shell 中的字符串转义规则。

代码块
$ export TF_VAR_availability_zone_names='["us-west-1b","us-west-1d"]'

为了可读性,并避免需要担心 shell 转义,我们建议始终通过变量定义文件设置复杂变量值。有关-var参数的引用和转义的更多信息,请参阅命令行上的输入变量

未声明变量的值

如果您已定义变量值,但未定义其相应的variable {}定义,则您可能会收到错误或警告,具体取决于您提供该值的方式。

如果您为未声明的变量提供值,这些变量被定义为环境变量,您将不会收到错误或警告。这是因为环境变量可能会被声明,但不会在所有可能运行的配置中使用。

如果您为未声明的变量提供值(这些变量是在文件中定义的),您将收到警告。这有助于在您提供一个变量值用于变量声明,但可能在值定义中存在错误的情况下。例如,以下配置

代码块
variable "moose" {
type = string
}

以及以下 .tfvars 文件

代码块
mosse = "Moose"

将导致 OpenTofu 警告您没有声明名为 "mosse" 的变量,这可以帮助您发现此错误。

如果您在多个配置中使用 .tfvars 文件,并希望继续看到此警告,可以使用-compact-warnings 选项来简化您的输出。

如果您在命令行上为未声明的变量提供值,OpenTofu 将返回错误。要避免此错误,请为该值声明一个变量块,或从您的 OpenTofu 调用中删除该变量值。

变量定义优先级

上述设置变量的机制可以组合使用。如果同一个变量被赋予多个值,OpenTofu 会使用它找到的最后一个值,覆盖任何先前的值。请注意,同一个变量不能在单个源中被赋予多个值。

OpenTofu 按以下顺序加载变量,后面的源优先于前面的源

  • 环境变量
  • 如果存在,则为 terraform.tfvars 文件。
  • 如果存在,则为 terraform.tfvars.json 文件。
  • 任何 *.auto.tfvars*.auto.tfvars.json 文件,按照其文件名词法顺序处理。
  • 命令行上的任何 -var-var-file 选项,按其提供的顺序。