[Terraform] 테라폼 반복문 본문
Terraform 반복문
list 형태의 값 목록이나 Key-Value 형태의 문자열 집합인 데이터가 있는 경우 반복문을 통해 관리할 수 있다. 또한, 단순한 자료구조뿐만 아니라 리소스 내에 생성된 블록에 대한 것도 반복문을 통해 코드의 중복 없이 동적으로 생성이 가능하다.
count
리소스 또는 모듈 블록에 count
값이 정수인 인수가 포함된 경우 선언된 정수 값만큼 리소스나 모듈을 생성하게 된다.
count
에서 생성되는 참조값은 count.index
이며, 반복하는 경우 0부터 1씩 증가해 인덱스가 부여된다. main.tf
를 아래와 같이 작성해보자.
resource "local_file" "abc" {
count = 5
content = "abc"
filename = "${path.module}/abc.txt"
}
위 코드를 실행시켰을 때 목표로 하는 결과는 다섯 개의 파일이 생성되는 것이지만, 파일명에는 변화가 없기 때문에 하나의 파일만 존재하게 된다. 본래의 의도대로 실행되도록 하려면 다음과 같이 count.index
값을 추가하면 된다.
resource "local_file" "abc" {
count = 5
content = "abc"
filename = "${path.module}/abc${count.index}.txt"
}
count
를 프로그래밍 언어의 반복문 인덱스처럼 활용하는 방법은 다음과 같다.
variable "names" {
type = list(string)
default = ["a", "b", "c"]
}
resource "local_file" "abc" {
count = length(var.names)
content = "abc"
filename = "${path.module}/abc-${var.names[count.index]}.txt"
}
resource "local_file" "def" {
count = length(var.names)
content = local_file.abc[count.index].content
filename = "${path.module}/def-${element(var.names, count.index)}.txt"
}
local_file.abc
와 local_file.def
는 var.names
에 선언되는 값에 영향을 받아 동일한 개수만큼 생성하게 된다.
count
로 생성되는 리소스의 경우 "<리소스 타입>.<이름>[<인덱스 번호>]
, 모듈의 경우 module.<모듈 이름>[<인덱스 번호>]
로 해당 리소스의 값을 참조한다.
for_each
리소스 또는 모듈 블록에서 for_each
에 입력된 데이터 형태가 map
또는 set
이면, 선언된 key 값 개수만큼 리소스를 생성하게 된다.
resource "local_file" "abc" {
for_each {
a = "content a"
b = "content b"
}
content = each.value
filename = "${path.module}/${each.key}.txt"
}
생성되는 리소스의 경우 <리소스 타입>.<이름>[<key>]
, 모듈의 경우 module.<모듈 이름>[<key>]
로 해당 리소스의 값을 참조한다. 이 참조 방식을 통해 리소스 간 종속성을 정의하기도 하고 변수로 다른 리소스에서 사용하거나 출력을 위한 결과 값으로 사용한다.
for_each
를 활용한 반복 참조 예시는 다음과 같다.
variable "names" {
default = {
a = "content a"
b = "content b"
c = "content c"
}
}
resource "local_file" "abc" {
for_each = var.names
content = each.value
filename = "${path.module}/abc-${each.key}.txt"
}
resource "local_file" "def" {
for_each = local_file.abc
content = each.value.content
filename = "${path.module}/def-${each.key}.txt"
}
for
for
문은 복합 형식 값의 형태를 변환하는데 사용된다. 예를 들어 list
값의 포맷을 변경하거나 특정 접두사를 추가할 수도 있고, output
에 원하는 형태로 반복적인 결과를 표현할 수 있다.
list
의 경우 값 또는 인덱스와 값을 반환한다.map
의 경우 키 또는 키와 값을 반환한다.set
의 경우 키 값을 반환한다.
variable "names" {
default = ["a", "b", "c"]
}
resource "local_file" "abc" {
content = jsonencode([for s in var.names: upper(s)]) # result: ["A", "B", "C"]
filename = "${path.module}/abc.txt"
}
for
문을 사용할 때 대상이 되는 타입에 따라 다음과 같은 규칙이 적용된다.
list
타입의 경우 반환 받는 값이 하나로 되어 있으면 값을, 두 개인 경우 앞의 인수가 인덱스를 반환하고 두 번째 인수가 값을 반환한다.map
타입의 경우 반환 받는 값이 하나로 되어 있으면 키를, 두 개인 경우 앞의 인수가 키를 반환하고 두 번째 인수가 값을 반환한다.for
문의 결과값은for
문을 감싸고 있는 괄호의 종류에 따라 다르게 결정된다.[ ]
형태로 감싸고 있을 경우tuple
로 반환된다.{ }
형태로 감싸고 있을 경우object
형태로 반환된다.object
형태의 경우 키와 값을 => 기호로 구분한다.
list
타입에 적용할 수 있는 규칙을 간단한 예제를 통해서 확인해보자.
variable "names" {
type = list(string)
default = ["a", "b"]
}
output "tuple_upper_value" {
value = [for v in var.names: upper(v)]
}
output "tuple_index_value" {
value = [for i, v in var.names: "${i}: ${v}"]
}
output "object_upper_value" {
value = {for v in var.names: v => upper(v)}
}
output "tuple_with_if" {
value = [for v in var.names: upper(v) if v != "a"]
}
위의 HCL을 terraform apply
명령어를 통해 실행할 경우 아래와 같은 output
결과가 나오게 된다. 작성된 순서와 무관하게 결과가 표시되기 때문에 output
의 이름을 잘 확인해보자.
이번에는 좀 더 복잡한 예제를 통해 확인해보자.
variable "members" {
type = map(object({
role = string
group = string
}))
default = {
"memberA" = {
role = "member",
group = "dev"
}
"adminB" = {
role = "admin",
group = "dev"
}
"devopsC" = {
role = "member",
group = "devops"
}
}
}
output "get_all_group" {
value = [for k, v in var.members: "${k} is a ${v.group}"]
}
output "get_only_admin" {
value = {
for name, user in var.members: name => user.role
if user.role == "admin"
}
}
output "C" {
value = {
for name, user in var.members: user.role => name...
}
}
위의 HCL을 terraform apply
명령어를 통해 실행할 경우 아래와 같은 output
결과가 나오게 된다. 작성된 순서와 무관하게 결과가 표시되기 때문에 output
의 이름을 잘 확인해보자.
특히 주목해서 살펴봐야 할 output
은 get_member_group_by_role
인데, name
뒤에 ...
이 붙은 것을 확인할 수 있다. 이는 object
타입으로 결과를 반환하는 경우 키 값은 고유해야 하기 때문에 값 뒤에 그룹화 모드 심볼인 ...
를 붙여 키의 중복을 방지하는 것이다.
...
는 SQL의 group by
문과 동일한 역할을 한다.
dynamic
테라폼을 통해 리소스를 구성하다 보면 count
나 for_each
를 통해 리소스 전체를 여러 개 생성하는 것 이외에도 리소스 내에 선언되는 구성 블록들을 여러 개 작성해야 할 때가 있다.
동일한 요소가 리소스 선언 내부에서 블록 형태로 여러 개 정의되는 상황에 dynamic
을 통해 동적으로 생성할 수 있다.
dynamic
블록을 작성하려면, 기존 블록의 속성 이름을 dynamic
블록의 이름으로 선언하고 기존 블록 속성에 정의되는 내용을 content
블록에 작성한다. 반복 선언에 사용되는 반복문 구문은 for_each
를 사용한다.
기존 for_each
문 사용시 각 속성에 key
, value
가 할당되었다면, dynamic
에서는 dynamic
에 지정한 이름에 대한 속성이 할당된다.
간단한 예시를 통해 dynamic
의 사용법에 대해 알아보자.
data "archive_file" "dotfiles" {
type = "zip"
output_path = "${path.module}/dotfile.zip"
source {
content = "hello a"
filename = "${path.module}/a.txt"
}
source {
content = "hello b"
filename = "${path.module}/b.txt"
}
source {
content = "hello c"
filename = "${path.module}/c.txt"
}
}
위의 HCL
을 terraform apply
를 통해 실행시키게 되면 경로에 dotfiles.zip
이라는 압축 파일이 생성되고 해당 압축 파일을 풀어보면 리소스 내에 정의된 source
블록에 맞게 텍스트 파일이 생성된 것을 확인할 수 있다
참고로 처음 archive
프로바이더를 사용하는 경우에는 잊지 말고 terraform init
을 실행하자.
이제 data
리소스 내에 반복적으로 정의되어 있는 source
블록을 dynamic
을 활용하여 동적으로 설정하는 코드로 변경해보자.
우선 각 리소스 블록 내에서 매번 변동되는 값인 content
와 filename
부분을 추출하여 variable
리소스로 만든다.
variable "names" {
default = {
a = "hello a"
b = "hello b"
c = "hello c"
}
}
data "archive_file" "dotfiles" {
type = "zip"
output_path = "${path.module}/dotfile.zip"
source {
content = [ ]
filename = "${path.module}/[ ]"
}
}
이제 반복적으로 생성되는 source
리소스에 dynamic
을 붙이고 for_each
로 variable
리소스에서 반복 구문을 추출한다.
variable "names" {
default = {
a = "hello a"
b = "hello b"
c = "hello c"
}
}
data "archive_file" "dotfiles" {
type = "zip"
output_path = "${path.module}/dotfile.zip"
dynamic "source" {
for_each = var.names
content = {
content = source.value
filename = "${path.module}/${source.key}.txt"
}
}
}
해당 코드를 실행시켜보면 이전에 dynamic
없이 작성했던 코드와 동일하게 동작하는 것을 확인할 수 있다. 이러한 반복문을 적절히 사용하는 것으로 테라폼 사용 시 중복되는 코드를 줄여 유지 보수 및 확장에 용이한 코드 작성이 가능해진다.
'DevOps' 카테고리의 다른 글
[Terraform] 테라폼 기초 (3) (1) | 2024.08.28 |
---|---|
[Terraform] 테라폼 기초 (2) (0) | 2024.08.19 |
[Helm] Helm Quick Start (0) | 2024.08.10 |
[Terraform] 테라폼 기초 (1) (0) | 2024.08.03 |
[Jenkins] CI/CD 파이프라인 구축 중 .gitIgnore 처리된 Config 파일 관리 (0) | 2024.07.19 |