본문 바로가기

study/T101 4기

T101 4기 2주차 두번째

출력 output

출력 값은 주로 테라폼 코드의 프로비저닝 수행 후의 결과 속성 값을 확인하는 용도로 사용된다.

또한 프로그래밍 언어에서 코드 내 요소 간에 제한된 노출을 지원하듯, 테라폼 모듈 간, 워크스페이스 간 데이터 접근 요소로도 활용할 수 있다.

예를 들면 자바의 getter와 비슷한 역할이다. 출력 값의 용도는 다음과 같이 정의할 수 있다.

  • 루트 모듈에서 사용자가 확인하고자 하는 특정 속성 출력
  • 자식 모듈의 특정 값을 정의하고 루트 모듈에서 결과를 참조
  • 서로 다른 루트 모듈의 결과를 원격으로 읽기 위한 접근 요소
output "instance_ip_addr" {
  value = "http://10.1.1"
}

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 실행 시, 이미 정해진 속성은 출력을 예측하지만 아직 생성되지 않은 file_id 값은 값의 경우는 결과 예측을 할 수 없다

# plan 실행 시, 이미 정해진 속성은 출력을 예측하지만
terraform init && terraform plan
...
Changes to Outputs:
  + file_abspath = "/Users/gasida/Downloads/workspaces/3.8/abc.txt"
  + file_id      = (known after 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 함수: 숫저의 절대값 반화, 음수면 양수로 - 링크, abspath 함수

 

 

반복문

list 형태의 값 목록이나 Key-Value 형태의 문자열 집합인 데이터가 있는 경우 동일한 내용에 대해 테라폼 구성 정의를 반복적으로 하지 않고 관리할 수 있다.

 

count : 반복문, 정수 값만큼 리소스나 모듈을 생성 - Blog

  • 리소스 또는 모듈 블록에 count 값이 정수인 인수가 포함된 경우 선언된 정수 값만큼 리소스나 모듈을 생성하게 된다.
  • count에서 생성되는 참조값은 count.index이며, 반복하는 경우 0부터 1씩 증가해 인덱스가 부여된다.
  • 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
}

 

 

실행 후 확인 : 5개의 파일이 생성되어야 하지만 파일명이 동일하여 결과적으로 하나의 파일만 존재 ← count 사용 시 주의

#
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

 

 

파일 수정

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

 

 

 

때때로 여러 리소스나 모듈의 count로 지정되는 수량이 동일해야 하는 상황이 있다. 이 경우 count에 부여되는 정수 값을 외부 변수에 식별되도록 구성할 수 있다.

 

main.tf 파일 수정 : list 형태의 배열을 활용한 반복문 동작 구성

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
  # element function 활용
  filename = "${path.module}/def-${element(var.names, count.index)}.txt"
}

 

확인

#
terraform apply -auto-approve
terraform state list
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

 

 

 

 

[스터디 전용/실습3] 반복문

실습1 : IAM 사용자 3명 생성

 

사용자 1명 생성 코드

provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_iam_user" "example" {
  name = "neo"
}

 

범용 프로그래밍 언어 for 반복문 사용 ⇒ 테라폼은 for 반복문 또는 언어에 내장된 절차 논리가 없어서 아래 구문 동작 불가능

# This is just pseudo code. It won't actually work in Terraform.
for (i = 0; i < 3; i++) {
  resource "aws_iam_user" "example" {
    name = "neo"
  }
}

 

 

테라폼에서 count 를 사용하여 3명 IAM 사용자 생성 → 3명의 IAM 사용자 이름 중복으로 오류 발생 ⇒ for 반복문의 인덱스를 사용하여 각 사용자에게 고유한 이름 지정 가능

resource "aws_iam_user" "example" {
  count = 3
  name  = "neo"
}

 

 

iam.tf

provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_iam_user" "myiam" {
  count = 3
  name  = "myuser.${count.index}"
}

 

iam.tf : 아래 처럼 count.index 를 사용하여 반복문 안에 있는 각각의 반복 ieration 을 가리키는 인덱스를 얻을 수 있음

provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_iam_user" "myiam" {
  count = 3
  name  = "myuser.${count.index}"
}
#
terraform init && 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

# apply
terraform apply -auto-approve

# 확인
terraform state list
aws_iam_user.myiam[0]
aws_iam_user.myiam[1]
aws_iam_user.myiam[2]

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

terraform state show 'aws_iam_user.myiam[0]'
terraform state show 'aws_iam_user.myiam[2]'

aws iam list-users | jq
...

 

 

 

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

touch variables.tf
variable "user_names" {
  description = "Create IAM users with these names"
  type        = list(string)
  default     = ["gasida", "akbun", "hyungwook"]
}

 

  • 테라폼에서 count 와 함께 배열 조회 구문과 length 함수를 사용해서 사용자들 생성 가능
    • 배열 조회 구문 Array lookup syntax
      • ARRAY[<INDEX>]
      • 예를 들어 다음은 var.user_names 의 인덱스 1에서 요소를 찾는 방법
      • var.user_names[1]
    • length (내장) 함수 built-on function
      • 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 사용한 후에는 하나의 리소스가 아니라 리소스의 배열이 됩니다.

 

  • aws_iam_user.myiam 은 이제 IAM 사용자의 배열이므로 표준 구문을 사용하여 해당 리소스인 <PROVIDER>_<TYPE>.<NAME>.<ATTRIBUTE> 에서 속성을 읽은 대신 배열에서 인덱스를 지정해서 IAM 사용자를 명시해야합니다.
  • <PROVIDER>_<TYPE>.<NAME>[INDEX].ATTRIBUTE

 

  • IAM 사용자 한명의 ARN과 사용자 전체의 ARN 을 출력 변수 outputs 으로 제공
    • output.tf : IAM 사용자 전체의 ARN을 원하면 인덱스 대신 스플랫 splat 연산자인 * 를 사용
output "first_arn" {
  value       = aws_iam_user.myiam[0].arn
  description = "The ARN for the first user"
}

output "all_arns" {
  value       = aws_iam_user.myiam[*].arn
  description = "The ARNs for all users"
}
#
terraform apply -auto-approve
terraform state list

terraform output
terraform output first_arn
terraform output -raw first_arn

terraform output all_arns
terraform output -raw all_arns

 

 

 

 

count 제약사항 - 인라인 블록 반복 X, 배열 중간 값을 변경할 때 의도하지 않은 결과 발생

  1. [실습X] 전체 리소스를 반복할 수는 있지만 리소스 내에서 인라인 블록을 반복할 수는 없습니다.
    • 예를 들어 아래 ASG 리소스에 태그 설정 방법에서 생각해보자
resource "aws_autoscaling_group" "example" {
  launch_configuration = aws_launch_configuration.example.name
  vpc_zone_identifier  = data.aws_subnets.default.ids
  target_group_arns    = [aws_lb_target_group.asg.arn]
  health_check_type    = "ELB"

  min_size = var.min_size
  max_size = var.max_size

  tag {
    key                 = "Name"
    value               = var.cluster_name
    propagate_at_launch = true
  }
}
  • 각각의 tag 를 사용하려면 key, value, propagate_at_launch 에 대한 값으로 새 인라인 블록을 만들어야 합니다.
  • 따라서 count 매개변수를 사용해서 이러한 태그를 반복하고 동적인 인라인 tag 블록을 생성하려고 시도할 수도 있지만, 인라인 블록 내에서는 count 사용은 지원하지 않습니다.

 

2. [실습] 배열 중간 값을 변경할 때 의도하지 않은 결과 발생

 

실습을 위해 다시 IAM 사용자 생성

 

variables.tf : IAM 사용자 생성 목록

variable "user_names" {
  description = "Create IAM users with these names"
  type        = list(string)
  default     = ["gasida", "akbun", "hyungwook"]
}

 

variables.tf : 중간에 있는 akbun 을 제거하고 plan & apply

variable "user_names" {
  description = "Create IAM users with these names"
  type        = list(string)
  default     = ["gasida", "hyungwook"]
}

 

