본문 바로가기
Terraform/Terraform 101 Study

2주차 3편 테라폼 기초 - 기본 사용 2/3

by 개발자 영만 2024. 6. 19.

3.7 local 지역 값

  • 로컬 변수(local variable)는 코드 내에서 선언되고, 코드 내에서만 참조 가능한 값을 의미합니다.
  • 로컬 변수는 선언된 모듈 내에서만 접근할 수 있으며, 외부에서는 접근이 불가능합니다.
  • 실행 시에 입력값을 받을 수 없습니다. 오직 코드 내에서 선언되고 가공된 값만을 사용합니다.
  • 로컬 변수는 테라폼 코드 구현 시 자주 사용하는 값이나 표현식을 반복적으로 사용하기 쉽게 합니다.
  • 여러 곳에서 빈번하게 사용될 경우 실제 값에 대한 추적이 어려워질 수 있습니다. 이는 코드의 유지 관리 측면에서 부담이 될 수 있습니다.

local 선언

  • 선언 블록
    • 로컬 변수는 locals 블록으로 시작하여 선언됩니다.
    • 선언되는 인수에 표현되는 값은 상수뿐만 아니라 리소스의 속성, 변수의 값들도 조합하여 정의할 수 있습니다.
  • 다양한 선언 위치
    • 동일한 tf 파일 내에서 여러 번 선언할 수 있습니다.
    • 여러 파일에 걸쳐서도 선언이 가능합니다.
  • locals에 선언한 로컬 변수 이름은 전체 루트 모듈 내에서 유일해야 합니다. 중복된 이름을 사용할 수 없습니다.
  • 정의되는 속성 값은 지정된 값의 형태에 따라 다양한 유형으로 정의될 수 있습니다. 예를 들어, 문자열, 숫자, 리스트, 맵 등 다양한 유형을 사용할 수 있습니다.\
  • local 값 선언 방식의 예
variable "prefix" {
  default = "hello"
}

locals {
  name    = "terraform"
  content = "${var.prefix} ${local.name}"
  my_info = {
    age    = 20
    region = "KR"
  }
  my_nums = [1, 2, 3, 4, 5]
}

locals {
  content = "content2" # 중복 선언되었으므로 오류가 발생한다.
}

  • main.tf 파일 수정
variable "prefix" {
  default = "hello"
}

locals {
  name    = "terraform"
  content = "${var.prefix} ${local.name}"
  my_info = {
    age    = 20
    region = "KR"
  }
  my_nums = [1, 2, 3, 4, 5]
}
  • 실행 및 확인
terraform init
terraform apply -auto-approve
terraform state list

local 참조

  • 선언된 로컬 값은 local.<이름> 형태로 참조할 수 있습니다.
  • 테라폼 구성 파일을 여러 개 생성해 작업하는 경우, 서로 다른 파일에 선언된 로컬 변수도 참조할 수 있습니다. 로컬 변수는 루트 모듈 전체에서 유일한 이름을 가지므로, 다른 파일에서도 해당 이름으로 참조 가능합니다.
  • main.tf 파일 수정
variable "prefix" {
  default = "hello"
}

locals {
  name    = "terraform"
}

resource "local_file" "abc" {
  content  = local.content
  filename = "${path.module}/abc.txt"
}
  • sub.tf 파일 생성
touch sub.tf
locals {
  content = "${var.prefix} ${local.name}"
}
  • 테라폼에서는 서로 다른 구성 파일에서 선언된 로컬 변수를 참조할 수 있습니다.
  • 실행
# .tf 파일 목록 확인
ls *.tf

# 테라폼 초기화 및 업그레이드
terraform init -upgrade

# 테라폼 적용
terraform apply -auto-approve

# 테라폼 상태 목록 확인
terraform state list

# 특정 리소스의 상태 확인
terraform state show local_file.abc

# 테라폼 콘솔에서 로컬 변수 값 확인
echo "local.content" | terraform console

# graph 확인 > graph.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph > graph.dot

