使用输入变量可以在创建基础设施资源时动态传入值,如果把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 = 8300external = 8300protocal = "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 = stringdescription = 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 = stringaddress = string})sensitive = true
}resource "some_resource" "a" {name = var.user_informaion.nameaddress = 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 = stringnullable = 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"]'
复杂类型的传值建议使用参数文件。