입력 변수 — 모듈 인자를 유연하게 받는 방법
입력 변수 — 모듈 인자를 유연하게 받는 방법
같은 서버를 개발, 스테이징, 운영 환경마다 만든다고 상상해 봐요. 하드코딩된 값으로는 그때그때 다르게 만들 수 없어요. 이럴 때 variable 블록을 쓰면 모듈의 입력 인터페이스를 정의해서, 실행 시점에 사용자가 원하는 값을 넣을 수 있어요.
출처: https://developer.hashicorp.com/terraform/language/values/variables
본문
왜 변수가 필요한가
Terraform이 하드코딩된 값으로 리소스를 만들면 매번 똑같은 결과만 나와서, 모듈이 유연하지 않고 재사용하기 어려워져요. 운영마다 바뀌는 값을 알고 있다면 그 자리에 variable 블록을 넣어요. 그러면 모듈 소비자가 모듈 소스 코드를 고치지 않고도 동작을 바꿀 수 있어요.
예를 들어 루트 모듈의 리소스가 하드코딩된 값을 갖고 있다고 해볼게요.
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
subnet_id = "subnet-12345"
tags = {
Environment = "dev"
Name = "dev-web-server"
}
}
입력으로 받고 싶은 값마다 variable 블록을 하나씩 추가하면 돼요. 다음은 instance_type, subnet_id, environment 변수를 정의한 예시예요.
variable "instance_type" {
type = string
description = "EC2 instance type for the web server"
default = "t2.micro"
}
variable "subnet_id" {
type = string
description = "Subnet ID where the web server will be deployed"
}
variable "environment" {
type = string
description = "Deployment environment name"
default = "dev"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
environment 변수에는 validation 블록도 들어 있어요. 소비자가 넣은 값이 모듈 요구사항을 만족하는지 확인하죠. 변수 값 검증에 대한 자세한 내용은 validate 문서를 보세요.
변수를 참조하는 법
변수를 다른 구성에서 참조할 때는 var.<NAME> 문법을 써요. 하드코딩된 값을 var.instance_type 같은 참조로 바꿔보면 이렇게 돼요.
# ...
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = var.instance_type
subnet_id = var.subnet_id
tags = {
Environment = var.environment
Name = "${var.environment}-web-server"
}
}
모듈 소비자는 environment, subnet_id, instance_type의 기본값을 그대로 쓰거나, 실행할 때 직접 값을 넣을 수 있어요. subnet_id처럼 기본값이 없는 변수는 플랜을 만들기 전에 Terraform이 값을 입력하라고 물어봐요.
민감한 값 다루기
API 키나 비밀번호처럼 민감한 변수는 sensitive 인자를 써서 Terraform이 CLI 출력에 값을 표시하지 않게 할 수 있어요.
variable "database_password" {
type = string
description = "Password for the RDS database instance"
sensitive = true
}
민감한 변수의 값도 여전히 상태(state)에 저장돼요. 상태와 플랜 파일에서 아예 빼고 싶다면 ephemeral 인자를 추가하면 되는데, 이 경우 그 변수에 넣을 수 있는 값에 제약이 생겨요. 민감 데이터 처리에 대한 자세한 내용은 민감 데이터 관리 문서를 보세요.
변수에 값 할당하기
루트 모듈 변수에는 여러 방법으로 값을 넣을 수 있고, 각 방법마다 우선순위가 달라요. 자식 모듈은 부모 모듈이 인자로 값을 전달받아요.
한 파일 안에서는 변수에 값을 두 번 할당할 수 없어요. 하지만 같은 이름의 변수에 여러 소스에서 값이 들어오면 Terraform은 다음 순서로 우선순위를 정해요.
- 명령줄의
-var와-var-file옵션(입력 순서대로), 그리고 HCP Terraform의 변수 - 사전순으로 정렬된
*.auto.tfvars또는*.auto.tfvars.json파일 terraform.tfvars.json파일terraform.tfvars파일- 환경 변수
variable블록의default인자
명령줄 변수
일회성 배포나 파일을 새로 만들지 않고 특정 값을 덮어쓰고 싶을 때는 CLI 플래그로 값을 넣어요. -var=<VAR_NAME>=<VALUE> 형식이에요.
terraform apply -var="instance_type=t3.medium" -var="environment=prod"
terraform apply -var='subnet_ids=["subnet-12345","subnet-67890"]'
환경 변수나 명령줄 플래그로 복잡한 타입을 넘길 때는 셸의 문자열 이스케이프 규칙을 지키려고 올바른 JSON 문법을 써야 해요.
export TF_VAR_complex_config='{"key": "value", "list": ["a", "b"]}'
가독성을 위해서라면 복잡한 변수 값은 변수 정의 파일로 넘기는 걸 권장해요.
변수 정의 파일
환경마다 구성을 다르게 관리하거나, 변수 값을 버전 관리에 넣고 싶다면 변수 정의 파일이 좋아요. .tfvars나 .auto.tfvars 확장자를 가진 파일에서 변수 이름에 직접 값을 할당해요. 다음은 프로덕션 환경의 값을 넣은 파일이에요.
instance_type = "t3.large"
environment = "prod"
subnet_ids = ["subnet-12345", "subnet-67890", "subnet-abcdef"]
enable_monitoring = true
Terraform은 다음 중 하나를 감지하면 변수 정의 파일을 자동으로 로드해요.
.auto.tfvars또는.auto.tfvars.json로 끝나는 파일 이름terraform.tfvars.json파일terraform.tfvars파일
파일 이름이 .json으로 끝나면 Terraform은 그 파일을 JSON 객체로 파싱하고, 변수 이름을 루트 객체의 키로 사용해요.
{
"image_id": "ami-abc123",
"availability_zone_names": ["us-west-1a", "us-west-1c"]
}
CLI에서 -var-file 플래그로 직접 .tfvars 파일을 적용할 수도 있어요.
terraform apply -var-file="production.auto.tfvars"
정의 파일에 민감한 값이 들어 있다면 버전 관리에서는 그 파일을 무시하도록 gitignore를 설정해야 해요. 정의 파일의 로드 시점과 우선순위는 다음과 같아요.
- 사전순의
*.auto.tfvars또는*.auto.tfvars.json파일 terraform.tfvars.json파일terraform.tfvars파일
환경 변수
CI/CD 파이프라인에서 파일을 추가로 만들지 않고 값을 주입하고 싶을 때 환경 변수가 편해요. 변수 이름 앞에 TF_VAR_ 접두사를 붙이면 돼요.
export TF_VAR_instance_type=t3.medium
export TF_VAR_environment=staging
terraform apply
선언되지 않은 변수
선언되지 않은 변수에 값을 넣는 상황은 값 할당 방법에 따라 다르게 처리해요.
- 매칭되는
variable블록이 없는 환경 변수는 무시돼요. - 변수 정의 파일에서 선언되지 않은 변수에 값을 할당하면 경고가 떠서, 구성이나 정의 파일의 오타를 잡을 수 있어요.
- 명령줄
-var로 선언되지 않은 변수 값을 주면 오류가 나요.
수명주기
Terraform은 대부분의 변수 값을 플랜을 만들 때 평가해요. 모듈이나 프로바이더의 source와 version 속성에 변수를 쓰려면 const 속성을 설정해서 초기화(init) 중에 평가되도록 해야 해요.