본문으로 바로가기

[Terraform] count와 for_each (Meta-Arguments)

category Devops/Terraform 2022. 12. 25. 10:00

개요

Meta-Argument는 Resource 나 Module에서 사용할 수 있는 Terraform의 특수한 아규먼트이다.

이 글에서는 Resource에 사용할 수 있는 Meta-Argument 중 count와 for_each를 소개한다.

 

1️⃣ count

하나의 Resource 혹은 Module에서 여러 인프라 리소스를 만들어내고 싶을 때 사용하는 Meta-Argument이다.

  • 숫자 표현식을 허용한다.
  • 생성할 인스턴스가 거의 동일한경우 for_each 보다는 count 사용이 적절하다.

기본 구문

  • 예시 1.
resource "aws_instance" "server" {
  count = 4 # create four similar EC2 instances

  ami           = "ami-a1b2c3d4"
  instance_type = "t2.micro"

  tags = {
    Name = "Server ${count.index}"
  }
}
  • 예시 2.
resource "aws_ec2_tag" "private_subnet_tag" {
  count          = length(module.vpc.private_subnets)
  resource_id    = module.vpc.private_subnets[0]
  key            = "Name"
  value          = "${var.name_prefix}private-${count.index}"
}

추가 Object

아래의 추가 object를 사용할 수 있다.

  1. count.index [0] : 인스턴스에 해당하는 고유의 인덱스 번호로 시작한다.
    • 인덱스 번호는 0부터 시작한다.
❗ count 사용 시 리소스를 인덱스로 식별할 수 있기 때문에 취약하다.
list의 요소 중 중간 요소가 삭제된다면 의도치 않은 변경사항이 발생할 수 있음.

2️⃣ for_each

하나의 Resource 혹은 Module에서 여러 인프라 리소스를 만들어내고 싶을 때 사용하는 Meta-Argument이다.

  • map 혹은 set 형식을 사용할 수 있다.
  • for_each의 map 또는 set의 각 항목에 대해 인스턴스를 생성한다.

기본 구문

  • 예시 1. map 형식의 for_each
resource "azurerm_resource_group" "rg" {
  for_each = {
    a_group = "eastus"
    another_group = "westus2"
  }

  name     = each.key
  location = each.value
}
  • 예시 2. set 형식의 for_each
resource "aws_iam_user" "the-accounts" {
  for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
  name     = each.key
}
  • 예시 3. 하위모듈
# my_buckets.tf
module "bucket" {
  for_each = toset(["assets", "media"])
  source   = "./publish_bucket"
  name     = "${each.key}_bucket"
}
# publish_bucket/bucket-and-cloudfront.tf
variable "name" {} # this is the input parameter of the module

resource "aws_s3_bucket" "example" {
  # Because var.name includes each.key in the calling
  # module block, its value will be different for
  # each instance of this module.
  bucket = var.name

  # ...
}

resource "aws_iam_user" "deploy_user" {
  # ...
}

 

추가 object

아래의 추가 object를 사용할 수 있다.

  1. each.key : map 혹은 set의 Key 값이다.
  2. each.value : map 혹은 set의 Value 값이다.
    • 만약 set 형식일 경우 each.value의 결괏값은 each.key와 동일하다.

유의사항

  1. map 혹은 set 은 known values이어야 한다. 아니라면 -target이 필요하다는 오류 메시지가 표시된다.
  2. for_each의 결괏값은 항상 UI에 출력되므로 민감한 변수들은 넣지 말자.

Expression

  • for_each 인수는 원하는 인스턴스당 하나의 element로 설정된 map이어야 한다.
    • 만약, for_each의 인수가 element가 아니라면 toset() 함수를 사용하여 값을 명시적으로 반환하는 식을 사용할 수 있다.
  • for_each는 변환 중에 의도치 않은 결과를 방지하기 위하여 암묵적으로 변환하지 않는다.
    • 예를 들면 tuple → set 자동 변환..
    • 만약 tuple 같은 구조화된 유형을 변환하고자 한다면 flatten() 함수를 이용할 수도 있다.
  • 만약, 입력변수로 set 형식을 사용한다면 입력변수의 type을 set(string)으로 지정하면 명시적 유형 변환이 필요하지 않다.
    • toset()을 사용하여 명시적으로 유형 변환을 하지 않아도 된다.