输入变量
注意:此页面是关于 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 文档。
如果同时指定了 type
和 default
参数,则给定的 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 |
- | - |