# abc.txt 파일 내용 출력
cat abc.txt ; echo

  • 테라폼에서는 여러 구성 파일 간에 로컬 변수를 참조할 수 있지만, 로컬 변수가 파편화되면 유지 관리가 어려워질 수 있습니다.
  • 따라서 로컬 변수를 사용할 때는 명확한 네이밍과 주석을 통해 가독성을 높이고, 파일 구조를 체계적으로 관리하는 것이 중요합니다.
  • terraform.tfvars에 정의된 변수 우선순위 실습
# terraform.tfvars 파일 생성
echo 'prefix="t101-study"' > terraform.tfvars

# 파일 내용 확인
cat terraform.tfvars

# 테라폼 적용
terraform apply -auto-approve

# 결과 파일 확인
cat abc.txt ; echo

 

[실습2] AWS IAM User 생성

AWS IAM User 생성

  • 폴더 및 파일 생성
mkdir local-test && cd local-test
touch iamuser.tf
  • iamuser.tf 파일 생성
provider "aws" {
  region = "ap-northeast-2"
}

locals {
  name = "mytest"
  team = {
    group = "dev"
  }
}

resource "aws_iam_user" "myiamuser1" {
  name = "${local.name}1"
  tags = local.team
}

resource "aws_iam_user" "myiamuser2" {
  name = "${local.name}2"
  tags = local.team
}
  • 실행 후 AWS 관리 콘솔에서 해당 사용자를 확인
# 테라폼 초기화 및 적용
terraform init && terraform apply -auto-approve

# 테라폼 상태 확인
terraform state list
terraform state show aws_iam_user.myiamuser1
terraform state show aws_iam_user.myiamuser2

# graph 확인 > graph.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph > graph.dot

# AWS IAM 사용자 리스트 확인
aws iam list-users | jq

# 리소스 삭제
terraform destroy -auto-approve -target=aws_iam_user.myiamuser1
terraform state list
terraform destroy -auto-approve
terraform state list

 

3.8 출력 output

  • 출력 값은 주로 테라폼 코드의 프로비저닝 수행 후 결과 속성 값을 확인하는 용도로 사용됩니다.
  • 또한 프로그래밍 언어에서 코드 내 요소 간에 제한된 노출을 지원하듯, 테라폼 모듈 간 및 워크스페이스 간 데이터 접근 요소로도 활용될 수 있습니다.
  • 예를 들면 자바의 getter와 비슷한 역할을 합니다.
    • 루트 모듈에서 사용자가 확인하고자 하는 특정 속성 출력
    • 자식 모듈의 특정 값을 정의하고 루트 모듈에서 결과를 참조
    • 서로 다른 루트 모듈의 결과를 원격으로 읽기 위한 접근 요소

output 선언

  • 모듈 내에서 생성되는 속성 값들은 output 블록을 사용하여 정의됩니다.
output "instance_ip_addr" {
  value = "http://${aws_instance.server.private_ip}"
}
  • value 속성은 출력 값의 실제 값을 정의합니다. 위 예시에서는 aws_instance.server.private_ip를 사용하여 해당 인스턴스의 프라이빗 IP 주소를 HTTP URL 형태로 출력합니다.
  • 출력 값은 리소스의 프로비저닝이 완료된 후에만 최종적으로 결정됩니다. 따라서 terraform apply 실행 후에만 출력 값의 실제 값을 확인할 수 있습니다. terraform plan 단계에서는 예상 결과만 표시되며, 실제 값을 출력하지 않습니다.
  • 출력 블록에서는 다양한 메타인수를 사용할 수 있습니다:
    • description: 출력 값에 대한 설명을 제공합니다.
    • sensitive: 출력 값이 민감할 경우 사용하여 테라폼의 출력 결과에서 값의 노출을 제한할 수 있습니다.
    • depends_on: 출력 값이 특정 구성에 종속적인 경우, 생성 순서를 제어하기 위해 사용됩니다.
    • precondition: 출력 값이 전달되기 전에 특정 조건을 검증하는 데 사용됩니다.

