Terraform 的变量使用及赋值规则

本人在 AWS 上建立基础架构的时候倾向于用 Terraform, 而不是 AWS 自家的 CloudFormation。倒不是因为 Terraform 支持多种类型的 Provider,而是它能模块化,不同项目共享 AWS 资源时也更方便。而使用 CloudFormation 的话,一不小心就会写出一个超大的 YAML 文件来,要使用共同的 AWS 资源时,谁来创建是个不小的问题。CloudFormation 稍值得称道的地方也就是有一个可视化的  Stack,但把  Terraform 执行的 state 存到 S3 也不差。使用 Terraform 还有一个最享受的地方就是它的官方文档组织的非常清晰。

出品 Terraform 的公司 HashiCorp 秉持着 Infrastructure as Code,近日在忙着 IPO, 估值在 $13B, Ticker 将为 HCP(该链接直接可用时便以上市),介时也值得关注一下。扯远了,回到日常使用 Terraform 的变量上来。

本文直接参考自 Terraform 官网的 Input Variables。不管英文好不好都应该读原文去理解 Terraform 变量的详细使用方法。这里主要是了解各种输入变量的方式,以及验证一下当同时用多种方式输入重复的变量时,以谁为最终的结果。

Terraform 变量的声明

借用函数的概念,在 Terraform 中,variable 为函数参数,output 为返回值,locals 就是局部变量。变量用 variable 块来声明,它有五个参数,格式如下

validation 用于校验输入,应该挺有用的,本人还未用过,每次都相信自己的输入,用法见 Custom Validation Rules. description 没什么好说的,sensitive 标记的值不会输出到 output 中,但会记录到 state 文件中,且作为变量使用时也不能确保它的隐私性。

我们经常有初始值的变量只需要指定 default,像

那么变量 version_number 的类型会自动推断为 number。没有 default 值的变量需要指明 type, 并在我们执行 terraform 命令时可以各种方式提供变量值,不然还是会要求逐个输入

$ terraform plan
var.version_number
    Enter a value:

Terraform 当前支持的 type 有 string, number, bool, 复合类型 list(<TYPE>), set(<TYPE>), map(<TYPE>), object({ATTR NAME>=<TYPE>, ...}), tuple([<TYPE>, ...]).

Terraform  会依照类型声明对 default 值, *.tfvars, 或 *.json 文件中提供的值进行相应的转换, 看下面的例子

执行 terraform plan 后看到的是

 

但声明为 number 就不能用 terraform plan -var var1="234",这样认为 var1 是含双引号的整体 '"234"'。

上面也看到了 object 类型的使用,稍加说明一下 map 类型。map 的 key 总是 string 类型,map(<TYPE>)  中的 <TYPE> 是值的类型,可以是 map(string), map(object({...}), map(any),any 为任意类型。

Terraform 变量的类型是可以随意嵌套,如

相关的变量组织到一个 object 中是一个较好的习惯。

Terraform 变量的使用

var 前缀来引用,比如要使用前面定义的 var1 变量,用 var.var1 就是了。

Terraform 变量的输入

在 *.tf 文件中声明的无默认值的 variable 在执行 terraform 时需以任意一种或多种形式输入,一谈到各种输入方式立即就面对重复赋值时以谁为准的问题。下面同时列出 Terraform 搜寻变量的输入的方式及顺序,并后面变量赋值的覆盖前面的,即最后为赢

  1. 环境变量: TF_VAR_image_id='ami-abc123', 以 TF_VAR_ 为前缀的环境变量值将会应用到相应的变量上去
  2. terraform.tfvars 文件中的变量赋值, tf 的格式
  3. terraform.tfvars.json 文件中的变量赋值,JSON 语法格式
  4. *.auto.tfvars*.auto.tfvars.json 文件中的变量赋值,文件加载顺序以文件名按字符串升序
  5. -var-var-file 的命令行选项指定的变量或文件中的变量赋值,-var-var-file 可出现多次,顺序为参数出现的顺序。-var-file 可以支持 *.tfvars*.json 两种文件格式

用种通俗的理解,这种最后为赢的规则相当于是创建一个 Map,前面的 1-5 的顺序,以及每一步内部的顺序都是在往 Map 中 put 值,有重复 Key 的话后面的覆盖前面的,最终的 Map 交给 Terraform 去对相应的变量赋值。

*.tfvars 文件中的格式为

*.tfvars.json 中的格式则为

-var 的复杂变量输入

使用 -var 参数输入简单变量容易,-var a=123 -var b=hello, 如果 type 为 map 为 object, list 等类型时,-var 应该如何输入呢? 很简单,用 JSON 的格式应对就是了,比如上面的 var2

$ terraform plan -var 'var2={"name": "Kitty", "age": 2}'

如果是一个数组变量就用

$ terraform plan -var 'zone_ids=["zone-a", "zone-b", "zone-c"]' 

因为复杂类型都以 JSON 的形式输入,所以 Terraform 中的 list, set, tuple 变量都表现为 JSON 数组。而 Terraform 的 map 和 object 输入时也都是 JSON 对象。

变量输入时的错误与警告

当执行 terraform 命令未提供足够的变量时会逐个提示补全,当类型不匹配(无法正确转型)时会报错,或是当提供了未声明的变量也会有警告或错误。

类型不匹配时

比如声明的变量为

执行时给的是无法转换为数字的字符串

$ terraform plan -var var1=hello

terraform plan -var var1="100" 也不行,应为它相应于是 terraform plan -var 'var1="100"'

如果是用 *.tfvars 来提供该变量值,可以写成

或写在  *.json 中,用

重复赋值时使用了不同的类型

依照前面最后为赢的 Map 规则,也很好理解,以最后的类型为准。还以前面 number 类型的 var1 为例

$ terraform plan -var var1=hello -var var1=200

最后 Terraform 收到的是 var1=200, 所以执行无误

提供了未声明的变量

有下面几种情况

  1. 环境变量中有 TF_VAR_image_id, 但未声明 image_id 变量,不会任何抱怨。大约是不能限制用户创建任何的环境变量
  2. .tfvars.json 文件中提供了未声明的变量,会有警告
    如在 .tfvars 文件中有 image_id="ami-abc", 但在 tf 文件中未声明 image_id 变量,警告为
    Warning: Value for undeclared variable
    ...........
    此时用 -compact-warnings 只能使得警告信息短一些,没有消除
  3. -var 参数提供了未声明的变量,直接报错,无法继续执行
    Error: Value for undeclared variable 

 

Terraform 变量相关的内容差不多就这些了,variable 的 validation 真需要用到时再回过头来参考 Custom Validation Rules。这里面还说到一个变量还可从 Terraform 的一个自家服务 Terraform Cloud workspace 中来,目前来说会用到它的可能性不到,它更像是 Docker 的 swarm 一样,远远敌不过 Kubernetes。

最后,等到 Hashicorp 公司上市时值得关注一下,预计发行价会在 $68 和 $72 之间,到时看 HCP 的表现。


本文链接 https://yanbin.blog/terraform-variables-input-priority/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments