IaC AWS 아키텍처 구축 - 1

SangYeon Min·2023년 11월 29일
1

STUDY-DevOps

목록 보기
2/7
post-thumbnail

해당 아키텍처를 Terraform을 통해 멱등성을 보장하면서 배포가능하도록 구축


IAM 생성

위와 같이 임의로 Admin Access 권한을 가진 사용자 생성
해당 사용자의 권한은 추후 IaC 작성 이후 변경할 예정
이후 해당 사용자에 대한 Access CMD CLI Access 키를 생성한다

$ aws configure
AWS Access Key ID [****************CE7M]:
AWS Secret Access Key [****************qscY]:
Default region name [ap-northeast-2]: 
Default output format [json]:

이후 aws configure을 완료하여 Terraform을 사용할 준비를 마친다


Terraform 기본 리소스 정의

main.tf에 aws provider 사용을 정의한다

# Use AWS Provider
provider "aws" {
  region = "ap-northeast-2"
}

variables.tf에 아래와 같이 구현되어야 하는 리소스의 이름을 미리 정의한다

# Terraform Variables

# Local Values
locals {
  vpc_name                = "judemin-vnet"
  internet_gateway_name   = "judemin-internet-gateway"
  subnet1_name            = "judemin-subnet-1"
  subnet2_name            = "judemin-subnet-2"
  web_route_table_name    = "judemin-web-public-route-table"
  app_route_table_name    = "judemin-app-private-route-table"
  nat_gateway_name        = "judemin-nat-gateway"
  alb_security_group_name = "judemin-alb-security-group"
  ...
}

Web 리소스 구축

EC2 Web 인스턴스 구축

위와 같이 전체 구조를 한번에 생성하지 않고 VPC, Subnet 하위의 EC2 인스턴스를 먼저 구축하고 Nginx를 각 인스턴스에 설치하여 라우팅 테이블로 접근을 확인한다

############# VPC ###############
# VPC resource
resource "aws_vpc" "goorm_vpc" {
  cidr_block = "172.16.0.0/16"
  tags = {
    Name = "goorm_vpc"
  }
}

# Subnet-a resource
resource "aws_subnet" "goorm_subnet_a" {
  vpc_id            = aws_vpc.goorm_vpc.id
  cidr_block        = "172.16.0.0/24"
  availability_zone = "ap-northeast-2a"
  tags = {
    Name = "goorm_subnet_a"
  }
}

# Subnet-c resource
resource "aws_subnet" "goorm_subnet_c" {
  vpc_id            = aws_vpc.goorm_vpc.id
  cidr_block        = "172.16.10.0/24"
  availability_zone = "ap-northeast-2c"
  tags = {
    Name = "goorm_subnet_c"
  }
}

이미지속 구조와 같이 VPC 하위에 subnet-a, subnet-c를 생성한다

############ EC2 Instance ##############
resource "aws_instance" "public_web_a" {
  ami           = "ami-01123b84e2a4fba05"
  instance_type = "t2.micro"
  subnet_id     = aws_subnet.goorm_subnet_a.id

  vpc_security_group_ids = [
    aws_security_group.web_server_sg.id,
  ]

  tags = {
    Name = "public_web_a"
  }

  # for aws_instance only
  # azure: custom_data
  # gcp: meta_data
  user_data = <<-EOF
    #! /bin/bash
    sudo yum update
    sudo yum install nginx -y
    sudo service nginx start
    sudo chkconfig nginx on
    sudo service nginx status
  EOF
}

...

이후 EC2 인스턴스를 위와 같이 생성한다, 이때 AMI와 t2.micro로 설정하여 프리티어를 사용할 수 있게 설정한다.
또한 user_data를 통해 최초 인스턴스 생성시에 nginx를 설치할 수 있도록 설정하고 subnet_id를 통해 인스턴스에 서브넷을 지정해준다.

############ Instance SG ##############
resource "aws_security_group" "web_server_sg" {
  name        = "web_server_sg"
  description = "allow 22, 80"
  vpc_id      = aws_vpc.goorm_vpc.id
}

resource "aws_security_group_rule" "websg_ssh" {
  type              = "ingress"
  from_port         = 22
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.web_server_sg.id
  description       = "ssh"
}

resource "aws_security_group_rule" "websg_http" {
  type              = "ingress"
  from_port         = 80
  to_port           = 80
  protocol          = "tcp"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.web_server_sg.id
  description       = "http"
}

resource "aws_security_group_rule" "websg_outbound" {
  type              = "egress"
  from_port         = 0
  to_port           = 0
  protocol          = "-1"
  cidr_blocks       = ["0.0.0.0/0"]
  security_group_id = aws_security_group.web_server_sg.id
  description       = "outbound"
}

또한 마지막으로 각 인스턴스에 적용될 SGRule을 SG로 묶어준다.

creating EC2 Instance: InvalidParameter: Security group sg-06d87931xx
and subnet subnet-09b91ac926xx belong to different networks

이떄 위와 같이 terraform apply시에 위와 같은 오류가 발생하게 되었는데
이는 인스턴스 subnet VPC외 SG의 VPC가 일치하지 않아서 발생하는 문제이다

