输入变量

原文


注意:此页面是关于 Packer 的 HCL2 模板的。 HCL2 模板最初作为 Beta 功能被 Packer 1.5 版引入。从 v1.7 开始,HCL2 支持不再处于测试阶段,并且是编写 Packer 配置的首选方式。对于稳定的旧风格配置语言,请参阅模板文档。从 v1.6.2 开始,您可以使用 hcl2_upgrade 命令将遗留的 JSON 模板转换为 HCL2 配置文件。

Packer HCL 模板中有两种变量:输入变量,简称为 variables,和局部变量,也称为 locals。输入变量可能有默认值,但可以从命令行或特殊变量文件读取覆盖这些默认值。局部变量可以被认为是常量,并且不能在运行时被覆盖。

这个页面是关于输入变量的。要了解局部变量,请参阅局部变量页面。

输入变量用作 Packer 构建的参数,让我们可以在不更改 build 代码的情况下定制构建的各个方面。

当您在配置构建中声明变量时,您可以使用命令行参数和环境变量设置它们的值。

变量指南中介绍了输入变量和局部变量的使用。

请注意:为简洁起见,当从上下文中可以清楚地了解所讨论的变量类型时,输入变量通常仅称为“变量”或“Packer 变量”。 Packer 中的其他类型的变量包括环境变量(由运行 Packer 的 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"
    }
  ]
}

或者不是那么精确的 variables 块:

variables {
   foo = "value"
   my_secret = "foo"
}

variable 关键字后的标签或变量块的标签是变量的名称,该名称在同一构建中的所有变量中必须是唯一的。此名称用于从外部为变量赋值,并在构建中引用变量的值。

参数

Packer 声明变量时可以对以下参数赋值:

default - 变量拥有一个默认值从而变成选填变量。 type - 变量接受的值的类型。 description - 输入变量的描述文档。 validation - 定义除了类型约束之外的验证规则的块。 sensitive - 宣告输入变量含有敏感信息,导致该变量的字符串值在 Packer 的输出中被混淆。

默认值

变量声明可以包含 default 参数。如果设置了该参数,则该变量被认为是选填的,如果在运行 Packer 时未设置值,则将使用默认值。默认参数需要一个常量字面值,不能引用配置中的其他对象。

类型约束

variable 块中的 type 参数允许您限制将被接收为变量值的类型。如果未设置类型约束,则接受任何类型的值。

虽然类型约束是可选的,但我们建议设置它;它们可以为构建用户提供的简单提醒,并允许 Packer 在使用错误类型时返回有用的错误消息。

类型约束是通过 type 关键字和类型的构造表达式创建的。支持的类型关键字是:

  • string
  • number
  • bool

可以用类型构造表达式指定复杂的集合类型:

  • list(<TYPE>)
  • set(<TYPE>)
  • map(<TYPE>)
  • object({<ATTR NAME> = <TYPE>, ... })
  • tuple([<TYPE>, ...])

关键字 any 可以用来表示任意类型。有关类型约束的详细信息,可以参阅Terraform 文档

如果同时指定了 typedefault 参数,则给定的 default 值必须可转换为指定的 type

如果仅指定 default ,将使用 default 的类型。

当未指定类型和默认值并且您尝试从环境变量命令行设置变量时,该变量将始终被解释为 string

输入变量的描述文档

因为构建的输入变量是其用户交互界面的一部分,我们可以使用可选的 description 参数简要描述每个变量的用途:

variable "image_id" {
  type        = string
  description = "The ID of the machine image (AMI) to use for the server."
}

description 应简明扼要地解释变量的用途以及期望的值类型。此描述字符串可能包含在有关构建的文档中,因此应该从构建用户而不是其维护者的角度来编写。面向编写构建代码的维护者的评论,请使用代码注释。

定制输入参数校验规则

此节内容已经在variable有所描述。

使用输入参数的值

在声明变量的构建中,可以从表达式中访问输入变量的值,如 var.<NAME>,其中 <NAME> 与声明块中定义的标签相匹配:

source "googlecompute" "debian"  {
    zone = var.gcp_zone
    tags = var.gcp_debian_tags
}

分配给变量的值只能被声明该变量的文件夹中的表达式访问。

为输入变量赋值

有以下几种为配置文件中声明的输入变量赋值的方法:

  • -var foo=bar 这样的命令行参数对一个输入变量赋值
  • 使用变量文件,要么用 -var-files values.pkrvars.hcl 这样的命令行参数,要么使用自动加载的变量文件(文件名以 *.auto.pkrvars.hcl 为后缀)
  • 使用环境变量,例如:PKR_VAR_foo=bar

下面的段落将详细描述这些赋值方式

命令行赋值

要在命令行上为指定的单个变量赋值,请在运行 packer build 命令时使用 -var 选项:

$ packer build -var="image_id=ami-abc123"
$ packer build -var='image_id_list=["ami-abc123","ami-def456"]'
$ packer build -var='image_id_map={"us-east-1":"ami-abc123","us-east-2":"ami-def456"}'

-var 选项可以在单个命令中多次使用。

