본문 바로가기
Terraform/실습

3 Tier Architecture 구성

by 개발자 영만 2024. 1. 21.

1. Provider 지정

  • provider : aws를 provider로 지정
  • region : aws의 “us-east-2” 리전에서 인프라 생성
provider "aws" {
  region = "us-east-2"
}

 

2. VPC 생성

  • resource : 실제로 생성할 인프라 자원을 의미. 리소스 타입은 “aws_vpc”, terraform에서 정의하는 이름은 “vpc”로 정한다. “vpc”는 aws에서 사용되는 이름이 아니고 terraform 내부에서 참조하기 위한 이름이다.
  • cidr_block : vpc가 사용하는 ip 대역
  • tag : vpc의 이름, 등록 날짜, 사용자 이름 지정
# vpc 생성
resource "aws_vpc" "vpc" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "ihwoo-tftest-vpc",
    Date = "2022-10-05",
    User = "ihwoo"
  }
}

 

3. Subnet 생성

  • resource : 리소스 타입은 “aws_subnet”
  • vpc_id : 참조할 vpc 지정
  • cidr_block : subnet이 사용하는 ip 대역
  • availability_zone : 가용영역 지정
  • map_public_ip_on_launch : 이 subnet에서 생성되는 인스턴스가 public ip 할당되어야 하는지 여부. public은 bastion을 올려야 하기 때문에 public ip가 할당되도록 옵션을 지정
  • tag : subnet의 이름, 등록 날짜, 사용자 이름 지정
