Variable 介绍

更新时间:

概述

前文中的示例一直在硬编码资源参数值,但如果你想参数化配置或者标准化代码,并在 Terraform 工作流的 apply 阶段自定义资源属性怎么办?这正是本文要讲的变量的用武之地。

变量可以让你参数化在资源之间共享的值,除此之外,使用变量还具有以下好处:

  1. 增加通用性

    输入变量作为参数提供给 Terraform 使用,将源代码和属性赋值分离,可以实现对同一份 Terraform 配置的轻松定制和共享,而无需更改源代码。

  2. 提高灵活性

    定义变量后,在运行时(apply)有多种方法可以为属性自定义设置其值,包括环境变量、CLI 选项和键值对文件。在如下的示例中,名称、描述和网段都是硬编码的。你可以将这些属性中的任何一个声明为变量,并在运行时指定具体的值。

resource "alicloud_vpc" "my_vpc" {
  vpc_name    = "main-vpc"
  cidr_block  = "10.0.0.0/16"
  description = "my first vpc netrowk"
}

变量的语法

接下来让我们探讨如何声明输入变量。

image (23).png

变量必须在 variable 块中声明。建议将所有的变量声明保存在一个名为 variables.tf 的文件中。

关键字 variable 旁边的标签为变量名称。变量名称有两个设置规则:

  1. 变量名在模块内必须唯一

    在当前模块中声明的变量,名称必须保持唯一性,当然子模块中声明的变量和主模块中声明的变量不会冲突。

  2. 变量名不能是关键字

    变量名不能是 Terraform 预留的关键字,比如所有的元参数 count,for_each 等

变量没有必选的参数,因此变量块可以为空,Terraform 可以根据变量值自动推断类型和默认值。

type

type 参数指定了变量接受的值的类型。Terraform 支持以下基本变量类型:

  • bool,用于二进制值,如 true 或 false(不带引号)

  • number,用于数值变量

  • string,用于字符序列

default

default 是变量的另一个元参数,用于给属性分配默认值。

要访问模块内声明的变量值,可以使用表达式 var.。在如下的示例中,变量 vpc_cidr_block 在资源块中格式化为 var.vpc_cidr_block,并被分配给 cidr_block 参数,创建资源时使用引号中的默认值。

resource "alicloud_vpc" "my_vpc" {
  vpc_name    = "main-vpc"
  cidr_block  = var.vpc_cidr_block
  description = ""
}

variable "vpc_cidr_block" {
  default = "10.0.0.0/16"
}

变量块中的变量名必须与资源块中的引用相匹配。默认值可以通过分配值在环境变量或 .tfvars 文件或 -var 选项中被覆盖,如:

# 通过 CLI -var 选项覆盖变量默认值
$ terraform plan -var vpc_cidr_block="172.16.0.0/16"

description

description 用于记录变量的用途。当变量没有定义默认值时,描述将在 plan 或者 apply 阶段显示:

截屏2024-07-13 21.05.24.png

description 字符串通常包含在文档中,应当解释变量的用途和预期值。因此应从用户使用视角而非维护者的角度去编写。维护者可以使用注释,而非直接写到 description 中。

sensitive

sensitive 是一个变量参数,顾名思义,用于保护敏感信息不会显示在命令输出或日志文件中。敏感值的可接受值为true。当设置为true时,变量的值在 terraform plan 或terraform apply 的输出中标记为敏感。

当处理如数据库凭证或 AccessKey 或者登录密码等敏感信息时,此参数非常有用,将变量标记为敏感将消除意外暴露机密信息的风险。

在此示例中,变量 vpc_cidr_block 被标记为敏感。资源 my-vpc 使用了变量 vpc_cidr_block,运行 terraform plan 或 apply 时,值没有被显示:

$ terraform plan
Terraform will perform the following actions:

  # alicloud_vpc.my-vpc will be created
  + resource "alicloud_vpc" "my-vpc" {
      + cidr_block            = (sensitive value)
      + create_time           = (known after apply)
      + id                    = (known after apply)
      + status                = (known after apply)
      + user_cidrs            = (known after apply)
      + vpc_name              = "main-vpc"
      ...
    }

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

validation

验证块包含一个条件参数,用于指定验证规则。你可以通过在变量块中包含验证子块来验证赋给变量的值。

在如下示例中,length 和 substr 用作条件参数,验证 vpc_name 的值是否长度超过 4 并且是否以 tf- 为开头:

variable "vpc_name" {
  validation {
    condition     = length(var.vpc_name) > 4 && substr(var.vpc_name, 0, 3) == "tf-"
    error_message = "The vpc name must start with 'tf-' and be longer than 4 characters."
  }
}

当执行 terraform plan 并且输入 vpc_name 值为 my-vpc 时,将会触发规则校验抛出具体的错误信息:

截屏2024-07-14 11.14.42.png

变量的设置方式

在运行时有多种设置变量值的方法:

# .tfvars 文件(推荐)
$ terraform apply -var-file my-vars.tfvars

# CLI 选项
$ terraform apply -var vpc_cidr_block=“172.16.0.0/16”

# 环境变量
$ export TF_VAR_vpc_dicr_block=“172.16.0.0/16”
$ terraform apply

# 默认的变量文件 terraform.tfvars
$ terraform apply

首先,你可以使用 .tfvars 文件快速切换和版本变量集;你也可以使用 CLI 选项,在运行简单配置文件的快速验证时非常有用;环境变量在脚本和流水线中非常有用。如果通过 description 的方法没有设置所需变量,可以使用 CLI 提示。

image (24).png

当需要输入许多变量定义,尤其是涉及到复杂类型的变量时,在 CLI 选项中设置变量值将会比较困难。相反,可以在扩展名为 .tfvars 或 .tfvars.json 的文件中以 K-V 的方式指定变量值,然后在运行 terraform plan 或者 apply 命令是通过 -var-file 选项指定参数集:

$ terraform plan -var-file my-vars.tfvars

扩展名为 .tfvars 或 .tfvars.json 的文件中的变量定义遵循与 HCL 相同的语法,但仅包含对变量名的赋值。值得注意的是,只要变量文件准确地命名为terraform.tfvars、terraform.tfvars.json、.auto.tfvars或.auto.tfvars.json,Terraform 在执行 plan 或者 apply 命令时会自动加载这些文件,无需使用 -var-file 选项。.tfvars 文件中的定义会覆盖变量的默认值和环境变量中的定义。如果要在命令行上替换 .tfvars 文件中设置的变量的值,可以使用 -var 选项,具体格式为 -var="<变量名>=<变量值>",比如想要在执行 terraform plan 的时候,将 vpc_name 指定为 "my-first-vpc",可以使用如下的方式:

$ terraform plan -var="vpc_name=my-fisrt-vpc"

此时 terraform plan 的输出结果中,vpc_name 的值将显示为 my-fisrt-vpc,而非 .tfvars 中定义的 my-vpc。此方法常用于自动化流程,其中 -var 从另一个环境变量获取,并替换掉变量文件中事先定义好的值。

-var 选项的优先级最高,超过所有其他变量赋值方法。如果同时存在多种为变量赋值的方法,使用 -var 选项定义的值最终将赋给变量。

如果某个变量没有使用以上所描述的方法设置变量值,那么 Terraform 会在运行 plan 或者 apply 的时候提示你。例如,在本例中,变量 vpc_name 未被赋值,如果在执行 terraform 命令的时候也没有使用 -var 或者 -var-file 选项,则 CLI 将会提示你要输入值:

截屏2024-07-14 10.57.18.png

变量的最佳实践

当声明变量的时候,我们提供以下几条建议:

  1. 只参数化每个实例或环境中会变化的值

    在决定是否暴露一个变量时,请确保你有具体的变更用例。如果一个变量只有很小的几率需要使用,请不要暴露它。对带有默认值的变量进行更改或新增是向后兼容的,但是移除某个变量则属于非兼容性变更,需要额外注意。

  2. 尽可能使用 .tfvars 变量文件

    对于根模块,推荐使用 .tfvars 变量文件来为变量设置具体的值。尽可能避免在变量文件和命令行选项之间交替使用,命令行选项是临时的,容易被遗忘,并且无法被提交到源代码中进行版本控制,而默认的变量文件更具有可预测性。

  3. 给变量起与其使用目的相关的名称

    表示数值的变量,例如磁盘大小或者内存大小或者付费时长,尽可能在变量命名中使用单位。阿里云的 OpenAPI 没有标准单位,因此遵循这种命名约定可以为 Terraform 配置文件的维护者明确预期的输入单位。表示逻辑的变量,为了简化条件逻辑,应给布尔变量取带有肯定含义的名字,例如 enable_ipv6。

  4. 变量必须要有描述

    描述会自动包含在文档中,并为新的开发人员添加额外的上下文,增强 Terraform 配置文件的可读性和可维护性。