# plan : 출력 내용 확인!
terraform plan
...
  ~ update in-place
  - destroy

 

 

  • 배열의 중간에 항목을 제거하면 모든 항목이 1칸씩 앞으로 당겨짐.
  • 테라폼이 인덱스 번호를 리소스 식별자로 보기 때문에 ‘인덱스 1에서는 계정 생성, 인덱스2에서는 계정 삭제한다’라고 해석합니다.
  • 즉 count 사용 시 목록 중간 항목을 제거하면 테라폼은 해당 항목 뒤에 있는 모든 리소스를 삭제한 다음 해당 리소스를 처음부터 다시 만듬.

 

 

 

 

 

[악분님 작성 count 실습] 따라하기 👍🏻👍🏻 - Link Blog Github

악분님이 테라폼 반복문 관련 내용(count, for_each, for expression 등)이해를 위한 좋은 실습을 정리해주셨습니다

 

t101-study/count_vs_foreach at main · sungwook-practice/t101-study

t101 테라폼 스터디 기록. Contribute to sungwook-practice/t101-study development by creating an account on GitHub.

github.com

 

 

코드 가져오기

git clone https://github.com/sungwook-practice/t101-study.git
cd t101-study/count_vs_foreach
cat Readme.md
tree -L 1

 

실습 환경 배포 : AWS VPC 생성

cd template
ls 
cat terraform.tfvars
terraform init && terraform plan && terraform apply -auto-approve
terraform state list

 

**[시나리오 1**] - aws_subnet

  • AWS VPC Subnet 테라폼 코드 작성
  • 요구사항 : subnet cidr를 변수로 입력
  1. main.tf 수정
    • ‘terraform aws subnet’ 검색하여 공식문서 링크의 예제 코드 복붙 - Docs
resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform VPC"
  }
}

resource "aws_subnet" "main" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"

  tags = {
    Name = "Main"
  }
}

 

 

변수 처리 + 실습 편리를 위해 output 추가

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform VPC"
  }
}

resource "aws_subnet" "main" {
  vpc_id     = aws_vpc.main.id
  cidr_block = var.subnet_cidr
}

output "myvpc_id" {
  value = aws_vpc.main.id
}

 

2. variables.tf 수정

variable "vpc_cidr" {
  type = string
}

variable "subnet_cidr" {
  type = string
}

 

 

3. terraform.tfvars 수정

vpc_cidr            = "192.168.0.0/16"
subnet_cidr = "192.168.1.0/24"

 

 

4.배포 실행

# 배포 실행
terraform plan && terraform apply -auto-approve

# 실행 결과 확인
terraform state list
terraform output myvpc_id

# 신규 생성한 VPC 내에 서브넷 확인
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --output table
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone}"
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone}" --output text

 

 

5. 다음 실습을 위해 생성한 리소스 삭제

terraform destroy -auto-approve

 

 

 

[시나리오 2] - index element length

 

length - Functions - Configuration Language | Terraform | HashiCorp Developer

The length function determines the length of a collection or string.

developer.hashicorp.com

  • subnet 1개밖에 못만드나요?…
  • 요구사항 : subnet cidr 변수 값을 여러 개 입력받도록 해주세요 → count 사용!

index element length function 공식 문제 예제 따라해보기

terraform console
-----------------
> index(["a", "b", "c"], "b")
1

> element(["a", "b", "c"], 1)
"b"
> element(["a", "b", "c"], 3)
"a"

> length([])
0
> length(["a", "b"])
2
> length({"a" = "b"})
1
> length("hello")
5

> exit
-----------------

 

 

1. variables.tf 수정

variable "vpc_cidr" {
  type = string
}

variable "subnet_cidr" {
  type = list(string)
}

 

 

2.terraform.tfvars 수정

vpc_cidr            = "192.168.0.0/16"
subnet_cidr = ["192.168.1.0/24", "192.168.2.0/24"]

 

3.main.tf 수정

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform VPC"
  }
}

resource "aws_subnet" "main" {
  count = length(var.subnet_cidr)
  vpc_id     = aws_vpc.main.id
  cidr_block = element(var.subnet_cidr, count.index)
}

output "myvpc_id" {
  value = aws_vpc.main.id
}

 

4.배포 실행

