입력 변수
입력 변수 (Input Variables)
Packer 템플릿에서 입력 변수에 대한 레퍼런스 정보를 제공하는 문서예요. Packer에서 로컬 변수를 사용하는 방법은 Local Variables 문서를 참고하세요.
출처: Packer 공식 문서
본문
소개 (Introduction)
입력 변수(input variables)는 때때로 변수(variables) 또는 Packer 변수라고 불리며, Packer 빌드의 매개변수예요. 입력 변수를 사용하면 빌드 자체의 소스 코드를 변경하지 않고도 빌드의 여러 측면을 커스터마이즈할 수 있습니다. 일부 입력 변수는 커맨드라인 옵션, 환경 변수, 또는 변수 정의 파일로 재정의할 수 있는 기본값을 가져요. 입력 변수는 최초 재정의 후에는 값을 변경할 수 없습니다.
추가 정보는 Input Variables and local variables 문서를 참고하세요.
입력 변수 선언하기 (Declaring an Input Variable)
빌드가 받아들이는 각 입력 변수는 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 키워드 뒤의 레이블이나 variables 블록의 레이블은 변수의 이름이며, 같은 빌드 내의 모든 변수 중에서 고유해야 해요. 이 이름은 외부에서 변수에 값을 할당하고, 빌드 내부에서 변수 값을 참조하는 데 사용됩니다.
인자 (Arguments)
Packer는 변수 선언에 대해 다음 인자를 정의합니다.
default- 변수를 선택 사항으로 만들어 주는 기본값.type- 변수에 허용되는 값 타입을 지정하는 인자.description- 입력 변수의 문서화를 지정해요.validation- 보통 타입 제약에 더해 검증 규칙을 정의하는 블록.sensitive- 그 변수의 문자열 값들이 Packer 출력에서 난독 처리되게 해요.
기본값 (Default values)
변수 선언은 default 인자를 포함할 수도 있어요. 이것이 있으면 변수는 선택 사항으로 간주되고, Packer를 실행할 때 값이 설정되지 않으면 기본값이 사용됩니다. default 인자는 리터럴 값을 요구하며 구성 안의 다른 객체를 참조할 수 없어요.
타입 제약 (Type Constraints)
variable 블록의 type 인자는 변수의 값으로 받아들여질 값의 타입을 제한할 수 있게 해 줍니다. 타입 제약이 설정되지 않으면 모든 타입의 값이 허용돼요.
타입 제약은 선택 사항이지만 지정을 권장합니다. 빌드 사용자에게 쉬운 알림 역할을 하고, 잘못된 타입이 사용되면 Packer가 도움이 되는 오류 메시지를 반환하게 해 줍니다.
타입 제약은 타입 키워드와 타입 생성자(constructor)의 혼합으로 만들어져요. 지원되는 타입 키워드는 다음과 같습니다.
stringnumberbool
타입 생성자는 컬렉션 같은 복잡한 타입을 지정할 수 있게 해 줍니다.
list(<TYPE>)set(<TYPE>)map(<TYPE>)object({<ATTR NAME> = <TYPE>,...})tuple([<TYPE>,...])
any 키워드는 어떤 타입이든 허용됨을 나타내는 데 사용할 수 있어요. 이 여러 타입의 의미와 동작, 복잡한 타입의 자동 변환에 대한 자세한 내용은 Type Constraints 문서를 참고하세요.
type과 default 인자가 모두 지정되면, 주어진 기본값은 지정된 타입으로 변환 가능해야 해요.
default만 지정되면 기본값의 타입이 사용됩니다.
type과 default가 모두 지정되지 않고 환경 변수나 커맨드라인에서 변수를 설정하려 하면, 변수는 항상 문자열로 해석돼요.
입력 변수 문서화 (Input Variable Documentation)
빌드의 입력 변수는 사용자 인터페이스의 일부이므로, 선택적 description 인자를 사용해 각 변수의 목적을 간단히 설명할 수 있어요.
variable "image_id" {
type = string
description = "The ID of the machine image (AMI) to use for the server."
}
description은 변수의 목적과 어떤 종류의 값이 기대되는지 간결하게 설명해야 해요. 이 설명 문자열은 빌드에 대한 문서에 포함될 수 있으므로, 빌드의 유지 관리자가 아니라 빌드 사용자의 관점에서 작성해야 합니다. 빌드 유지 관리자를 위한 주석은 comments를 사용하세요.
사용자 정의 검증 규칙 (Custom Validation Rules)
타입 제약에 더해, 해당 variable 블록 안에 중첩된 하나 이상의 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-\"."
}
}
condition 인자는 값이 유효하면 true를, 유효하지 않으면 false를 반환하기 위해 반드시 변수의 값을 사용해야 하는 표현식이에요. 이 표현식은 조건이 적용되는 변수만 참조할 수 있으며, 오류를 발생시키면 안 됩니다.
표현식의 실패가 검증 결정의 근거라면 can 함수를 사용해 그런 오류를 감지하세요. 예를 들면 다음과 같습니다.
variable "image_id" {
type = string
description = "The ID of the machine image (AMI) to use for the server."
validation {
# regex(...) fails if it cannot find a match
condition = can(regex("^ami-", var.image_id))
error_message = "The image_id value must be a valid AMI ID, starting with \"ami-\"."
}
}
condition이 false로 평가되면 error_message에 주어진 문장들을 포함하는 오류 메시지가 만들어져요. 오류 메시지 문자열은 위 예시들과 비슷한 문장 구조로, 실패한 제약을 설명하는 완전한 문장 하나 이상이어야 합니다.
검증은 더 복잡한 경우에도 동작해요.
variable "image_metadata" {
default = {
key: "value",
something: {
foo: "bar",
}
}
validation {
condition = length(var.image_metadata.key) > 4
error_message = "The image_metadata.key field must be more than 4 runes."
}
validation {
condition = can(var.image_metadata.something.foo)
error_message = "The image_metadata.something.foo field must exist."
}
validation {
condition = substr(var.image_metadata.something.foo, 0, 3) == "bar"
error_message = "The image_metadata.something.foo field must start with \"bar\"."
}
}
민감한 변수 숨기기 (Suppressing Sensitive Variables)
변수가 민감(sensitive)하면 그 변수의 모든 문자열 값이 Packer 출력에서 난독 처리돼요.
# var-foo.pkr.hcl
variable "foo" {
sensitive = true
default = {
key = "SECR3TP4SSW0RD"
}
}
$ packer inspect var-foo.pkr.hcl
Packer Inspect: HCL2 mode
> input-variables:
var.foo: "{\"key\" = \"<sensitive>\" }"
...
입력 변수 값 사용하기
변수를 선언한 빌드 안에서 그 값은 표현식에서 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
다음 섹션들에서 이 옵션들을 더 자세히 설명할게요.
커맨드라인의 변수 (Variables on the Command Line)
커맨드라인에서 개별 변수를 지정하려면 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 파서가 무엇이 설정되고 있는지 이해하는 데 도움이 돼요. 그렇지 않으면 인터프리터는 커맨드라인에 설정된 모든 변수를 문자열로 간주합니다.
표준 변수 정의 파일 (Standard Variable Definitions Files)
많은 변수를 설정하려면 .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",
]
Important: 레거시 JSON 템플릿과 달리, 변수 정의 파일 안의 입력 변수는 값이 할당되기 전에 표준 HCL2 템플릿 파일 *.pkr.hcl 안의 variables 블록으로 선언되어야 해요. 그렇게 하지 않으면 Packer 실행 중에 알 수 없는 변수(unknown variable) 오류가 발생합니다.
자동 로드 변수 정의 파일 (Auto-loaded Variable Definitions Files)
Packer는 변수 정의 파일이 존재하면 하나 이상을 자동으로 로드할 수도 있어요.
.auto.pkrvars.hcl또는.auto.pkrvars.json으로 끝나는 이름의 모든 파일.
이름이 .json으로 끝나는 파일은 HCL 대신 JSON 객체로 파싱되며, 루트 객체의 속성이 변수 이름에 대응합니다.
{
"image_id": "ami-abc123",
"availability_zone_names": ["us-west-1a", "us-west-1c"]
}
Important: 레거시 JSON 템플릿과 달리, 변수 정의 파일 안의 입력 변수는 값이 할당되기 전에 표준 HCL2 템플릿 파일 *.pkr.hcl 안의 variables 블록으로 선언되어야 해요. 그렇게 하지 않으면 Packer 실행 중에 알 수 없는 변수(unknown variable) 오류가 발생합니다.
환경 변수 (Environment Variables)
변수를 정의하는 다른 방식의 폴백으로, Packer는 자신의 프로세스 환경에서 선언된 변수의 이름 뒤에 PKR_VAR_가 붙은 환경 변수를 검색해요.
이는 자동화에서 Packer를 실행하거나, 같은 변수들로 일련의 Packer 커맨드를 연달아 실행할 때 유용할 수 있어요. 예를 들어 Unix 시스템의 bash 프롬프트에서:
$ export PKR_VAR_image_id=ami-abc123
$ packer build gcp/debian/
...
환경 변수 이름이 대소문자를 구분하는 운영체제에서 Packer는 구성에 주어진 그대로 변수 이름을 매칭하므로, 필요한 환경 변수 이름은 위 예시처럼 대문자와 소문자가 섞여 있을 때가 많아요.
복합 타입 값 (Complex-typed Values)
변수 값이 변수 정의 파일에서 제공되면, Packer의 일반적인 문법으로 리스트와 맵 같은 복합 타입 값을 할당할 수 있어요.
-var 커맨드라인 옵션과 환경 변수에는 몇 가지 특별한 규칙이 적용돼요. 편의상 Packer는 기본적으로 -var와 환경 변수 값을 따옴표 없이 리터럴 문자열로 해석합니다.
$ export PKR_VAR_image_id=ami-abc123
하지만 빌드 변수가 타입 제약으로 복합 값(list, set, map, object, tuple)을 요구하면, Packer는 대신 변수 정의 파일 안에서 사용되는 것과 같은 문법으로 그 값을 파싱하려 시도해요. 이 경우 셸의 문자열 이스케이프 규칙에 주의해야 합니다.
$ export PKR_VAR_availability_zone_names='["us-west-1b","us-west-1d"]'
가독성을 위해, 그리고 셸 이스케이프에 신경 쓸 필요를 없애기 위해, 복합 변수 값은 항상 변수 정의 파일로 설정할 것을 권장합니다.
변수 정의 우선순위 (Variable Definition Precedence)
위의 변수 설정 메커니즘들은 어떤 조합으로든 함께 사용할 수 있어요.
Packer는 다음 순서로 변수를 로드하며, 나중 소스가 앞선 소스보다 우선합니다.
- 환경 변수 (가장 낮은 우선순위)
*.auto.pkrvars.hcl또는*.auto.pkrvars.json파일들. 파일 이름의 어휘 순서대로 처리돼요.- 커맨드라인의
-var및-var-file옵션들. 제공된 순서대로 처리됩니다. (가장 높은 우선순위)
같은 변수가 다른 메커니즘으로 여러 값을 할당받으면 Packer는 찾은 마지막 값을 사용해 이전 값을 재정의해요. 같은 소스 안에서 같은 변수에 여러 값을 할당할 수는 없다는 점을 참고하세요.
Important: 맵과 객체 값을 가진 변수도 다른 변수와 똑같이 동작해요. 마지막으로 찾은 값이 이전 값들을 재정의합니다.
변수 값은 알려져 있어야 해요 (A variable value must be known):
다음 변수를 예로 들어 볼게요.
variable "foo" {
type = string
}
여기서 foo는 알려진 값을 가져야 하지만, 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 |
1: Null은 유효한 값이에요. Packer는 받는 필드가 값을 필요로 할 때만 오류를 냅니다. 예:
variable "example" {
type = string
default = null
}
source "example" "foo" {
arg = var.example
}
위의 경우 "example" 소스에서 "arg"가 선택 사항인 한 오류가 없고 arg는 설정되지 않아요.
알 수 없는 변수를 설정하는 것이 항상 실패하지는 않아요 (Setting an unknown variable will not always fail):
| 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 | - | - |