output 활용 & abspath 함수

  • main.tf 파일 수정
    • abspath : 파일 시스템 경로를 포함하는 문자열을 가져와 절대 경로로 변환하는 함수
resource "local_file" "abc" {
  content  = "abc123"
  filename = "${path.module}/abc.txt"
}

output "file_id" {
  value = local_file.abc.id
}

output "file_abspath" {
  value = abspath(local_file.abc.filename)
}
  • 실행
# plan 실행
terraform init && terraform plan
...
Changes to Outputs:
  + file_abspath = "/Users/gasida/Downloads/workspaces/3.8/abc.txt"
  + file_id      = (known after apply)

  • file_id는 local_file.abc.id가 생성된 후에 확정되기 때문에, terraform plan 단계에서는 알 수 없습니다.
  • terraform apply -auto-approve 명령을 실행하면 리소스가 생성되고, 출력 값들이 최종적으로 확정됩니다.
# apply 실행
terraform apply -auto-approve
...
Outputs:
  file_abspath = "/Users/gasida/Downloads/workspaces/3.8/abc.txt"
  file_id      = "6367c48dd193d56ea7b0baad25b19455e529f5ee"

# graph 확인 > graph.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph > graph.dot

# 파일 경로 비교 확인
terraform state list
terraform state show local_file.abc
echo "local_file.abc" | terraform console
echo "local_file.abc.filename" | terraform console
terraform output -raw file_abspath ; echo

  • abs : 주어진 숫자의 절대값을 반환하는 함수. 이 함수는 양수 값을 반환하며, 입력 값이 음수인 경우에는 해당 값을 양수로 변환합니다.
terraform state list

terraform output

terraform console
> abspath(local_file.abc.filename)
"/Users/gasida/Downloads/workspaces/3.8/abc.txt"

> abspath(path.root)
"/Users/gasida/Downloads/workspaces/3.8"

> abs(23)
23

> abs(0)
0

> abs(-12.4)
12.4

> exit

 

3.9 반복문

  • 반복문을 사용하여 리스트 형태의 값 목록이나 Key-Value 형태의 문자열 집합을 기반으로 동일한 내용을 반복적으로 처리할 수 있습니다. 이는 특히 테라폼(Terraform)과 같은 인프라스트럭처 코드 관리 도구에서 매우 유용하게 사용될 수 있습니다.

count

  • count 속성을 사용하여 정의된 횟수만큼 리소스나 모듈을 생성합니다.
  • 각 반복에는 count.index를 사용하여 인덱스에 접근할 수 있습니다.
  • main.tf 파일
resource "local_file" "abc" {
  count    = 5
  content  = "abc"
  filename = "${path.module}/abc.txt"
}

output "filecontent" {
  value = local_file.abc.*.content
}

output "fileid" {
  value = local_file.abc.*.id
}

output "filename" {
  value = local_file.abc.*.filename
}
  • 실행
# 초기화 및 적용
terraform init && terraform apply -auto-approve

# 상태 목록 조회
terraform state list

# 콘솔에서 리소스 참조
echo "local_file.abc" | terraform console
echo "local_file.abc[0]" | terraform console
echo "local_file.abc[4]" | terraform console

# 특정 리소스 상세 정보 조회
terraform state show 'local_file.abc[0]'
terraform state show 'local_file.abc[4]'

# 생성된 파일 목록 확인
ls *.txt

# 출력값 확인
terraform output
terraform output filename
terraform output fileid
terraform output filecontent

  • local_file 리소스를 5개 생성하는 경우를 보여줍니다. 하지만 파일 이름이 동일하여 하나의 파일만 생성되는 문제가 있습니다.
  • 이를 해결하기 위해 파일 이름에 count.index 값을 추가하여 각 파일이 고유하게 생성되도록 수정합니다.
  • main.tf 파일 수정
resource "local_file" "abc" {
  count    = 5
  content  = "This is filename abc${count.index}.txt"
  filename = "${path.module}/abc${count.index}.txt"
}