# 신규 터미널 : 모니터링
while true; do aws ec2 describe-subnets --filters --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone}" --output text; echo; time; sleep 1; done

# 배포 실행
terraform plan && terraform apply -auto-approve

# 실행 결과 확인
terraform state list

# 신규 생성한 VPC 내에 서브넷 확인
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --output table
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone}"

# Tip. 코드 중 동작 결과를 눈으로 직접 확인해보기
terraform console
--------------------
> length(var.subnet_cidr)
2

> aws_vpc.main.id
"vpc-0c01f6cdbf3c9ad7a"

> exit
--------------------

 

5. 다음 실습을 위해 생성한 리소스 삭제

terraform destroy -auto-approve

 

 

 

[시나리오 3] - aws_subnet-arg_az (AZ for the subnet)

  • 감사, 그런데~
  • 요구사항 : 서브넷이 배치되는 AZ 설정이 필요. AZ는 변수로 입력해주세요

1.variables.tf 수정

variable "vpc_cidr" {
  type = string
}

variable "subnet_cidr" {
  type = list(string)
}

variable "subnet_az" {
  type = list(string)
}

 

2.terraform.tfvars 수정

vpc_cidr            = "192.168.0.0/16"
subnet_cidr = ["192.168.1.0/24", "192.168.2.0/24"]
subnet_az = ["ap-northeast-2a", "ap-northeast-2c"]

 

 

3.main.tf 수정

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform VPC"
  }
}

resource "aws_subnet" "main" {
  count = length(var.subnet_cidr)
  vpc_id     = aws_vpc.main.id
  cidr_block = element(var.subnet_cidr, count.index)
  availability_zone = element(var.subnet_az, count.index)
}

output "myvpc_id" {
  value = aws_vpc.main.id
}

 

 

4.배포 실행

# 신규 터미널 : 모니터링
while true; do aws ec2 describe-subnets --filters --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone}" --output text; echo; time; sleep 1; done

# 배포 실행
terraform plan && terraform apply -auto-approve

# 실행 결과 확인
terraform state list
echo "aws_subnet.main[0].availability_zone" | terraform console
echo "aws_subnet.main[1].availability_zone" | terraform console
echo "aws_subnet.main[0].tags_all" | terraform console
echo "aws_subnet.main[1].tags_all" | terraform console

# 신규 생성한 VPC 내에 서브넷 확인
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --output table
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone}"
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone,Name:Tags[?Key=='Name']|[0].Value}" --output table

 

 

5.다음 실습을 위해 생성한 리소스 삭제

terraform destroy -auto-approve

 

 

[시나리오 4] - aws_subnet-arg_tags (A map of tags assigned to the resource) map

  • subnet이 여러개인데 구분할 수 없을까요?
  • 요구사항 : subnet tag 설정이 필요해요

 

1.main.tf 1차 수정(vpc tags 복붙) → 실행 후 확인

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform VPC"
  }
}

resource "aws_subnet" "main" {
  count = length(var.subnet_cidr)
  vpc_id     = aws_vpc.main.id
  cidr_block = element(var.subnet_cidr, count.index)
  availability_zone = element(var.subnet_az, count.index)

  tags = {
    Name = "terraform VPC"
  }
}

output "myvpc_id" {
  value = aws_vpc.main.id
}

 

실행 후 확인

# 신규 터미널 : 모니터링
while true; do aws ec2 describe-subnets --filters --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone,Name:Tags[?Key=='Name']|[0].Value}" --output text; echo; time; sleep 1; done

# 배포 실행
terraform plan && terraform apply -auto-approve

# 실행 결과 확인
terraform state list
echo "aws_subnet.main[0].tags_all" | terraform console
echo "aws_subnet.main[1].tags_all" | terraform console
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone,Name:Tags[?Key=='Name']|[0].Value}" --output table

 

 

2.main.tf 2차 수정(count index 활용) → 실행 후 확인

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform VPC"
  }
}

resource "aws_subnet" "main" {
  count = length(var.subnet_cidr)
  vpc_id     = aws_vpc.main.id
  cidr_block = element(var.subnet_cidr, count.index)
  availability_zone = element(var.subnet_az, count.index)

  tags = {
    Name = "terraform VPC-${count.index}"
  }
}

