About/IaC

[Terraform] for_each 문법 및 사용 예시(Meta Argument)

김징어 2022. 6. 13. 18:05

이전 포스팅에서 Terraform의 count 문법에 대하여 알아보았습니다.

2022.06.11 - [About/DevOps] - [Terraform] Meta-Agument - count

테라폼에서 여러 리소스를 한 번에 생성하는 방법으로는 countfor_each가 있는데 이번 포스팅에서 for_each에 대하여 다루어 보도록 하겠습니다.  자세한 정보는 Terraform 공식 문서에서 확인할 수 있습니다.

https://www.terraform.io/language/meta-arguments/for_each

 

The for_each Meta-Argument - Configuration Language | Terraform by HashiCorp

The for_each meta-argument allows you to manage similar infrastructure resources without writing a separate block for each one.

www.terraform.io


for_each

for_each는 Terraform 언어에서 정의한 메타 인수입니다. 모듈 및 모든 리소스 유형과 함께 사용할 수 있습니다. 우선
Terraform의 MapSet 변수에 대하여 알아야합니다.

  • set : 유일한 값의 요소들로 이루어진 list
    • [1, 2, 3]
  • map : Key-Value 형식의 데이터
    • { k : v, k2 : v2 }
    • key 값은 string이여야함

Terraform은 해당 Map 또는 Set 의 각 구성원에 대해 하나의 인스턴스를 생성합니다. 

Basic Syntax

for_each는 Terraform 언어에서 정의한 메타 인수입니다. 모듈 및 모든 리소스 유형과 함께 사용할 수 있습니다.

for_each 메타 인수는 Map 또는 String Set 를 허용하고 해당 또는 세트의 각 항목에 대한 인스턴스를 생성합니다. 각 인스턴스에는 연결된 고유한 인프라 개체가 있으며 구성이 적용될 때 각각 별도로 생성, 업데이트 또는 소멸됩니다.

예시 - Map을 사용한 for_each

resource "azurerm_resource_group" "rg" {
  for_each = {
    a_group = "eastus"
    another_group = "westus2"
  }
  name     = each.key
  location = each.value
}

 

예시 - Set을 사용한 for_each

resource "aws_iam_user" "the-accounts" {
  for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
  name     = each.key
}

 

each Object

for_each가 설정된 블록에서는 표현식에서 각 개체를 추가로 사용할 수 있으므로 각 인스턴스의 구성을 수정할 수 있습니다. 이 개체에는 두 가지 속성이 있습니다.

  • each.key — 인스턴스에 해당하는 Map의 Key(또는 Set의 Value)입니다.
  • each.value — 인스턴스에 해당하는 Map의 Value니다. (Set의 경우 each.key와 동일)

for_each 예시

for_each - set 자료형 사용 예시

for_each를 이용해서 AWS에서 IAM User 를 여러 개 생성해보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
provider "aws" {
    region = "ap-northeast-2"
}
 
resource "aws_iam_user" "for_each_set" {
  for_each = toset([
    "for-each-set-user-1",
    "for-each-set-user-2",
    "for-each-set-user-3"
  ])
 
  name = each.key
}
 
output "for_each_set_user_arns" {
  value = values(aws_iam_user.for_each_set).*.arn
}
cs

 

  • 6번 라인 : toset() 함수를 통해서 리스트 자료형을 set으로 변경합니다.
  • 7~9번 라인 : IAM User의 name에 사용할 값입니다.
  • 12번 라인 : each.key를 이용하여 set의 데이터를 가져옵니다. set이기 때문에 each.value를 이용해도 상관없습니다.
  • 13번 라인 : for_eachmap형태로 참조됩니다. 따라서 values() 함수를 이용하여 값만 가져오도록 하여 생성된 리소스의 모든 arn을 출력합니다.

위의 코드를 이용해 Terraform apply를 통해 적용한 결과는 다음과 같습니다.

Outputs:

for_each_set_user_arns = [
  "arn:aws:iam::536887461755:user/for-each-set-user-1",
  "arn:aws:iam::536887461755:user/for-each-set-user-2",
  "arn:aws:iam::536887461755:user/for-each-set-user-3",
]

 

또한 AWS Management Console에 접속해서 생성된 IAM User를 확인할 수 있습니다.

for_each - map 자료형 예시

이번에는 set이 아닌 map 자료형을 통해 리소스를 생성해보도록 하겠습니다. 이전과 동일하게 AWS에서 IAM User를 생성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
provider "aws" {
    region = "ap-northeast-2"
}
 
resource "aws_iam_user" "for_each_map" {
  for_each = {
    alice = {
      level = "low"
      manager = "mhmhm3"
    }
    bob = {
      level = "mid"
      manager = "wlghks5"
    }
    jh = {
      level = "high"
      manager = "mcc32"
    }
  }
 
  name = each.key
  tags = each.value
}
 
output "for_each_map_user_arns" {
  value = values(aws_iam_user.for_each_map).*.arn
}
cs

 

  • 6번 라인 : map자료형은 toset()과 같은 함수 필요 없이 {}를 통해서 바로 생성할 수 있습니다.
  • 7~18번 라인 : IAM User의 생성에 사용할 정보를 정의합니다. map이기 때문에 key = value 형태로 정의합니다.
  • 21~22번 라인 : IAM User의 name은 mapkey 값, 그리고 tags에는 mapValue를 사용합니다.

위의 코드를 이용해 Terraform apply를 통해 적용하고  AWS Management Console에 접속해서 생성된 IAM User와 태그를 확인할 수 있습니다.

$ terraform state list
aws_iam_user.for_each_map["alice"]
aws_iam_user.for_each_map["bob"]
aws_iam_user.for_each_map["jh"]

 

Map 자료형은 key-value 형식으로 관리되기 때문에 좀 더 유리할 수 있습니다. 또한 이전에 count에서 발생할 수 있는 문제가 발생하지 않습니다. 예를들어 중간에 bob이 퇴사를 한다고 하더라도 bob에 대한 value만 삭제하면 되므로 문제가 생기지 않습니다.


Terraform의 for_each에 대하여 알아보았습니다.

참고

https://www.terraform.io/language/meta-arguments/for_each

https://fastcampus.co.kr/dev_online_awsdevops