output "fileid" {
  value = local_file.abc.*.id
}

output "filename" {
  value = local_file.abc.*.filename
}

output "filecontent" {
  value = local_file.abc.*.content
}

 

  • 실행 후 확인
# 적용 및 상태 목록 조회
terraform apply -auto-approve
terraform state list

# 생성된 파일 목록 확인
ls *.txt

# 콘솔에서 리소스 참조
echo "local_file.abc" | terraform console
echo "local_file.abc[0].content" | terraform console
echo "local_file.abc[4].content" | terraform console

# 특정 리소스 상세 정보 조회
terraform state show 'local_file.abc[0]'
terraform state show 'local_file.abc[4]'

# 출력값 확인
terraform output
terraform output filename
terraform output fileid
terraform output filecontent

# graph 확인 > graph.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph > graph.dot

  • main.tf 파일 수정
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"
}
  • 실행 후 확인
# 적용 및 상태 정보 조회
terraform apply -auto-approve
terraform state list

# 생성된 모든 .txt 파일확인
ls *.txt

# 파일 간의 차이 비교
diff abc-a.txt abc-b.txt
diff abc-a.txt def-c.txt

# 파일 내용 출력
cat abc-a.txt abc-b.txt abc-c.txt
cat def-a.txt def-b.txt def-c.txt

# 콘솔에서 리소스와 관련된 값 조회
echo "local_file.abc" | terraform console
echo "local_file.abc[0].content" | terraform console
echo "local_file.abc[2].content" | terraform console

# 특정 리소스 상세 정보 조회
terraform state show 'local_file.abc[0]'
terraform state show 'local_file.abc[2]'

# graph 확인 > graph.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph > graph.dot

  • local_file 리소스인 abc와 def는 각각 names 리스트의 길이만큼 생성됩니다.
  • abc 리소스의 파일명은 abc-[name].txt로 설정되며, def 리소스는 abc 리소스의 content를 참조하여 설정됩니다.
  • count로 생성된 리소스의 경우, 테라폼 상태 파일에서는 <리소스 타입>.<이름>[<인덱스 번호>] 형식으로 각 리소스를 참조할 수 있습니다.
  • 모듈의 경우에는 module.<모듈 이름>[<인덱스 번호>] 형식으로 해당 모듈을 참조할 수 있습니다.
  • 테라폼에서는 모듈 내에서 count를 적용하는 것에는 제한이 있습니다. 특히 provider 블록과 같이 모듈의 초기 설정 부분에서는 count를 사용할 수 없습니다.
  • 외부 변수가 리스트 형태일 때 중간에 값이 삭제되면, 그에 따라 인덱스가 조정됩니다. 이는 의도하지 않은 리소스의 삭제 및 재생성을 유발할 수 있습니다.

 

[실습3] 반복문

IAM 사용자 3명 생성

  • 신규 폴더 생성 후 작업
mkdir iam-count-for && cd iam-count-for
touch iam.tf
  • iam.tf 파일 수정
provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_iam_user" "myiam" {
  count = 3
  name  = "myuser.${count.index}"
}
# 배포
terraform init && terraform plan && terraform apply -auto-approve

# 상태에 있는 모든 리소스의 목록을 출력
terraform state list

# 특정 리소스의 상세 정보를 출력
terraform state show 'aws_iam_user.myiam[0]'
terraform state show 'aws_iam_user.myiam[2]'

echo "aws_iam_user.myiam" | terraform console
echo "aws_iam_user.myiam[0]" | terraform console

# IAM 사용자 확인
aws iam list-users | jq

  • 다음 실습을 위해 iam user 삭제
terraform destroy -auto-approve
aws iam list-users | jq

count 입력 변수를 통해 IAM 사용자 생성

  • variables.tf 파일 수정