output "myvpc_id" {
  value = aws_vpc.main.id
}

 

 

 

 

[시나리오 5] - map

  • tag에 인덱스번호 말고 고유하게 이름을 설정할 수 없을까요?
  • 요구사항 : subnet tag 를 설정하는 변수 생성

1.variables.tf 수정

variable "vpc_cidr" {
  type = string
}

variable "subnet_cidr" {
  type = list(string)
}

variable "subnet_az" {
  type = list(string)
}

variable "subnet_tag" {
  type = list(map(string))
}

 

 

2.terraform.tfvars 수정 : main 에 tag 내용을 복붙 후 수정

vpc_cidr            = "192.168.0.0/16"
subnet_cidr = ["192.168.1.0/24", "192.168.2.0/24"]
subnet_az = ["ap-northeast-2a", "ap-northeast-2c"]
subnet_tag = [
  {
    Name = "public-subnet"
    Environment = "dev"
  },
  {
    Name = "private-subnet"
    Environment = "dev"
  }
]

 

3.main.tf 수정

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform VPC"
  }
}

resource "aws_subnet" "main" {
  count = length(var.subnet_cidr)
  vpc_id     = aws_vpc.main.id
  cidr_block = element(var.subnet_cidr, count.index)
  availability_zone = element(var.subnet_az, count.index)
  
  tags = element(var.subnet_tag, count.index)
}

output "myvpc_id" {
  value = aws_vpc.main.id
}

 

4.배포 실행

# 신규 터미널 : 모니터링
while true; do aws ec2 describe-subnets --filters --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone}" --output text; echo; time; sleep 1; done

# 배포 실행
terraform plan && terraform apply -auto-approve

# 실행 결과 확인
terraform state list
echo "aws_subnet.main[0].tags_all" | terraform console
echo "aws_subnet.main[1].tags_all" | terraform console

# 신규 생성한 VPC 내에 서브넷 확인
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone,Name:Tags[*]|[*].Value}" --output table
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone,Name:Tags[*]|[*].Value}" --output text

 

 

 

[시나리오 6] (리팩토링) - map list_object

  • subnet 추가할 때마다 변수 전부 일일이 입력해야 되나요? 불편한데… (휴먼에러도 나고 있네요)
  • 요구사항 : subnet 설정 변수를 한 변수로 설정하도록 리팩토링

1.variables.tf 수정

variable "vpc_cidr" {
  type = string
}

variable "subnets" {
  type = list(object({
    cidr = string
    az = string
    tags = map(string)
  }))
}

 

2.terraform.tfvars 수정

vpc_cidr            = "192.168.0.0/16"

subnets = [
  {
    cidr = "192.168.1.0/24",
    az = "ap-northeast-2a",
    tags = {
      Name = "public-subnet"
      Environment = "dev"
    }
  },
  {
    cidr = "192.168.2.0/24",
    az = "ap-northeast-2c",
    tags = {
      Name = "private-subnet"
      Environment = "dev"
    }
  }
]

 

 

3.main.tf 수정 → 실행

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform VPC"
  }
}

resource "aws_subnet" "main" {
  count = length(var.subnet_cidr)
  vpc_id     = aws_vpc.main.id
  cidr_block = var.subnets[count.index].cidr
  availability_zone = var.subnets[count.index].az

  tags = var.subnets[count.index].tags
}

output "myvpc_id" {
  value = aws_vpc.main.id
}

 

 

실행 → 에러 발생

 

 

 

main.tf 수정

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform VPC"
  }
}

resource "aws_subnet" "main" {
  count = length(var.subnets)
  vpc_id     = aws_vpc.main.id
  cidr_block = var.subnets[count.index].cidr
  availability_zone = var.subnets[count.index].az

  tags = var.subnets[count.index].tags
}

output "myvpc_id" {
  value = aws_vpc.main.id
}

 

배포 실행

# 신규 터미널 : 모니터링
while true; do aws ec2 describe-subnets --filters --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone}" --output text; echo; time; sleep 1; done