#public subnet 생성
resource "aws_subnet" "public-subnet-1" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "10.0.1.0/24"
  availability_zone = "us-east-2a"

  tags = {
    Name = "ihwoo-tftest-public-subnet-1",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

resource "aws_subnet" "public-subnet-2" {
  vpc_id = aws_vpc.vpc.id
  cidr_block = "10.0.2.0/24"
  availability_zone = "us-east-2b"

  tags = {
    Name = "ihwoo-tftest-public-subnet-2",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# private subent web 생성
resource "aws_subnet" "private-subnet-web-1"{
  vpc_id  = aws_vpc.vpc.id
  cidr_block  = "10.0.10.0/24"
  availability_zone = "us-east-2a"

  tags = {
    Name = "ihwoo-tftest-private-subnet-web-1",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

resource "aws_subnet" "private-subnet-web-2"{
  vpc_id  = aws_vpc.vpc.id
  cidr_block  = "10.0.20.0/24"
  availability_zone = "us-east-2b"

  tags = {
    Name = "ihwoo-tftest-private-subnet-web-2",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# private subnet was 생성
resource "aws_subnet" "private-subnet-was-1"{
  vpc_id  = aws_vpc.vpc.id
  cidr_block  = "10.0.30.0/24"
  availability_zone = "us-east-2a"

  tags = {
    Name = "ihwoo-tftest-private-subnet-was-1",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

resource "aws_subnet" "private-subnet-was-2"{
  vpc_id  = aws_vpc.vpc.id
  cidr_block  = "10.0.40.0/24"
  availability_zone = "us-east-2b"

  tags = {
    Name = "ihwoo-tftest-private-subnet-was-2",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# private subnet db 생성
resource "aws_subnet" "private-subnet-db-1"{
  vpc_id  = aws_vpc.vpc.id
  cidr_block  = "10.0.50.0/24"
  availability_zone = "us-east-2a"

  tags = {
    Name = "ihwoo-tftest-private-subnet-db-1",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

resource "aws_subnet" "private-subnet-db-2"{
  vpc_id  = aws_vpc.vpc.id
  cidr_block  = "10.0.60.0/24"
  availability_zone = "us-east-2b"

  tags = {
    Name = "ihwoo-tftest-private-subnet-db-2",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

 

4. Internet gateway 생성

  • resource : 리소스 타입은 “aws_internet_gateway”
  • vpc_id : 참조할 vpc 지정
  • tags : internet gateway의 이름, 등록 날짜, 사용자 이름 지정
# internet gateway 생성
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name = "ihwoo-tftest-igw",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

5. EIP 생성

  • NAT 게이트웨이를 생성하려면 EIP가 필요하다.
  • resource : 리소스 타입은 “aws_eip”
  • vpc : eip가 vpc에 위치하는지 여부
  • tags : eip의 이름, 등록 날짜, 사용자 이름 지정
# elastic ip 생성
resource "aws_eip" "eip" {
  vpc   = true

  lifecycle {
    create_before_destroy = true
  }

  tags = {
    Name = "ihwoo-tftest-eip",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

 

6. NAT gateway 생성

  • resource : 리소스 타입은 “aws_nat_gateway” 지정
  • allocation_id : 위에서 생성했던 eip를 nat에 할당
  • subnet_id : nat가 위치 할 subnet 지정
  • tags : nat gateway의 이름, 등록 날짜, 사용자 이름 지정
# nat gateway 생성
resource "aws_nat_gateway" "natgw" {
  allocation_id = aws_eip.eip.id
  subnet_id = aws_subnet.public-subnet-1.id

  tags = {
    Name = "ihwoo-tftest-natgw",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

 

7. Route table 생성

  • resource : 리소스 타입은 “aws_route_table”
  • vpc_id : 참조할 vpc 지정
  • tags : route table의 이름, 등록 날짜, 사용자 이름 지정
# public route table 생성
resource "aws_route_table" "public-route-table" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name = "ihwoo-tftest-public-route-table",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# private route table 생성
resource "aws_route_table" "private-route-table-web" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name = "ihwoo-tftest-private-route-table-web",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

resource "aws_route_table" "private-route-table-was" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name = "ihwoo-tftest-private-route-table-was",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

resource "aws_route_table" "private-route-table-db" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name = "ihwoo-tftest-private-route-table-db",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

 

8. Route 설정

  • resource : 리소스 타입은 “aws_route”
  • route_table_id : route table 테이블 지정
  • destination_cidr_block : ip 대역 지정
  • gatewat_id : 라우팅 할 igw지정
  • nat_gatewat_id : 라우팅 할 nat 지정
# public route rule 설정
resource "aws_route" "public-route" {
  route_table_id = aws_route_table.public-route-table.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id = aws_internet_gateway.igw.id
}

# private route rule 설정
resource "aws_route" "private-route-web" {
  route_table_id = aws_route_table.private-route-table-web.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id = aws_nat_gateway.natgw.id
}

resource "aws_route" "public-route-was" {
  route_table_id = aws_route_table.private-route-table-was.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id = aws_nat_gateway.natgw.id
}

resource "aws_route" "public-route-db" {
  route_table_id = aws_route_table.private-route-table-db.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id = aws_nat_gateway.natgw.id
}

 

9. Route table에 subnet 연결

  • resource : 리소스 타입은 “aws_route_table_association”
  • subnet_id : 연결할 subnet 지정
  • route_table_id : 연결할 route table 지정
# public route table에 public subnet 연결
resource "aws_route_table_association" "public-route-table-association-1" {
  subnet_id = aws_subnet.public-subnet-1.id
  route_table_id = aws_route_table.public-route-table.id
}

resource "aws_route_table_association" "public-route-table-association-2" {
  subnet_id = aws_subnet.public-subnet-2.id
  route_table_id = aws_route_table.public-route-table.id
}

# private route table에 private subnet 연결
resource "aws_route_table_association" "private-route-table-association-1" {
  subnet_id = aws_subnet.private-subnet-web-1.id
  route_table_id = aws_route_table.private-route-table-web.id
}

resource "aws_route_table_association" "private-route-table-association-2" {
  subnet_id = aws_subnet.private-subnet-web-2.id
  route_table_id = aws_route_table.private-route-table-web.id
}

resource "aws_route_table_association" "private-route-table-association-3" {
  subnet_id = aws_subnet.private-subnet-was-1.id
  route_table_id = aws_route_table.private-route-table-was.id
}

resource "aws_route_table_association" "private-route-table-association-4" {
  subnet_id = aws_subnet.private-subnet-was-2.id
  route_table_id = aws_route_table.private-route-table-was.id
}

resource "aws_route_table_association" "private-route-table-association-5" {
  subnet_id = aws_subnet.private-subnet-db-1.id
  route_table_id = aws_route_table.private-route-table-db.id
}

resource "aws_route_table_association" "private-route-table-association-6" {
  subnet_id = aws_subnet.private-subnet-db-2.id
  route_table_id = aws_route_table.private-route-table-db.id
}

 

10. Security Group 생성

  • resource : 리소스 타입은 “aws_security_group”
  • vpc_id : 참조할 vpc 지정
  • name : security group의 이름
  • tags : security group의 이름, 등록 날짜, 사용자 이름 지정
# bastion security group 생성
resource "aws_security_group" "security-group-bastion"{
  vpc_id = aws_vpc.vpc.id
  name = "ihwoo-tftest-security-group-bastion"

  tags = {
    Name = "ihwoo-tftest-security-group-bastion",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# alb security group 생성
resource "aws_security_group" "security-group-alb"{
  vpc_id = aws_vpc.vpc.id
  name = "ihwoo-tftest-security-group-alb"

  tags = {
    Name = "ihwoo-tftest-security-group-alb",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# web security group 생성
resource "aws_security_group" "security-group-web"{
  vpc_id = aws_vpc.vpc.id
  name = "ihwoo-tftest-security-group-web"

  tags = {
    Name = "ihwoo-tftest-security-group-web",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# was security group 생성
resource "aws_security_group" "security-group-was"{
  vpc_id = aws_vpc.vpc.id
  name = "ihwoo-tftest-security-group-was"

  tags = {
    Name = "ihwoo-tftest-security-group-was",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# db security group 생성
resource "aws_security_group" "security-group-db"{
  vpc_id = aws_vpc.vpc.id
  name = "ihwoo-tftest-security-group-db"

  tags = {
    Name = "ihwoo-tftest-security-group-db",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

 

11. 인바운드 및 아웃바운드 규칙 추가

Security Group에서 사용할 인바운드 및 아웃바운드 규칙들을 설정해야 한다.

  • resource : 리소스 타입은 “aws_security_group_rule”
  • type : ingress & egress 지정
  • from_port : port
  • to_port : port
  • protocol : 프로토콜 타입
  • cidr_blocks : ip대역
  • source_security_group_id : 특정 대상만 허용할 경우 사용. cidr_block과 둘 중 하나만 사용 가능
  • security_group_id : 규칙을 추가할 security group
# bastion 인바운드 규칙 추가
resource "aws_security_group_rule" "security-group-rule-bastion-i" {
  type = "ingress"
  from_port = 22
  to_port = 22
  protocol = "tcp"
  cidr_blocks = ["0.0.0.0/0"]

  security_group_id = aws_security_group.security-group-bastion.id
}

# bastion 아웃바운드 규칙 추가
resource "aws_security_group_rule" "security-group-rule-bastion-e" {
  type = "egress"
  from_port = 0
  to_port = 0
  protocol = "-1"
  cidr_blocks = ["0.0.0.0/0"]

  security_group_id = aws_security_group.security-group-bastion.id
}

# alb 인바운드 규칙 추가
resource "aws_security_group_rule" "security-group-rule-alb-i" {
  type = "ingress"
  from_port = 80
  to_port = 80
  protocol = "tcp"
  cidr_blocks = ["0.0.0.0/0"] 

  security_group_id = aws_security_group.security-group-alb.id
}

# alb 아웃바운드 규칙 추가
resource "aws_security_group_rule" "security-group-rule-alb-e" {
  type = "egress"
  from_port = 0
  to_port = 0
  protocol = "-1"
  cidr_blocks = ["0.0.0.0/0"]

  security_group_id = aws_security_group.security-group-alb.id
}

# web 인바운드 규칙 추가
resource "aws_security_group_rule" "security-group-rule-web-i1" {
  type = "ingress"
  from_port = 22
  to_port = 22
  protocol = "tcp"
  source_security_group_id = aws_security_group.security-group-bastion.id

  security_group_id = aws_security_group.security-group-web.id
}

resource "aws_security_group_rule" "security-group-rule-web-i2" {
  type = "ingress"
  from_port = 80
  to_port = 80
  protocol = "tcp"
  cidr_blocks = ["0.0.0.0/0"] 

  security_group_id = aws_security_group.security-group-web.id
}

# web 아웃바운드 규칙 추가
resource "aws_security_group_rule" "security-group-rule-web-e" {
  type = "egress"
  from_port = 0
  to_port = 0
  protocol = "-1"
  cidr_blocks = ["0.0.0.0/0"]

  security_group_id = aws_security_group.security-group-web.id
}

# was 인바운드 규칙 추가
resource "aws_security_group_rule" "security-group-rule-was-i1" {
  type = "ingress"
  from_port = 22
  to_port = 22
  protocol = "tcp"
  source_security_group_id = aws_security_group.security-group-bastion.id

  security_group_id = aws_security_group.security-group-was.id
}

resource "aws_security_group_rule" "security-group-rule-was-i2" {
  type = "ingress"
  from_port = 8080
  to_port = 8080
  protocol = "tcp"
  cidr_blocks = ["10.0.10.0/24", "10.0.20.0/24"] 

  security_group_id = aws_security_group.security-group-was.id
}

# was 아웃바운드 규칙 추가
resource "aws_security_group_rule" "security-group-rule-was-e" {
  type = "egress"
  from_port = 0
  to_port = 0
  protocol = "-1"
  cidr_blocks = ["0.0.0.0/0"]

  security_group_id = aws_security_group.security-group-was.id
}

# db 인바운드 규칙 추가
resource "aws_security_group_rule" "security-group-rule-db-i1" {
  type = "ingress"
  from_port = 22
  to_port = 22
  protocol = "tcp"
  source_security_group_id = aws_security_group.security-group-bastion.id

  security_group_id = aws_security_group.security-group-db.id
}

resource "aws_security_group_rule" "security-group-rule-db-i2" {
  type = "ingress"
  from_port = 3306
  to_port = 3306
  protocol = "tcp"
  cidr_blocks = ["0.0.0.0/0"] 

  security_group_id = aws_security_group.security-group-db.id
}

# db 아웃바운드 규칙 추가
resource "aws_security_group_rule" "security-group-rule-db-e" {
  type = "egress"
  from_port = 0
  to_port = 0
  protocol = "-1"
  cidr_blocks = ["0.0.0.0/0"]

  security_group_id = aws_security_group.security-group-db.id
}

 

12. Key pair 생성

instance에 사용할 key pair 생성

  • resource : 리소스 타입은 aws_key_pair
  • key_name : key pair 이름
  • public_key : 사용할 public key
#key pair 생성
resource "aws_key_pair" "private-key" {
  key_name = "private-key"
  public_key = file("~/key/terraform-test")
}

 

13. Instance 생성

  • resource : 리소스 타입은 aws_instance
  • ami : instance의 os 지정
  • instance_type : cpu, memory를 고려한 생성할 instance의 타입
  • availability_zone : 가용영역 지정
  • subnet_id : instance가 위치할 subnet 지정
  • key_name : instance에 접근하기 위해 필요한 key 지정
  • vpc_security_group_ids : instance의 security group 지정
  • associate_public_ip_address : public ip 할당 여부
# bastion 인스턴스 생성
resource "aws_instance" "instance-bastion" {
  ami = "ami-0f924dc71d44d23e2"
  instance_type = "t2.micro"
  availability_zone = "us-east-2a"
  subnet_id = aws_subnet.public-subnet-1.id
  vpc_security_group_ids = [aws_security_group.security-group-bastion.id]
  key_name = aws_key_pair.private-key.key_name

  associate_public_ip_address = true

  tags = {
    Name = "ihwoo-tftest-instance-bastion",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# web1 인스턴스 생성
resource "aws_instance" "instance-web-1" {
  ami = "ami-0f924dc71d44d23e2"
  instance_type = "t2.micro"
  availability_zone = "us-east-2a"
  subnet_id = aws_subnet.private-subnet-web-1.id
  vpc_security_group_ids = [aws_security_group.security-group-web.id]
  key_name = aws_key_pair.private-key.key_name

  associate_public_ip_address = false

  tags = {
    Name = "ihwoo-tftest-instance-web-1",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# web2 인스턴스 생성
resource "aws_instance" "instance-web-2" {
  ami = "ami-0f924dc71d44d23e2"
  instance_type = "t2.micro"
  availability_zone = "us-east-2b"
  subnet_id = aws_subnet.private-subnet-web-2.id
  vpc_security_group_ids = [aws_security_group.security-group-web.id]
  key_name = aws_key_pair.private-key.key_name

  associate_public_ip_address = false

  tags = {
    Name = "ihwoo-tftest-instance-web-1",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# was1 인스턴스 생성
resource "aws_instance" "instance-was-1" {
  ami = "ami-0f924dc71d44d23e2"
  instance_type = "t2.micro"
  availability_zone = "us-east-2a"
  subnet_id = aws_subnet.private-subnet-was-1.id
  vpc_security_group_ids = [aws_security_group.security-group-was.id]
  key_name = aws_key_pair.private-key.key_name

  associate_public_ip_address = false

  tags = {
    Name = "ihwoo-tftest-instance-was-1",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# was2 인스턴스 생성
resource "aws_instance" "instance-was-2" {
  ami = "ami-0f924dc71d44d23e2"
  instance_type = "t2.micro"
  availability_zone = "us-east-2b"
  subnet_id = aws_subnet.private-subnet-was-2.id
  vpc_security_group_ids = [aws_security_group.security-group-was.id]
  key_name = aws_key_pair.private-key.key_name

  associate_public_ip_address = false

  tags = {
    Name = "ihwoo-tftest-instance-was-2",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

 

14. ELB, Target Group, Target, Listener 생성

Load Balancer의 구성 요소는 크게 3가지가 있다. 먼저 요청을 받아들여 이 요청을 처리할 적절한 Target Group으로 전달하는 Listener, 어느 대상 그룹에 전달할지 판단하는 기준이 되는 Rule, 마지막으로 요청을 처리할 EC2가 모여있는 Target Group이 있다.

  • resource : 리소스 타입은 aws_lb, aws_lb_target_group, aws_lb_target_group_attachment, aws_alb_listener
  • name : elb 이름 지정
  • internal : 외부와 통신하는지, 내부와 통신하는지 결정
  • load_balancer_type : elb의 타입 지정
  • security_groups : elg 의 sg 지정
  • subnets : load balancer가 위치할 subnet. alb는 private subnet에 있는 web 서버를 load balancing 하지만, 외부와 통신하기 때문에 public subnet에 위치해야 한다. nlb는 private subnet에 있는 was 서버를 load balancing 하기 위해, 그 앞에 위치한 private subnet에 있어야 한다.
# alb 생성
resource "aws_lb" "alb" {
  name = "ihwoo-tftest-alb"
  internal = false
  load_balancer_type = "application"
  security_groups = [aws_security_group.security-group-alb.id]
  subnets = [aws_subnet.public-subnet-1.id, aws_subnet.public-subnet-2.id]

  tags = {
    Name = "ihwoo-tftest-alb",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# target group 생성
resource "aws_lb_target_group" "target-group-web" {
  name = "ihwoo-tftest-target-group-web"
  port = 80
  protocol = "HTTP"
  vpc_id = aws_vpc.vpc.id

  health_check {
    interval = 30
    path = "/"
    healthy_threshold = 3
    unhealthy_threshold = 3
  }
}

# target group에 target 설정
resource "aws_lb_target_group_attachment" "target-group-attachment-web-1" {
  target_group_arn = aws_lb_target_group.target-group-web.arn
  target_id = aws_instance.instance-web-1.id
  port = 80
}

 resource "aws_lb_target_group_attachment" "target-group-attachment-web-2" {
  target_group_arn = aws_lb_target_group.target-group-web.arn
  target_id = aws_instance.instance-web-2.id
  port = 80
}

# alb 리스너 설정
resource "aws_lb_listener" "web-http" {
  load_balancer_arn = aws_lb.alb.arn
  port = "80"
  protocol = "HTTP"

  default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.target-group-web.arn
  }
}

resource "aws_alb_listener" "web-https" {
  load_balancer_arn = aws_lb.alb.arn
  port = "443"
  protocol = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  certificate_arn   = "${data.aws_acm_certificate.example_dot_com.arn}"

  default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.target-group-web.arn
  }
}

# nlb 생성
resource "aws_lb" "nlb" {
  name = "ihwoo-tftest-nlb"
  internal = true
  load_balancer_type = "network"
  subnets = [aws_subnet.private-subnet-web-1.id, aws_subnet.private-subnet-web-2.id]

  tags = {
    Name = "ihwoo-tftest-nlb",
    Date = "2022-10-07",
    User = "ihwoo"
  }
}

# target group 생성
resource "aws_lb_target_group" "target-group-was" {
  name = "ihwoo-tftest-target-group-was"
  port = 8080
  protocol = "TCP"
  vpc_id = aws_vpc.vpc.id

  health_check {
    interval = 30
    path = "/"
    healthy_threshold = 3
    unhealthy_threshold = 3
  }
}

# target group에 target 설정
resource "aws_lb_target_group_attachment" "target-group-attachment-was-1" {
  target_group_arn = aws_lb_target_group.target-group-was.arn
  target_id = aws_instance.instance-was-1.id
  port = 8080
}

 resource "aws_lb_target_group_attachment" "target-group-attachment-was-2" {
  target_group_arn = aws_lb_target_group.target-group-was.arn
  target_id = aws_instance.instance-was-2.id
  port = 8080
}

# nlb 리스너 설정
resource "aws_lb_listener" "was-http" {
  load_balancer_arn = aws_lb.nlb.arn
  port = "8080"
  protocol = "TCP"

  default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.target-group-was.arn
  }
}

resource "aws_lb_listener" "was-https" {
  load_balancer_arn = aws_lb.nlb.arn
  port = "443"
  protocol = "TCP"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  certificate_arn   = "${data.aws_acm_certificate.example_dot_com.arn}"

  default_action {
    type = "forward"
    target_group_arn = aws_lb_target_group.target-group-was.arn
  }
}