如果您打算通过命令行对变量赋值,我们强烈建议至少设置一个默认类型而不是使用空块;这有助于 HCL 解析器了解正在设置的内容。否则,解释器将假定命令行上赋值的任何变量都是字符串。

标准变量文件赋值

要设置多个变量,更方便的方法是在文件名以 .pkrvars.hcl.pkrvars.json 结尾的变量定义文件中指定它们的值,然后在命令行上使用 -var-file 指定该文件:

$ packer build -var-file="testing.pkrvars.hcl"

变量定义文件使用与 Packer 语言文件相同的基本语法,但仅包含变量名及其赋予的值:

image_id = "ami-abc123"
availability_zone_names = [
  "us-east-1a",
  "us-west-1c",
]

重要提示:与遗留 JSON 模板不同,变量定义文件中的输入变量必须在标准 HCL2 模板文件 *.pkr.hcl 中有对应的 variable 块声明,然后才能为其赋值。如果不这样做,将导致 Packer 运行时出现 unknown variable 错误。

自动加载变量文件赋值

Packer 还可以自动加载一个或多个变量定义文件(如果存在):

名称以 .auto.pkrvars.hcl.auto.pkrvars.json 结尾的任何文件。

名称以 .json 结尾的文件被解析为 JSON 对象而不是 HCL,根对象属性对应于变量名:

{
  "image_id": "ami-abc123",
  "availability_zone_names": ["us-west-1a", "us-west-1c"]
}

重要提示:与遗留 JSON 模板不同,变量定义文件中的输入变量必须在标准 HCL2 模板文件 *.pkr.hcl 中有对应的 variable 块声明,然后才能为其赋值。如果不这样做,将导致 Packer 运行时出现 unknown variable 错误。

环境变量赋值

相对于其他为变量赋值方式的后备方案,Packer 在其自身进程的环境中搜索名为 PKR_VAR_ 的环境变量,后跟已声明变量的名称。

对于自动化运行 Packer 或使用相同变量连续运行一系列 Packer 命令时该功能非常有用。例如,在 Unix 系统的 bash 提示符下:

$ export PKR_VAR_image_id=ami-abc123
$ packer build gcp/debian/
...

在环境变量名称区分大小写的操作系统上,Packer 会完全按照配置中给定的变量名称进行匹配,因此所需的环境变量名称通常会像上例中的同时包含大小写字母。

复杂类型值

当在变量定义文件中提供变量值时,Packer 的常用语法可用于分配复杂类型的值,如列表和映射。

一些特殊规则适用于 -var 命令行选项和环境变量。为方便起见,Packer 默认将 -var 和环境变量值解释为字符串,不需要加引号:

$ export PKR_VAR_image_id=ami-abc123

但是,如果输入变量定义为一个复杂类型list/set/map/object/tuple),Packer 将改为尝试使用变量定义文件中使用的相同语法来解析其值,这需要特别注意到 shell 中的字符串转义规则:

$ export PKR_VAR_availability_zone_names='["us-west-1b","us-west-1d"]'

为了可读性,也为了避免 shell 转义引发的错误,我们建议始终通过变量定义文件设置复杂的变量值。

变量赋值的优先级

上述变量赋值的机制可以任意组合使用。

Packer 按以下顺序加载变量,优先级递增:

  • 环境变量(最低优先级)
  • 任何 *.auto.pkrvars.hcl*.auto.pkrvars.json 文件,按其文件名的字典顺序排序。
  • 命令行上的任何 -var-var-file 选项,按它们出现的顺序排列。 (最高优先级)

如果使用不同的机制为同一个变量分配了多个值,Packer 将使用它找到的最后一个值,覆盖任何以前的值。请注意,同一变量不能在单个来源中分配多个值。

重要提示:映射和对象值的变量与其他变量的行为方式相同:高优先级的值会覆盖低优先级值。

Packer 执行时输入变量值必须是已知的

假设这样一个输入变量:

variable "foo" {
  type = string
}

我们必须为 foo 设定一个值,但也可以将其 default 设置为 null 从而不需要设置值:

no default default = null default = "xy"
foo unused error, "foo needs to be set" - -
var.foo error, "foo needs to be set" null¹ xy
PKR_VAR_foo=yz
var.foo
yz yz yz
-var foo=yz
var.foo
yz yz yz

null 是一个合法值。Packer 只会在一个输入变量没有值的时候报错,例如:

variable "example" {
  type = string
  default = null
}

source "example" "foo" {
  arg = var.example
}

在上面的例子里,只要 arg 在使用 example 这个 source 时是可选的,那不对 arg 设置值就不会有错误。

为一个不存在的输入变量赋值并不一定会报错

Usage packer validate any other packer command
bar=yz in .pkrvars.hcl file. error, "bar undeclared" warning, "bar undeclared"
var.bar in .pkr.hcl file error, "bar undeclared" error, "bar undeclared"
-var bar=yz argument error, "bar undeclared" error, "bar undeclared"
export PKR_VAR_bar=yz - -

results matching ""

    No results matching ""