속성을 블록으로 사용하기

속성을 블록으로 사용하기 (Attributes as Blocks)

인자 문법과 중첩 블록 문법의 특수한 상호작용을 설명하는 부록 문서예요. 대부분의 사용자는 잘 알 필요가 없는 동작이지만 JSON 문법을 쓰거나 재사용 모듈을 만들 때는 알아두면 좋아요.

출처: 문서

본문

참고: 이 페이지는 Terraform 문서의 부록이에요. 대부분의 사용자는 이 동작의 전체 세부 사항을 알 필요가 없어요.

요약 (Summary)

많은 리소스 유형이 반복 가능한 중첩 블록을 사용해서 기본 리소스와 관련된 하위 객체 컬렉션을 관리해요. 드물게 일부 리소스 유형은 중첩 블록 유형과 같은 이름의 인자도 지원하며, 그 인자가 빈 목록(= [])으로 설정되면 해당 유형의 하위 객체를 모두 제거해요.

대부분의 사용자는 이 "중첩 블록 또는 빈 목록" 동작에 대해 더 알 필요가 없어요. 하지만 다음 경우에는 더 읽어보는 것이 좋아요:

  • 이 유형의 리소스와 함께 Terraform의 JSON 문법을 사용할 때
  • 이 유형의 리소스를 감싸는 재사용 가능한 모듈을 만들 때

세부 사항 (Details)

Terraform v0.12 이상에서 언어는 블록 안의 인자 문법과 중첩 블록 문법을 구분해요:

  • 인자 문법은 포함하는 객체에 대한 명명된 인자를 설정해요. 속성에 기본값이 있으면 명시적으로 지정된 값이 그 기본값을 완전히 재정의해요.
  • 중첩 블록 문법은 자신만의 인자 세트를 가진 컨테이너의 관련 하위 객체를 나타내요. 이런 객체가 여러 개 가능할 때 같은 유형의 블록이 여러 개 존재할 수 있어요. 중첩 속성 자체에 기본값이 있으면 각 중첩 블록에 대해 별도로 존중되며, 명시적으로 정의된 인자와 병합돼요.

이 구분은 JSON 문법에서 특히 중요한데, 같은 기본 JSON 구조(리스트와 객체)가 특정 이름이 인자인지 중첩 블록 유형인지에 따라 다르게 해석되기 때문이에요.

그러나 일부 기존 프로바이더 기능은 Terraform v0.11 이하 언어에서 이 두 개념의 혼동에 의존하고 있었어요. 대부분의 경우 중첩 블록 문법을 사용하면서도, 블록이 하나도 없으면 "기존 객체 무시"로 해석되므로, 해당 유형의 모든 기존 객체를 제거한다는 개념을 명시적으로 나타내기 위해 인자 문법을 사용했던 거예요.

이 페이지의 정보는 Terraform v0.12 이전에 이 사용 패턴에 의존했던 특정 특수 인자에만 적용돼요. 각 기능의 문서는 적용되는 특수 사용 패턴의 세부 사항을 이 페이지로 연결해요. 그 외의 모든 경우에는 특정 리소스 유형 문서의 예시가 지시하는 대로 인자 또는 중첩 블록 문법을 사용해요.

고정 객체 컬렉션 값 정의하기 (Defining a Fixed Object Collection Value)

이런 방식으로 동작하는 리소스 유형 인자로 작업할 때, 고정 객체 컬렉션을 정의할 때는 중첩 블록 문법을 사용하는 것이 유효하며 권장돼요:

example {
  foo = "bar"
}
example {
  foo = "baz"
}

위는 example 인자에 할당된 두 요소짜리 객체 리스트를 암시적으로 지정하며, 마치 중첩 블록 유형인 것처럼 취급해요.

example 객체를 명시적으로 0개 호출해야 한다면 빈 목록과 함께 인자 문법을 사용해야 해요:

example = []

이 두 형식은 혼합할 수 없어요. 명시적으로 0개의 example 객체와 명시적인 단일 example 블록을 동시에 선언할 수는 없어요.

이 특수 동작이 적용되지 않는 진짜 중첩 블록의 경우, 인자 문법으로 []를 할당하는 것은 유효하지 않아요. 유형의 객체를 0개 지정하는 일반적인 방법은 중첩 블록을 전혀 쓰지 않는 것이에요.

인자 문법으로 임의 표현식 (Arbitrary Expressions with Argument Syntax)

단순한 경우에는 가독성을 위해 블록 문법을 권장하지만, 이 모드에서 동작하는 이름은 인자로 정의되므로 예상 결과 유형을 가진다면 인자 문법으로 임의의 동적 표현식을 할당할 수 있어요:

example = [
  for name in var.names: {
    foo = name
  }
]
# 권장되지는 않지만 유효한: 상수 객체-리스트 표현식
example = [
  {
    foo = "bar"
  },
  {
    foo = "baz"
  },
]

이런 인자 선언이 기본값을 완전히 재정의한다는 규칙 때문에, 객체-리스트 표현식을 직접 만들 때는 선택적 인자의 일반적인 처리가 적용되지 않아요. 그래서 모든 인자에 명시적 null이더라도 값을 할당해야 해요:

example = [
  {
    # 이 경우 foo를 생략할 수 없어요. 중첩 블록 문법에서는 선택적이더라도요.
    foo = null
  },
]

호출자가 이런 인자에 할당할 객체 리스트를 전달할 수 있게 하는 재사용 모듈을 작성한다면, merge 함수를 사용해서 사용자가 명시적으로 설정하지 않은 속성을 채워 모듈 사용자에게 선택적 인자의 효과를 줄 수 있어요:

example = [
  for ex in var.examples: merge({
    foo = null # (또는 다른 적절한 기본값)
  }, ex)
]

attributes-as-blocks 사용 모드를 사용하는 인자의 경우, 위 방식이 dynamic 블록을 사용하는 것보다 더 나은 패턴이에요. 호출자가 빈 리스트를 제공하면 아무 값도 할당하지 않고 기존 객체를 유지·무시하는 대신 명시적으로 빈 리스트 값을 할당하기 때문이에요. 다만 일반 중첩 블록을 동적으로 생성할 때는 dynamic 블록이 필요해요.

JSON 문법에서 (In JSON syntax)

이 특수 모드를 사용하는 인자는 JSON 문법에서 항상 JSON 표현식 매핑을 사용해 객체 리스트를 생성하도록 지정돼요. 따라서 JSON 문법에서 이 값들의 해석은 위의 "인자 문법으로 임의 표현식"에서 설명한 것과 동등하지만 JSON 문법으로 표현돼요.

JSON 문법의 모호성 때문에 입력만으로는 인자 사용과 중첩 블록 사용을 구분할 방법이 없어서, JSON 문법은 이 인자들에 대한 중첩 블록 처리 모드를 지원할 수 없어요. 아쉽게도 이는 기존 프로바이더 설계 패턴과의 호환성을 위해 실용적으로 내린 네이티브 문법과 JSON 문법 사이의 동등성에 대한 필요한 양보예요. 프로바이더는 향후 주요 릴리스에서 이런 패턴을 단계적으로 없앨 수 있어요.

더 알아보기 (Learn more)