- OpenTofu 语言
- 变量和输出
- 输入变量
输入变量
输入变量允许您自定义模块的各个方面,而无需更改模块自身的源代码。此功能使您可以跨不同的 OpenTofu 配置共享模块,从而使您的模块可组合和可重用。
在配置的根模块中声明变量时,可以使用 CLI 选项和环境变量设置它们的值。在 子模块 中声明变量时,调用模块应在 module
块中传递值。
如果您熟悉传统的编程语言,将模块与函数定义进行比较可能会有用。
为简洁起见,输入变量通常在上下文清楚地表明变量类型时,简称为“变量”或“OpenTofu 变量”。OpenTofu 中的其他变量类型包括*环境变量*(由 OpenTofu 运行的 shell 设置)和*表达式变量*(用于在 表达式 中间接表示值)。
声明输入变量
模块接受的每个输入变量都必须使用 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
关键字后的标签是变量的名称,在同一模块中的所有变量中必须是唯一的。此名称用于从外部为变量分配值,以及从模块内部引用变量的值。
变量的名称可以是任何有效的 标识符,*除了*以下内容:source
、version
、providers
、count
、for_each
、lifecycle
、depends_on
、locals
。
这些名称是 模块配置块 中元参数的保留名称,不能声明为变量名称。
参数
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
可用于指示接受任何类型。有关这些不同类型的含义和行为以及有关自动转换复杂类型的详细信息,请参阅 类型约束。
如果同时指定了 type
和 default
参数,则给定的默认值必须可转换为指定的类型。
输入变量文档
由于模块的输入变量是其用户界面的一部分,因此您可以使用可选的 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 在使用该变量配置中的其他位置时,在plan
或apply
输出中显示其值。
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
。当nullable
为true
时,null
是变量的有效值,模块配置必须始终考虑变量值为null
的可能性。传递null
值作为模块输入参数将覆盖任何default
值。
将nullable
设置为false
可确保变量值在模块中永远不会为null
。如果nullable
为false
并且变量具有default
值,则当模块输入参数为null
时,OpenTofu 会使用默认值。
nullable
参数仅控制变量的直接值在哪里可以为null
。对于集合或结构类型(例如列表或对象)的变量,调用者仍可以在嵌套元素或属性中使用null
,只要集合或结构本身不为空。
使用输入变量值
在声明变量的模块内,可以通过表达式中的var.<NAME>
访问其值,其中<NAME>
与声明块中给出的标签匹配。
输入变量由variable
块创建,但您引用它们作为名为var
的对象的属性。
resource "aws_instance" "example" {
instance_type = "t2.micro"
ami = var.image_id
}
分配给变量的值只能在声明该变量的模块内的表达式中访问。
将值分配给根模块变量
当变量在配置的根模块中声明时,可以使用多种方法设置它们。
- 单独使用
-var
命令行选项。 - 在变量定义(
.tfvars
)文件中,这些文件是在命令行上指定还是自动加载的。 - 作为环境变量。
以下部分将更详细地描述这些选项。本节不适用于子模块,子模块中输入变量的值是在其父模块的配置中分配的,如模块中所述。
命令行上的变量
要在命令行上指定单个变量,请在运行tofu plan
和tofu 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.tfvars
或terraform.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
选项,按其提供的顺序。
具有映射和对象值的变量的行为与其他变量相同:找到的最后一个值将覆盖前面的值。这与 OpenTofu 的先前版本有所不同,先前版本会合并映射值而不是覆盖它们。