使用输入变量可以在创建基础设施资源时动态传入值,如果把Terraform代码看作是一个函数,那么输入变量都是函数参数。
Terraform输入变量使用variable
块进行定义,如下示例:
variable "image_id" {
type = string # 变量类型为字符串
}
variable "availability_zone_names" {
type = list(string) # 变量类型为列表,列表元素为字符串类型
default = ["us-west-1a"] # 变量默认值
}
variable "docker_ports" {
type = list(object({ # 变量类型为列表,列表元素为对象类型
interval = number,
external = number,
protocal = string
}))
// 设置变量默认值
default = [
{
interval = 8300
external = 8300
protocal = "tcp"
}
]
}
如上示例都是合法的变量定义,紧跟在variable
关键字之后的就是变量名。
在同一个Terraform模块(不包含子文件夹)中的变量名必须是唯一的,在代码中可以使用var.变量名
的方式来引用变量的值。
如下关键字不能作为输入变量名:source
,version
,providers
,count
,for_each
,lifecycle
,depends_on
,locals
。
输入变量名只能在声明该变量的目录下的代码中使用,在输入变量的定义中可以指定一些属性。
输入变量类型
在输入变量块中使用type
指定类型,如:
variable "name" {
type = string # 变量类型为字符串
}
variable "ports" {
type = list(number) # 变量类型为列表,列表元素为数字
}
定义了类型的输入变量只能被赋值为符合类型约束的值。
输入变量默认值
当Terraform无法获取一个输入变量的值时会使用其定义的默认值,如:
variable "name" {
type = string # 变量类型为字符串
default = "zhangsan" # 变量默认值
}
输入变量描述
可以在输入变量定义中设置描述信息,简单地向调用者描述该变量的意义和用法:
variable "imag_id" {
type = string # 变量类型为字符串
description = "This id of the machine image (AMI) to use the server."
}
如果在执行terraform plan
或terraform apply
时Terraform不知道某个输入变量的值,Terraform会在命令行界面上提示为输入变量设置一个值,这时候给用户展示的提示信息就是定义的输入变量描述。
注:输入变量描述并不是注释信息!
输入变量的断言
输入变量的断言是在Terraform 0.13.0开始引入的,在输入变量定义块中通过validation
块定义。
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-\"."
}
}
在validation
块中condition
参数是一个bool类型的参数,可以用一个表达式来定义如何界定输入变量是合法的。当condition
为true时输入变量合法,反之不合法。condition
表达式中只能通过var.输入变量名
的方式引用当前定义的变量,并且它的计算不能产生错误。
可以使用can
函数来判定表达式的执行是否会出错,如下示例:
variable "image_id" {
type = string
description = The id of the machine image (AMI) to use for the server.
validation {
condition = can(regex("^ami-", var.image_id)) # 使用can函数来判断表达式是否会执行出错
error_message = "The image_id value must be a valid AMI id, starting with \"ami-\"."
}
}
condition
表达式如果为false,Terraform会返回error_message
中定义的错误消息(error_message
中应该完整描述输入变量校验失败的原因,以及输入变量的合法约束条件)。
在命令行输出中隐藏值
该功能于Terraform v0.14.0 开始引入。
将输入变量设置为sensitive
可以防止在执行terraform plan
和terraform apply
时将输入变量的值展示出来。
声明一个包含敏感数据值的输入变量需要将其sensitive
属性设置为true,如下:
variable "user_information" {
type = object({
name = string
address = string
})
sensitive = true
}
resource "some_resource" "a" {
name = var.user_informaion.name
address = var.user_information.address
}
如果一个输入变量被声明为是敏感的,则任何使用敏感变量的表达式都将被视为敏感的。因此在上述例子中的资源”a”的两个参数name
和address
值也将在执行terraform plan
和terraform apply
时被隐藏。
可能暴露敏感数据值的地方
sensitive
输入变量是一个以配置文件为中心的概念,值会被毫无混淆地发送给Provider。但是如果该输入变量的值包含在了错误消息中,则Provider可能会暴露该输入变量值。
例如:即使’foo’是敏感值,Provider也可能返回以下错误:Invalid value 'foo' for field
。
如果将资源属性用作,或是作为Provider定义的资源ID的一部分,则在执行terraform apply
时将会公开该值。
+ resource "random_pet" "animal" {
+ id = (known after apply)
+ length = 2
+ prefix = (sensitive)
+ 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]
在上述示例中,资源属性prefix
已经设置为sensitive
敏感类型,但随后该值(“jae”)作为资源ID的一部分被公开展示了。
禁止输入变量为空
该功能自 v1.1.0开始被引入。
输入变量的nullable
参数控制调用者是否可以将null
值赋值给该变量。
variable "example" {
type = string
nullable = false
}
nullable
的默认值为true
,此时将null
值赋值给输入变量将会覆盖其默认值;如果nullable
为false
且输入变量有默认值,当把null
赋值给输入变量时,Terraform将使用输入变量的默认值。nullable
参数仅仅控制输入变量的直接值可能为null
值的情况,对于集合或对象类型的输入变量,仍然可以在集合元素或属性中使用null
值,只要集合或对象本身不为null
值即可。
给输入变量赋值
对输入变量赋值有多种方式,如:命令行参数,参数文件,环境变量,交互界面传值。
命令行参数
在Terraform命令行中使用-var="输入变量名=值"
的方式给输入变量赋值。
$ terraform apply -var="image_id=ami-abc123"
$ tarraform apply -var='image_id_list=["ami-abc123","ami-def456"]'
$ terraform apply -var='image_id_map={"us-east-1":"ami-abc123","us-east-2":"ami-def456"}'
可以在一条命令中使用多个-var
参数。
参数文件
参数文件的后缀名可以是.tfvars
或.tfvars.json
,.tfvars
文件使用HCL语法,.tfvars.json
文件使用JSON语法。
以.tfvars
文件为例,用HCL代码给输入变量赋值:
image_id = "ami-abc123"
available_zone_names = ["us-east-1a", "us-west-1c"]
后缀名为.tfvars.json
文件用一个JSON对象来对输入变量赋值:
{
"image_id": "ami-abc123",
"available_zone_names": ["us-east-1a", "us-west-1c"]
}
然后在Terraform命令中使用-var-file
参数指定参数文件:
$ terraform apply -var-file="testing.tfvars"
$ terraform apply -var-file="testing.tfvars.json"
有2种情况可以不用明确指定参数文件(Terraform会自动使用这2种情况下的参数文件):
- 当前模块内存在名为
terrform.tfvars
或terraform.tfvars.json
的文件 - 当前模块内存在一个或多个后缀名为
.auto.tfvars
或.auto.tfvars.json
的文件
环境变量
可以设置名为TF_VAR_输入变量名
的环境变量名为输入变量赋值:
$ export TF_VAR_image_id=ami-abc123
$ terraform apply
环境变量传值特别适合在自动化流水线中使用,尤其适合用来传递敏感数据的场景。
交互界面传值
当从命令行界面执行Terraform操作,Terraform无法从其他途径获取输入变量的值时,而该输入变量又未定义默认值,Terraform会进行最后的尝试,在命令行界面上以交互提示的方式让用户输入值。
输入变量值的优先级
由于存在多种输入变量的赋值方式,Terraform在加载变量值时存在有一个优先级顺序:
- 环境变量
- terraform.tfvars文件(如果存在的话)
- terraform.tfvars.json(如果存在的话)
- 所有的
.auto.tfvars
或.auto.tfvars.json
文件,以字母顺序升序处理 - 通过
-var
或-var-file
参数传递的变量值,按照在命令行中定义的顺序加载
如果使用上述方式均未能成功给输入变量赋值,Terraform将尝试使用默认值;对于没有定义默认值的输入变量,Terraform会尝试从命令行交互界面中获取一个用户输入的值。如果在执行Terraform命令时使用参数-input=false
禁用了界面传值方式,那么将会报错。
给复杂类型的输入变量赋值
通过参数文件给定义的输入变量传值时,可以直接使用HCL语法或JSON语法对复杂类型的输入变量传值(例如:list或map)。
对于某些场景下必须使用-var
命令行参数,或者环境变量传值时,可以使用单引号引用HCL语法的字面量来定义复杂类型,如:
# 采用这种方式需要手动处理引号的转义,比较容易出错
$ export TF_VAR_available_zone_names='["us-west-1d", "us-west-1b"]'
复杂类型的传值建议使用参数文件。