테라폼 같은 선언적 언어에는 for 반복문이 없습니다. 그렇다고 테라폼에서 이용을 하지 못하는건 아닙니다.
하지만 몇가지의 반복문 구성을 제공하여 사용할 수 있게 하였습니다.
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_iam_user" "wgpark-example" {
name = "wgpaark"
}
위 코드는 aws_iam_user 리소스를 사용하여 새 개별 IAM 사용자를 생성하는 코드입니다.
만약, 3명의 IAM 사용자를 생성하려면 프로그래밍을 배우신 분은 for문을 사용하여 만들려고하실겁니다. 하지만
테라폼에는 for 반복문 또는 언어에 내장된 기존의 절차 논리가 없기 때문에 동작하지 않습니다.
하지만 모든 테라폼 리소스에는 count 라는 메타 매개 변수가 있습니다.
resource "aws_iam_user" "wgpark_example" {
count = 3
name = "wgpaark.${count.index}"
}
위 코드를 이용하면 wgparrk0~2까지의 IAM 사용자를 3개 만들 수 있습니다.
여기서 variable의 입력변수에 원하는 모든 IAM 사용자 이름을 정의해 놓으면 원하는 값을 넣어 사용할 수 있습니다.
variable "user_names" {
type = list(string)
default = ["park1","park2","park3"]
# length(user_names) = 3
}
리소스에 count를 사용한 수에는 하나의 리소스가 아니라 리소스의 배열이 됩니다. aws_iam_user.wgpark-example은 이제 IAM 사용자의 배열이므로 표준 구문을 사용하여 해당 리소스인 <PROVIDER>_<TYPE>.<NAME>.<ATTRIBUTE>에서 속성을 읽는 대신 동일한 배열 조회 구문을 이용해 배열에서 인덱스를 지정함으로써 IAM 사용자를 명시해야합니다.
count에는 유용성을 저해하는 두 가지 제약이 있습니다.
첫 번째로는 count를 사용하여 전체 리소스를 반복할 수는 있지만 리소스 내에서 인라인 블록을 반복할 수는 없습니다. 인라인 블록을 다음 형식의 리소스 내에서 설정한 인수입니다.
resource "xxx" "yyy" {
<NAME> {
[CONFIR...]
}
}
여기서 NAME은 tag와 같은 인라인 블록의 이름이고 CONFIG는 key 또는 value 값이 해당 인라인 블록에 특정한 이상의 인수로 구성됩니다. CONFIG에 해당하는 인라인 블록 내에서 count 사용은 지원하지 않습니다.
두 번째 제약은 변경 하려고 할 때 발생합니다.앞서 생성한 IAM 사용자 목록을 확인하는 코드 블록입니다.
variable "user_names" {
type = list(string)
default = ["park1","park2","park3"]
}
이 리스트에서 park2를 제거하고 terraform plan을 실행하면 우리가 기대한 결과가 아닌 'park2' IAM 사용자를 삭제하는 대신 'park2' IAM 사용자의 이름을 'park3'로 바꾸고 원래 'park3'였던 사용자를 삭제할 것이라고 나타냅니다.
이러한 작업이 일어나는 이유는 리소스에 count 매개 변수를 사용하면 해당 리소스는 리소스 리스트 또는 리소스 배열이 됩니다.
테라폼은 해당 배열의 위치(index)로 배열 내의 각 리소스를 식별합니다.
즉, 처음 3명의 사요자 이름을 apply를 실행한 후 이러한 IAM 사용자에 대한 테라폼의 내부 표현은 다음과 같습니다.
aws_iam_user.wgpark_example[0] : park1
aws_iam_user.wgpark_example[1] : park2
aws_iam_user.wgpark_example[2] : park3
배열의 중간에서 항목을 제거하면 모든 항목이 1칸씩 앞으로 당겨집니다. 따라서 2개의 버킷 이름으로 plan 명령을 실행한 후의 테라폼 내부 표현은
aws_iam_user.wgpark_example[0] : park1
aws_iam_user.wgpark_example[1] : park3
입니다.
테라폼이 인덱스 번호를 리소스 식별자로 보기 때문에 이 변화를 대략 '인덱스1 에서는 버킷을 park2를 park3로 바꾸고 인덱스 2에서는 버킷을 삭제한다'로 해석합니다.
count를 사용하여 리소스 목록을 만들 때마다 목록 중간에서 항목을 제거하면 테라폼은 해당 항목 뒤에 있는 모든 리소스를 삭제한 다음 해당 리소스를 처음부터 다시 만드는 것입니다.
for_each 표현식을 사용하면 리스트,집합,맵을 사용하여 전체 리소스의 여러복사 본 또는 리소스 내 인라인 블록의 여러 복사본을 생성할 수 있습니다.
구문은 다음과 같습니다.
resource "<PROVIDER>_<TYPE>" "<NAME>" {
for_each = <COLLECTION> # COLLECTION은 루프를 처리할 집합 또는 맵입니다.
[CONFIG...]
}
리소스에 for_each 를 사용할 때 리스트는 지원되지 않습니다. 그리고 CONFIG는 해당 리소스와 관련된 하나 이상의 인수로 구성되는데 CONFIG 내에서 each.key 또는 each.value를 사용하여 COLLECTION에서 현재 항목의 키와 값에 접근 할 수 있습니다.
# Example
resource "aws_iam_user" "wgpark-example"{
for_each = toset(var.user_name)
name = each.value
}
var.user_names 리스트를 집합(set)으로 변환하기 위해 toset을 사용하는 것입니다.
for_each는 리소스에서 사용될 때만 집합과 맵을 지원합니다. for_each가 이 집합을 반복하면 each.value에서 각 사용자 이름을 사용할 수 있습니다. 일반적으로 each.key는 키/값 쌍의 맵에만 사용 가능하지만, 사용자 이름은 each.key에서도 사용할 수 있습니다.
for_each를 사용한 후에는 하나의 리소스 또는 count를 사용한 것과 같은 리소스 배열이 되는 것이 아니라 리소스 맵이 됩니다.
Terraform Up & Running 테라폼 Writing Infrastructure as code 업앤 러닝 - 예브게닝 브릭만