# 배포 실행
terraform plan && terraform apply -auto-approve

# 실행 결과 확인
terraform state list
echo "aws_subnet.main[0].tags_all" | terraform console
echo "aws_subnet.main[1].tags_all" | terraform console

# 신규 생성한 VPC 내에 서브넷 확인
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone,Name:Tags[*]|[*].Value}" --output table
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone,Name:Tags[*]|[*].Value}" --output text

 

terraform destroy -auto-approve

 

 

 

[시나리오 7] 장애 상황 재현 - Docs

  • 테라폼 변수에서 안쓰는 subnet을 삭제한 후, 테라폼을 실행하니 EC2 instance가 교체되었어요. EC2 내에 작업한 내용이 다 사라졌는데…
  • 요구사항 : 오류 확인 후 코드 수정

 

1.실습 환경 배포

# 코드 파일 확인
cd ..
cd step5_count_invalid_example
ls

 

실습 편리를 위해 main.tf 하단에 output 추가

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform VPC"
  }
}

resource "aws_subnet" "main" {
  count = length(var.subnets)

  vpc_id     = aws_vpc.main.id
  cidr_block = var.subnets[count.index].cidr
  availability_zone = var.subnets[count.index].az

  tags = var.subnets[count.index].tags
}

resource "aws_instance" "server" {
  ami           = "ami-0e8bd0820b6e1360b"
  instance_type = "t4g.nano"
  subnet_id = aws_subnet.main[1].id
  # index 접근 방법 오류 해결 코드
  # subnet_id = index(aws_subnet.main.*.cidr_block, "192.168.2.0/24")
  tags = {
    Name = "Terraform demo"
  }
}

output "myvpc_id" {
  value = aws_vpc.main.id
}

 

배포 실행

# 신규 터미널 : 모니터링
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PrivateIP:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --output text
while true; do aws ec2 describe-instances --query "Reservations[*].Instances[*].{PrivateIP:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --output text; echo; aws ec2 describe-subnets --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone,Name:Tags[*]|[*].Value}" --output text; echo; time; sleep 1; done

# 배포 실행
terraform init && terraform plan && terraform apply -auto-approve

# 실행 결과 확인
terraform state list
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PrivateIP:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --output table
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$(terraform output -raw myvpc_id)" --query "Subnets[*].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone,Name:Tags[*]|[*].Value}" --output table

 

 

2.[장애 재현] terraform.tfvars 수정 : 아래 부분 주석 처리

vpc_cidr            = "192.168.0.0/16"

subnets = [
  # (유투브 7번째 시나리오) terrafprm apply 이 후, 첫 번째 요소를 주석하세요
  # {
  #   cidr = "192.168.1.0/24",
  #   az = "ap-northeast-2a",
  #   tags = {
  #     Name = "public-subnet"
  #     Environment = "dev"
  #   }
  # },
  # (유투브 8번째 시나리오) terrafprm apply 이 후, 주석을 해제하고 terraform apply해보세요
  # {
  #   cidr = "192.168.5.0/24",
  #   az = "ap-northeast-2a",
  #   tags = {
  #     Name = "public-subnet"
  #     Environment = "dev"
  #   }
  # },
  {
    cidr = "192.168.2.0/24",
    az = "ap-northeast-2a",
    tags = {
      Name = "private-subnet"
      Environment = "dev"
    }
  },
...

 

실행 후 인스턴스 삭제..

 

 

4.원인 : 반복문index로 접근했기 때문에 - Docs

 

The count Meta-Argument - Configuration Language | Terraform | HashiCorp Developer

Count helps you efficiently manage nearly identical infrastructure resources without writing a separate block for each one.

developer.hashicorp.com

 

(아래 그림은 출처 - 악분)

리소스 삭제

terraform destroy -auto-approve

 

 

 

'study > T101 4기' 카테고리의 다른 글

T101 4기 3주차 두번째  (0) 2024.06.29
T101 4기 3주차 첫번째  (0) 2024.06.29
T101 4기 2주차 첫번째  (0) 2024.06.22
T101 4기 1주차 세번째  (0) 2024.06.15
T101 4기 1주차 두번째  (0) 2024.06.15