SG 리소스의 vpc_id에 인스턴스 서브넷의 VPC를 넣어주어 해결하면 아래와 같이 정상적으로 인스턴스가 생성되는 것을 볼 수 있다.

인스턴스 Public IP 주소 할당

하지만 인스턴스에 퍼블릭 DNS 및 IP 주소가 할당되지 않은 것을 확인할 수 있다.

resource "aws_subnet" "goorm_subnet_a" {
  ...
  map_public_ip_on_launch = true
  tags = {
    Name = "goorm_subnet_a"
  }
}

map_public_ip_on_launch 설정을 통해 해당 서브넷 하위 리소스 모두 public IP를 가질 수 있도록 설정할 수 있다. 또한 리소스에 대한 SG 설정으로 이를 제어한다.

Routing Table 및 Gateway 연결

############ Gateway ##############
# Internet gateway
resource "aws_internet_gateway" "goorm_internet_gw" {
  vpc_id = aws_vpc.goorm_vpc.id

  tags = {
    Name = "goorm_internet_gw"
  }
}

# Route table
resource "aws_route_table" "goorm_route_table" {
  vpc_id = aws_vpc.goorm_vpc.id

  tags = {
    Name = "goorm_route_table"
  }
}

# Route
resource "aws_route" "goorm_route" {
  route_table_id         = aws_route_table.goorm_route_table.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.goorm_internet_gw.id
}

resource "aws_route_table_association" "goorm_rtb_sub_a_aasosiation" {
  subnet_id      = aws_subnet.goorm_subnet_a.id
  route_table_id = aws_route_table.goorm_route_table.id
}

# Route table association
resource "aws_route_table_association" "goorm_rtb_sub_c_aasosiation" {
  subnet_id      = aws_subnet.goorm_subnet_c.id
  route_table_id = aws_route_table.goorm_route_table.id
}

Internet Gateway와 라우트 테이블을 설정하고 VPC id를 입력한다.

이후 route_table의 route를 생성하여 연결하고 aws_route_table_association를 통해 각 서브넷을 라우팅 하여 게이트웨이로 접속할 수 있게 만든다.

ALB, ASG 인프라 구축

############ Security Group #############
# Application Load Balancer SG
resource "aws_security_group" "web_alb_security_group" {
  name        = "web_alb_security_group"
  description = "ALB Security Group"
  vpc_id      = aws_vpc.goorm_vpc.id

  ingress {
    description = "HTTP from Internet"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "web_alb_security_group"
  }
}

위와 같이 ALB의 SG를 생성한다, 이때 VPC 포함 및 HTTP 요청을 활성화한다

######## Application Load Balancer #########
resource "aws_lb" "web-alb" {
  name               = "web-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.web_alb_security_group.id]
  subnets = [
    aws_subnet.goorm_subnet_a.id,
    aws_subnet.goorm_subnet_c.id
  ]
}

# Send HTTP request to target group
resource "aws_lb_listener" "web-alb-listener" {
  load_balancer_arn = aws_lb.web-alb.arn
  port              = "80"
  protocol          = "HTTP"

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

resource "aws_lb_target_group" "web-alb-target-group" {
  name     = "web-alb-target-group"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.goorm_vpc.id

  health_check {
    path    = "/"
    matcher = 200
  }
}

이후 각 subnet을 포함하는 ALB를 생성한다.
이때 aws_lb_listener는 특정 포트와 프로토콜을 수신하여 해당 요청을 aws_lb_target_group, 즉 타겟 서버에 포워딩 해주어 요청을 처리한다.

######## Auto Scaling Group #########
resource "aws_launch_configuration" "goorm-web-launconfig" {
  name            = "goorm-web-launconfig"
  image_id        = "ami-01123b84e2a4fba05"
  instance_type   = "t2.micro"
  security_groups = [aws_security_group.web_server_sg.id]

  user_data = <<-EOF
    #! /bin/bash
    sudo yum update
    sudo yum install nginx -y
    sudo service nginx start
    sudo chkconfig nginx on
    sudo service nginx status
  EOF

  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_autoscaling_group" "goorm-web-asg" {
  name                 = "goorm-web-asg"
  launch_configuration = aws_launch_configuration.goorm-web-launconfig.name
  vpc_zone_identifier = [
    aws_subnet.goorm_subnet_a.id,
    aws_subnet.goorm_subnet_c.id
  ]

  target_group_arns = [aws_lb_target_group.web-alb-target-group.arn]
  health_check_type = "ELB"

  min_size = 2
  max_size = 5

  tag {
    key                 = "name"
    value               = "goorm-web-asg"
    propagate_at_launch = true
  }
}

기존에 사용했던 EC2 인스턴스 대신 aws_autoscaling_groupaws_launch_configuration를 통해 자동적으로 스케일을 조정한다.

따라서 aws_launch_configuration에 nginx를 설치하도록 정의하고 기존에 정의한 SG에 연결한다. 이후 ASG에 서브넷을 지정하고 health check type을 ELB로 지정한 이후 apply로 전체 인스턴스를 생성하면 아키텍처 구현이 완료된다.

0개의 댓글