Cloud Native Solution/[IaC] terraform

[변수] 테라폼 Variable, Output, Data 개념과 예제 및 활용 방법

Cloud Engineer 2022. 3. 10. 14:46

1. 들어가기 전

테라폼에서 변수 형태로 사용되는 키워드는 3가지가 있습니다. 바로 입력 변수인 Variable, 출력 변수인 Output, Provider에서 제공하는 읽기 전용 정보를 호출하는 Data인데요. 해당 키워드가 존재하기 때문에 대규모의 인프라를 테라폼으로 구현하더라도 중복 배제 원칙(DRY, Don't Repeat Yourself)을 준수하여 HCL 코드를 작성할 수 있습니다. 본 포스팅에서는 위 3가지 키워드에 대한 개념과

2. Variable : 입력 변수

2.1. 기본 문법

Variable을 선언할 경우 총 3개의 매개변수가 포함될 수 있으며, 매개변수를 입력할지는 사용자의 선택사항(Optional)입니다.

variable "Name" {
  description   = "본 변수에 대한 설명"
  default	= "기본 변수값"
  type		= "데이터타입"		# string | list | map
}

2.1.1. description : 변수 사용 방법

입력 변수를 작성할 때 본 매개변수에서는 일반적으로 변수 사용 방법을 작성합니다. 협엽할 때 본 매개변수를 통해 코드를 이해할 수 있으며 plan, apply를 수행할 때 참고할 수 있습니다.

2.1.2. default : 변수의 기본값

테라폼 구동 시 사용자로부터 전달받은 변수가 없을 경우, 자동으로 default에 입력된 값을 사용합니다. 만약 본 매개변수 또한 없을 경우에는 plan, apply 명령어를 실행한 시점에 사용자가 변수값을 입력할 수 있도록 합니다. 사용자는 plan, apply 명령어에서 아래와 같이 옵션 형태로 변수값을 전달할 수 있습니다.

  • 변수값 전달 ( -var {변수명}={변수값} )
    • ex) terraform plan -var port_num="80"
  • 변수 파일 호출 ( --var-file {위치} )
    • ex) terraform plan --var-file ./var.tf
  • 환경변수 ( TF_VAR_{변수명} )
    • export TF_VAR_port_num="80"
    • 외부에 노출되면 안되는 변수에 대해 해당 방식으로 테라폼에 값을 전달합니다. (DB 패스워드 등)

2.1.3. type : 변수의 데이터 타입

테라폼에서 제공하는 입력 변수에 대한 데이터 타입은 string, list, map 총 3가지이며, 사용자가 type을 지정하지 않았을 경우 테라폼이 default 변수 속성을 참조하여 타입을 유추합니다. 만약 default 마저 정의되어 있지 않는다면 string으로 판단합니다.

2.2. 예제 : AWS Security Group 생성 후 53, 80, 443 포트 Open

# list
variable "server_port_list" {
  description = "port number"
  type        = "list"
  default     = ["80", "443", "53"]
}

# map
variable "server_port_map" {
  description = "port number"
  type        = "map"
  default     = {
    http = "80"
    https = "443"
    dns = "53"
  }
}

# string
variable "http_port_string" {
  description = "http port number"
  type        = "string"
  default     = "80"
}

# AWS Security Group 생성 및 53, 80, 443 포트 오픈
resource "aws_security_group" "my_server" {
  vpc_id = "${module.vpc.vpc_id}"		# module로 구현한다고 가정
  name = "my-server"
  description = "Terraform Security Group"
  ingress {
    from_port = lookup(var.server_port_map, "http")
    to_port = lookup(var.server_port_map, "http")
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  ingress {
    from_port = lookup(var.server_port_map, "https")
    to_port = lookup(var.server_port_map, "https")
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
 ingress {
    from_port = lookup(var.server_port_map, "dns")
    to_port = lookup(var.server_port_map, "dns")
    protocol = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
  egress {
    from_port       = 0
    to_port         = 0
    protocol        = "-1"
    cidr_blocks     = ["0.0.0.0/0"]
  }
}

3. Output : 출력 변수

3.1. 기본 문법

apply 명령어를 통해 인프라에 반영 후 특정 리소스에 대한 속성값을 출력하여 확인하고 싶을 경우 본 키워드를 사용합니다.

output "Name" {
	value = "변수값"
}

3.2. 예제 : EC2 생성 후 해당 노드의 공인 IP를 출력

resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id		# AWS에서 ubuntu AMI 추출
  instance_type = "t3.micro"

  tags = {
    Name = "my-node"
  }
}

# 출력 변수
output "public_ip" {
	value = "${aws_instance.web.public_ip}"
}

3.3. 레퍼런스 활용법

Terraform 홈페이지에 공식 Provider로 등록되어 있는 AWS에 대한 Documentation에 들어가서 각 인스턴스의 Resources를 확인해보시면 Attributes Reference라는 부분이 있습니다. 해당 내용을 참고하여 출력 가능한 값을 확인할 수 있습니다.

4. Data : Provider에서 제공하는 읽기 전용 정보 호출

4.1. 기본 문법

테라폼이 수행될 때마다 Provider에서 제공하는 읽기 전용 정보를 호출할 때 본 키워드를 사용합니다. 해당 키워드를 통해 Provider에서 제공하는 API를 통해 정보를 가져올 수 있으며 가용 영역, AMI ID를 비롯하여 IP 대역 등의 현재 Provider에 구성된 인프라 형상 정보 또한 불러들일 수 있습니다.

data "타입" "이름" {
  매개변수 = "값"

  # 호출한 데이터 중 특정 리소스만 가져오고 싶을 때 하기 키워드를 이용
  filter {
  	...
  }
}

4.2. 예제

# 테라폼으로 생성한 EC2 노드에 대한 정보를 수집
data "aws_instance" "my_server_info" {
  instance_id = "${aws_instance_web.id}"

  filter {
    name   = "image-id"
    values = [${aws_instance.web.ami}]
  }

  filter {
    name   = "tag:Name"
    values = [${aws_instance.web.tags.Name}]
  }
}

4.3. 레퍼런스 활용법

Terraform 홈페이지에 공식 Provider로 등록되어 있는 AWS에 대한 Documentation에 들어가서 각 인스턴스의 Data Sources를 확인해보시면 Argument Reference라는 부분이 있습니다. 해당 내용을 참고하여 호출이 가능한 값을 확인할 수 있습니다.