공부하면서/Terraform

[T1012] 2주차 - 테라폼 기본 사용 2/3 (데이터 소스 + 실습)

omelette master 2023. 7. 15. 19:53
해당 내용은 T1012 스터디에 나온 내용과 '테라폼으로 시작하는 IaC' 책을 기준으로 정리 했습니다

데이터 소스

데이터 소스 구성

데이터 소스는 테라폼으로 정의되지 않은 외부 리소스 또는 저장된 정보를 테라폼 내에 참조할때 사용
  • 데이터 소스 블록은 data로 시작 하여 데이터 소스 유형을 정의
  • 데이터 소스 유형을 정의한 뒤에는 고유한 이름을 붙인다
    (1주차에서 배운 리소스 블록처럼 동일 유형에 대해 이름은 중복될수 없다)
# main.tf 파일에 다음과 같이 생성
data "local_file" "abc" {
  filename = "${path.module}/abc.txt"
}


# 확인을 위한 abc.txt 생성

echo "t101 study - 2week" > abc.txt
terraform init && terraform plan && terraform apply -auto-approve

# 테라폼 콘솔 : 데이터 소스 참조 확인
terraform console
> 
data.local_file.abc
...
data.local_file.abc.filename
data.local_file.abc.content
data.local_file.abc.id
exit

데이터 소스에서 사용가능한 메타인수

데이터 소스에서만 사용가능한 것이 아니라, "~ 에서도 사용할수 있는" 으로 인지를 해야한다
  • depends_on (1주차에서 진행) : 종속성 선언
  • lifecycle (1주차에서 진행) : 생명주기 관리
  • count : 선언된 개수에 따라 여러 리소스를 생성
  • for_each : map 또는 set 타입의 데이터 배열의 값을 기준으로 여러 리소스 생성

데이터 소스 속성 참조 방법

다른 블록에서 data의 값을 가져오고 싶을때 사용
# Terraform Code
data "<리소스 유형>" "<이름>" {
  <인수> = <값>
}

# 데이터 소스 참조
data.<리소스 유형>.<이름>.<속성>
  • 예시) aws_availability_zones available 리소스 유형을 사용하여 available 상태의 az 정보를 data 에 저장 후
    resource 에서 data 를 참조 하여 출력
 

Terraform Registry

 

registry.terraform.io

# Declare the data source
data "aws_availability_zones" "available" {
  state = "available"
}
resource "aws_subnet" "primary" {
  availability_zone = data.aws_availability_zones.available.names[0]
  # e.g. ap-northeast-2a
}
resource "aws_subnet" "secondary" {
  availability_zone = data.aws_availability_zones.available.names[1]
  # e.g. ap-northeast-2b
}
  • main.tf 파일 코드 수정
resource "local_file" "abc" {
  content  = "123!"
  filename = "${path.module}/abc.txt"
}

data "local_file" "abc" {
  filename = local_file.abc.filename
}

resource "local_file" "def" {
  content  = data.local_file.abc.content
  filename = "${path.module}/def.txt"
}
terraform apply -auto-approve

kkyoung@DESKTOP-26MI22N:/mnt/d/study/workspaces/3.5$ terraform state list
data.local_file.abc
local_file.abc
local_file.def

terraform graph > graph.dot

# 테라폼 콘솔 : 데이터 소스 참조 확인
terraform console
> 
data.local_file.abc.content
...
exit

  • (추가 실습) az.tf 파일 생성 - az datasource
vi az.tf

data "aws_availability_zones" "available" {
  state = "available"
}
#
terraform init -upgrade && terraform apply -auto-approve
terraform state list

## 결과
kkyoung@DESKTOP-26MI22N:/mnt/d/study/workspaces/3.5$ terraform state list
data.aws_availability_zones.available
data.local_file.abc
local_file.abc
local_file.def

# 활성화된 az 조회
terraform state show data.aws_availability_zones.available
# data.aws_availability_zones.available:
data "aws_availability_zones" "available" {
    group_names = [
        "ap-northeast-2",
    ]
    id          = "ap-northeast-2"
    names       = [
        "ap-northeast-2a",
        "ap-northeast-2b",
        "ap-northeast-2c",
        "ap-northeast-2d",
    ]
    state       = "available"
    zone_ids    = [
        "apne2-az1",
        "apne2-az2",
        "apne2-az3",
        "apne2-az4",
    ]
}