variable "user_names" {
  description = "Create IAM users with these names"
  type        = list(string)
  default     = ["gasida", "akbun", "hyungwook"]
}
  • count와 함께 배열 조회 구문 및 length 함수를 사용하여 여러 사용자를 자동으로 생성 가능합니다.
  • 배열 조회 구문: ARRAY[<INDEX>]
    • 예: var.user_names[1] (var.user_names 배열의 인덱스 1 요소를 조회)
  • length (내장) 함수: length(<ARRAY>)
    • 주어진 ARRAY 의 항목 수를 반환하는 함수. 문자열 및 맵을 대상으로도 동작
  • iam.tf 파일 수정
provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_iam_user" "myiam" {
  count = length(var.user_names)
  name  = var.user_names[count.index]
}
  • init & plan - count를 사용하면 리소스가 배열로 처리됩니다. terraform plan 명령어를 통해 이를 확인할 수 있습니다.
terraform plan
...
  # aws_iam_user.myiam[0] will be created
  # aws_iam_user.myiam[1] will be created
  # aws_iam_user.myiam[2] will be created

  • aws_iam_user.myiam 은 IAM 사용자의 배열이므로 해당 리소스의 속성에 접근하려면 인덱스를 사용해서 IAM 사용자를 지정해야 합니다.
  • <PROVIDER>_<TYPE>.<NAME>[INDEX].ATTRIBUTE
  • output.tf 파일 수정 - IAM 사용자 한 명과 스플랫 연산자 * 를 사용해 IAM 사용자 전체의 ARN을 출력
# 배포
terraform apply -auto-approve

# 상태에 있는 모든 리소스의 목록을 출력
terraform state list

# 모든 출력 변수 확인
terraform output

# IAM 사용자 한 명의 ARN을 확인
terraform output first_arn
terraform output -raw first_arn

# IAM 사용자 전체의 ARN을 확인
terraform output all_arns
terraform output -raw all_arns

count 제약사항

제약 1

  • 전체 리소스를 반복하는 것은 가능하지만, 리소스 내의 인라인 블록을 반복하는 것은 지원되지 않습니다.
  • 대신, 동적 블록(dynamic block)을 사용하여 이러한 문제를 해결할 수 있습니다. 동적 블록은 리소스 내에서 반복할 수 있도록 해주며, 이를 통해 유연하게 여러 구성을 적용할 수 있습니다.

제약 2

  • count 속성을 사용하여 리소스를 생성할 때, 배열의 중간 값을 변경하거나 배열의 순서를 변경하면 의도하지 않은 결과가 발생할 수 있습니다.
  • variables.tf 파일 수정 - IAM 사용자 생성 목록
variable "user_names" {
  description = "Create IAM users with these names"
  type        = list(string)
  default     = ["gasida", "akbun", "hyungwook"]
}
  • IAM 사용자 생성
terraform apply -auto-approve
...
aws_iam_user.myiam[2]: Refreshing state... [id=hyungwook]
aws_iam_user.myiam[1]: Refreshing state... [id=akbun]
aws_iam_user.myiam[0]: Refreshing state... [id=gasida]
...

  • variables.tf 파일 수정 - akbun 을 제거하고 plan & apply
variable "user_names" {
  description = "Create IAM users with these names"
  type        = list(string)
  default     = ["gasida", "hyungwook"]
}
# plan : 출력 내용 확인!
terraform plan

  • count 속성을 사용하여 리소스를 생성할 때, 배열의 중간 항목을 제거하면 발생하는 문제는 Terraform이 리소스의 식별을 인덱스로 하기 때문입니다.
  • 이로 인해 배열의 중간 값을 제거하면 그 뒤의 모든 리소스가 삭제되고 다시 생성됩니다.
  • 이를 피하기 위해 for_each를 사용할 수 있습니다. for_each는 리소스를 배열의 요소를 키로 사용하는 맵으로 관리하여 배열의 순서나 중간 값이 변경되어도 리소스가 재생성되지 않도록 합니다.
terraform apply -auto-approve

  • 다음 실습을 위해 iam user 삭제
terraform destroy -auto-approve
aws iam list-users | jq