dynamic 블록
dynamic 블록 (dynamic Blocks)
리소스 같은 최상위 블록 안에서 표현식은 보통 name = expression 형태로 인자에 값을 할당할 때만 사용할 수 있어요. 이것으로 많은 경우를 처리할 수 있지만, 일부 리소스 타입은 인자 안에 반복 가능한 중첩 블록(nested block)을 가지며, 이 블록은 보통 포함하는 객체와 관련된(또는 임베드된) 별도의 객체를 나타내요.
출처: 문서
본문
why dynamic
예를 들어 다음과 같은 리소스에서 setting 블록은 항상 리터럴 블록이에요:
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf-test-name" # can use expressions here
setting {
# but the "setting" block is always a literal block
}
}
resource, data, provider, provisioner 블록 안에서 지원되는 특별한 dynamic 블록 타입을 사용하면 setting 같은 반복 가능한 중첩 블록을 동적으로 구성할 수 있어요:
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
name = "tf-test-name"
application = aws_elastic_beanstalk_application.tftest.name
solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"
dynamic "setting" {
for_each = var.settings
content {
namespace = setting.value["namespace"]
name = setting.value["name"]
value = setting.value["value"]
}
}
}
dynamic 블록은 for 표현식과 유사하게 동작하지만, 복합 타입 값 대신 중첩 블록을 생성해요. 주어진 복합 값을 반복하며, 그 복합 값의 각 요소에 대해 중첩 블록 하나를 생성해요.
- dynamic 블록의 라벨(위 예제의
"setting")은 생성할 중첩 블록의 종류를 지정해요. for_each인자는 반복할 복합 값을 제공해요.iterator인자(선택)는 복합 값의 현재 요소를 나타내는 임시 변수의 이름을 설정해요. 생략하면 변수 이름은 기본적으로dynamic블록의 라벨(위 예제의"setting")이 돼요.labels인자(선택)는 생성되는 각 블록에 순서대로 사용할 블록 라벨을 지정하는 문자열 리스트예요. 이 값에 임시 반복자 변수를 사용할 수 있어요.- 중첩된
content블록은 생성되는 각 블록의 본문을 정의해요. 이 블록 안에서 임시 반복자 변수를 사용할 수 있어요.
for_each 인자는 어떤 컬렉션이나 구조적 값이든 받을 수 있으므로, for 표현식이나 splat 표현식을 사용해 기존 컬렉션을 변환할 수 있어요.
반복자 객체(위 예제의 setting)는 두 개의 속성을 가져요:
key는 현재 요소의 맵 키 또는 리스트 요소 인덱스예요.for_each표현식이 set 값을 생성하면key는value와 동일하므로 사용하지 말아야 해요.value는 현재 요소의 값이에요.
dynamic 블록은 구성 중인 리소스 타입, 데이터 소스, 프로바이더 또는 프로비저너에 속한 인자만 생성할 수 있어요. lifecycle나 provisioner 블록 같은 메타-인자 블록은 생성할 수 없어요. Terraform이 표현식을 안전하게 평가하기 전에 처리해야 하기 때문이에요.
for_each 값은 원하는 중첩 블록 하나당 요소 하나를 가진 컬렉션이어야 해요. 중첩 데이터 구조나 여러 데이터 구조의 요소 조합을 기반으로 리소스 인스턴스를 선언해야 한다면 Terraform 표현식과 함수를 사용해 적절한 값을 도출할 수 있어요. 이런 상황의 일반적인 예는 flatten과 setproduct 함수 문서를 참고하세요.
다중 레벨 중첩 블록 구조 (Multi-level Nested Block Structures)
일부 프로바이더는 서로 안에 여러 레벨로 중첩된 블록을 포함하는 리소스 타입을 정의해요. 이런 중첩 구조는 다른 dynamic 블록의 content 부분에 dynamic 블록을 중첩함으로써 필요할 때 동적으로 생성할 수 있어요.
예를 들어, 모듈이 다음과 같은 복잡한 데이터 구조를 받아들일 수 있어요:
variable "load_balancer_origin_groups" {
type = map(object({
origins = set(object({
hostname = string
}))
}))
}
원본 그룹마다 블록이 하나씩, 그리고 그룹 안의 원본마다 중첩 블록이 하나씩 있는 리소스 타입을 정의하는 경우, 다음과 같은 중첩 dynamic 블록을 사용해 동적으로 생성하도록 Terraform에 요청할 수 있어요:
dynamic "origin_group" {
for_each = var.load_balancer_origin_groups
content {
name = origin_group.key
dynamic "origin" {
for_each = origin_group.value.origins
content {
hostname = origin.value.hostname
}
}
}
}
중첩 dynamic 블록을 사용할 때는 각 블록의 반복자 기호에 특히 주의해야 해요. 위 예제에서 origin_group.value는 바깥 블록의 현재 요소를 가리키고, origin.value는 안쪽 블록의 현재 요소를 가리켜요.
특정 리소스 타입이 부모와 동일한 타입 이름의 중첩 블록을 정의한다면, 각 dynamic 블록에서 iterator 인자를 사용해 두 블록을 구분하기 쉬운 다른 반복자 기호를 선택할 수 있어요.
dynamic 블록의 모범 사례 (Best Practices)
dynamic 블록을 과도하게 사용하면 구성을 읽고 유지하기 어려워질 수 있어요. 재사용 가능한 모듈을 위한 깔끔한 사용자 인터페이스를 만드는 데 세부사항을 숨길 필요가 있을 때만 사용하는 것을 권장해요. 가능하면 중첩 블록은 항상 리터럴로 작성하세요.
resource 블록의 인자와 중첩 블록 대부분을 입력 변수의 직접 대응 속성으로 정의하고 있다면, 그 모듈이 유용한 추상화를 만들지 못하고 있을 가능성이 있어요. 호출하는 모듈이 리소스 자체를 정의한 다음 그 정보를 모듈에 전달하는 것이 더 나을 수 있어요. 이 설계 트레이드오프에 대한 자세한 내용은 모듈을 작성해야 할 때와 모듈 구성 문서를 참고하세요.
더 알아보기 (Learn more)
- for 표현식 (for Expressions): 컬렉션 변환
- Splat 표현식 (Splat Expressions): 컬렉션 요소 속성 접근
- flatten 함수: 중첩 컬렉션 평탄화
- setproduct 함수: 컬렉션 곱집합 생성