# 위의 방식이 어려운 경우 다음과 같이 데이터를 추출 해보길!
terraform console
>
-----------------
data.aws_availability_zones.available
data.aws_availability_zones.available.names
data.aws_availability_zones.available.names[0]
data.aws_availability_zones.available.names[1]
data.aws_availability_zones.available.zone_ids[0]
data.aws_availability_zones.available.zone_ids[1]
exit
-----------------

[실습1] VPC + 보안그룹 + EC2 배포

vpc 배포

# 신규 디렉터리 생성
mkdir my-vpc-ec2
cd my-vpc-ec2

# vpc.tf 파일 생성
provider "aws" {
  region  = "ap-northeast-2"
}

resource "aws_vpc" "kkyoung" {
  cidr_block       = "10.10.0.0/16"

  tags = {
    Name = "t101-study"
  }
}

DNS 호스트 이름이 비활성화 되어 있다

VPC DNS 옵션 수정

  • enable_dns_support, enable_dns_hostnames 추가
provider "aws" {
  region  = "ap-northeast-2"
}

resource "aws_vpc" "kkyoung" {
  cidr_block       = "10.10.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "t101-study"
  }
}

  • 기본값으로 enable_dns_hostnames가 false 였던것을 볼수 있다

VPC 서브넷 추가 (도전과제1,도전과제2)

  • (도전과제1) 서브넷 생성시에 필요한 가용영역은 맨 위에서 배운 데이타 블럭을 사용하여 생성
  • (도전과제2) 리소스 이름을 내맘대로 변경하여 속성참조에 대해 익숙해지기
provider "aws" {
  region  = "ap-northeast-2"
}

data "aws_availability_zones" "available" {
  state = "available"
}

resource "aws_vpc" "kkyoung" {
  cidr_block       = "10.10.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "t101-study"
  }
}

resource "aws_subnet" "kkyoung_sub_az1_pri_01" {
  vpc_id     = aws_vpc.kkyoung.id
  cidr_block = "10.10.1.0/24"

  availability_zone = data.aws_availability_zones.available.names[0]

  tags = {
    Name = "t101-subnet1"
  }
}

resource "aws_subnet" "kkyoung_sub_az3_pri_01" {
  vpc_id     = aws_vpc.kkyoung.id
  cidr_block = "10.10.2.0/24"

  availability_zone = data.aws_availability_zones.available.names[2]

  tags = {
    Name = "t101-subnet2"
  }
}

output "aws_vpc_id" {
  value = aws_vpc.kkyoung.id
}

subnet생성시 data를 참조 했다는것을 확인 할수 있다

VPC 인터넷 게이트웨이 추가

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

data "aws_availability_zones" "available" {
  state = "available"
}

resource "aws_vpc" "kkyoung" {
  cidr_block       = "10.10.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "t101-study"
  }
}

resource "aws_subnet" "kkyoung_sub_az1_pri_01" {
  vpc_id     = aws_vpc.kkyoung.id
  cidr_block = "10.10.1.0/24"

  availability_zone = data.aws_availability_zones.available.names[0]

  tags = {
    Name = "t101-subnet1"
  }
}

resource "aws_subnet" "kkyoung_sub_az3_pri_01" {
  vpc_id     = aws_vpc.kkyoung.id
  cidr_block = "10.10.2.0/24"

  availability_zone = data.aws_availability_zones.available.names[2]

  tags = {
    Name = "t101-subnet2"
  }
}

resource "aws_internet_gateway" "kkyoung_igw" {
  vpc_id = aws_vpc.kkyoung.id

  tags = {
    Name = "t101-igw"
  }
}

output "aws_vpc_id" {
  value = aws_vpc.kkyoung.id
}

VPC 라우팅 테이블 추가

  • 위에서 인터넷 게이트웨이를 생성 했으니
    인터넷 게이트웨이로 연결할수 있게 라우팅 테이블을 이용하여 연결 해줘야 한다
provider "aws" {
  region  = "ap-northeast-2"
}

data "aws_availability_zones" "available" {
  state = "available"
}

resource "aws_vpc" "kkyoung" {
  cidr_block       = "10.10.0.0/16"
  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "t101-study"
  }
}

resource "aws_subnet" "kkyoung_sub_az1_pri_01" {
  vpc_id     = aws_vpc.kkyoung.id
  cidr_block = "10.10.1.0/24"

  availability_zone = data.aws_availability_zones.available.names[0]

  tags = {
    Name = "t101-subnet1"
  }
}

resource "aws_subnet" "kkyoung_sub_az3_pri_01" {
  vpc_id     = aws_vpc.kkyoung.id
  cidr_block = "10.10.2.0/24"

  availability_zone = data.aws_availability_zones.available.names[2]

  tags = {
    Name = "t101-subnet2"
  }
}

resource "aws_internet_gateway" "kkyoung_igw" {
  vpc_id = aws_vpc.kkyoung.id

  tags = {
    Name = "t101-igw"
  }
}

resource "aws_route_table" "kkyoung_rt" {
  vpc_id = aws_vpc.kkyoung.id

  tags = {
    Name = "t101-rt"
  }
}

resource "aws_route_table_association" "kkyoung_rtassociation1" {
  subnet_id      = aws_subnet.kkyoung_sub_az1_pri_01.id
  route_table_id = aws_route_table.kkyoung_rt.id
}

resource "aws_route_table_association" "kkyoung_rtassociation2" {
  subnet_id      = aws_subnet.kkyoung_sub_az3_pri_01.id
  route_table_id = aws_route_table.kkyoung_rt.id
}

resource "aws_route" "kkyoung_defaultroute" {
  route_table_id         = aws_route_table.kkyoung_rt.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.kkyoung_igw.id
}

output "aws_vpc_id" {
  value = aws_vpc.kkyoung.id
}

서브넷 이름을 pri로 만들었지만! 인터넷 연결 했었다ㅋㅋ
t101-rt 라는 라우팅 테이블을 이용하여 t101-igw 와 연결

보안그룹 생성 + EC2 생성

  • main.tf에 많은 내용들이 작성되어 있으므로
    보기 편하게 sg.tf, ec2.tf 라는 파일들로 나뉘어서 진행
# sg.tf 생성
resource "aws_security_group" "kkyoung_ec2_sg" {
  vpc_id      = aws_vpc.kkyoung.id
  name        = "T101 SG"
  description = "T101 Study SG"
}

resource "aws_security_group_rule" "kkyoung_ec2_sg_inbound" {
  type              = "ingress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.kkyoung_ec2_sg.id
}

resource "aws_security_group_rule" "kkyoung_ec2_sg_outbound" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.kkyoung_ec2_sg.id
}

보안그룹을 만들기만 하고 아직 연결하지 않은 모습

# ec2.tf 생성

data "aws_ami" "my_amazonlinux2" {
  most_recent = true
  filter {
    name   = "owner-alias"
    values = ["amazon"]
  }

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-ebs"]
  }

  owners = ["amazon"]
}

resource "aws_instance" "kkyoung_ec2" {

  depends_on = [
    aws_internet_gateway.kkyoung_igw
  ]

  ami                         = data.aws_ami.my_amazonlinux2.id
  associate_public_ip_address = true
  instance_type               = "t2.micro"
  vpc_security_group_ids      = ["${aws_security_group.kkyoung_ec2_sg.id}"]
  subnet_id                   = aws_subnet.kkyoung_sub_az1_pri_01.id

  user_data = <<-EOF
              #!/bin/bash
              wget https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-x86_64
              mv busybox-x86_64 busybox
              chmod +x busybox
              RZAZ=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone-id)
              IID=$(curl 169.254.169.254/latest/meta-data/instance-id)
              LIP=$(curl 169.254.169.254/latest/meta-data/local-ipv4)
              echo "<h1>RegionAz($RZAZ) : Instance ID($IID) : Private IP($LIP) : Web Server</h1>" > index.html
              nohup ./busybox httpd -f -p 80 &
              EOF

  user_data_replace_on_change = true

  tags = {
    Name = "t101-myec2"
  }
}

output "myec2_public_ip" {
  value       = aws_instance.kkyoung_ec2.public_ip
  description = "The public IP of the Instance"
}

curl 을 이용하여 내가 원하는대로 웹서버가 생성되었는지 확인!

실습 정리하기

terraform destroy -auto-approve